mobile-ai-agents 1.0.23
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.
- package/AGENTS.md +228 -0
- package/CLAUDE.md +236 -0
- package/LICENSE +21 -0
- package/README.md +652 -0
- package/agents/android/android-crash-analyzer/README.md +134 -0
- package/agents/android/android-crash-analyzer/agent.md +206 -0
- package/agents/android/android-crash-analyzer/example-input.md +138 -0
- package/agents/android/android-crash-analyzer/example-output.md +225 -0
- package/agents/android/anr-investigation/README.md +78 -0
- package/agents/android/anr-investigation/agent.md +117 -0
- package/agents/android/anr-investigation/example-input.md +62 -0
- package/agents/android/anr-investigation/example-output.md +103 -0
- package/agents/android/axiom/agent.md +197 -0
- package/agents/android/code-reviewer/README.md +108 -0
- package/agents/android/code-reviewer/agent.md +210 -0
- package/agents/android/code-reviewer/example-input.md +116 -0
- package/agents/android/code-reviewer/example-output.md +115 -0
- package/agents/android/compose-navigation/README.md +76 -0
- package/agents/android/compose-navigation/agent.md +121 -0
- package/agents/android/compose-navigation/example-input.md +49 -0
- package/agents/android/compose-navigation/example-output.md +325 -0
- package/agents/android/compose-screen-builder/README.md +95 -0
- package/agents/android/compose-screen-builder/agent.md +170 -0
- package/agents/android/compose-screen-builder/example-input.md +40 -0
- package/agents/android/compose-screen-builder/example-output.md +568 -0
- package/agents/android/compose-ui-reviewer/README.md +73 -0
- package/agents/android/compose-ui-reviewer/agent.md +253 -0
- package/agents/android/compose-ui-reviewer/example-input.md +84 -0
- package/agents/android/compose-ui-reviewer/example-output.md +102 -0
- package/agents/android/crash-analyzer/README.md +53 -0
- package/agents/android/crash-analyzer/agent.md +295 -0
- package/agents/android/memory-leak-analyzer/README.md +79 -0
- package/agents/android/memory-leak-analyzer/agent.md +116 -0
- package/agents/android/memory-leak-analyzer/example-input.md +78 -0
- package/agents/android/memory-leak-analyzer/example-output.md +128 -0
- package/agents/cross-platform/accessibility-auditor/README.md +47 -0
- package/agents/cross-platform/accessibility-auditor/agent.md +268 -0
- package/agents/cross-platform/accessibility-auditor/example-input.md +84 -0
- package/agents/cross-platform/accessibility-auditor/example-output.md +132 -0
- package/agents/cross-platform/appforge/agent.md +303 -0
- package/agents/cross-platform/ci-cd-generator/README.md +65 -0
- package/agents/cross-platform/ci-cd-generator/agent.md +422 -0
- package/agents/cross-platform/ci-cd-generator/example-input.md +69 -0
- package/agents/cross-platform/ci-cd-generator/example-output.md +261 -0
- package/agents/cross-platform/crasher/agent.md +221 -0
- package/agents/cross-platform/figma/agent.md +247 -0
- package/agents/cross-platform/launchpad/agent.md +330 -0
- package/agents/cross-platform/mobile-harness/agent.md +422 -0
- package/agents/cross-platform/mobile-memory/agent.md +429 -0
- package/agents/cross-platform/perf/agent.md +261 -0
- package/agents/cross-platform/pipeline/agent.md +288 -0
- package/agents/cross-platform/release-notes-generator/README.md +63 -0
- package/agents/cross-platform/release-notes-generator/agent.md +218 -0
- package/agents/cross-platform/release-notes-generator/example-input.md +71 -0
- package/agents/cross-platform/release-notes-generator/example-output.md +96 -0
- package/agents/cross-platform/scribe/agent.md +180 -0
- package/agents/cross-platform/security-scanner/README.md +61 -0
- package/agents/cross-platform/security-scanner/agent.md +287 -0
- package/agents/cross-platform/security-scanner/example-input.md +77 -0
- package/agents/cross-platform/security-scanner/example-output.md +141 -0
- package/agents/cross-platform/sentinel/agent.md +217 -0
- package/agents/cross-platform/store-listing-writer/README.md +58 -0
- package/agents/cross-platform/store-listing-writer/agent.md +380 -0
- package/agents/cross-platform/store-listing-writer/example-input.md +67 -0
- package/agents/cross-platform/store-listing-writer/example-output.md +131 -0
- package/agents/flutter/bloc-feature-builder/README.md +101 -0
- package/agents/flutter/bloc-feature-builder/agent.md +225 -0
- package/agents/flutter/bloc-feature-builder/example-input.md +47 -0
- package/agents/flutter/bloc-feature-builder/example-output.md +838 -0
- package/agents/flutter/dart/agent.md +223 -0
- package/agents/flutter/widget-generator/README.md +66 -0
- package/agents/flutter/widget-generator/agent.md +264 -0
- package/agents/flutter/widget-generator/example-input.md +71 -0
- package/agents/flutter/widget-generator/example-output.md +163 -0
- package/agents/gaming/forge/agent.md +197 -0
- package/agents/gaming/unreal/agent.md +200 -0
- package/agents/ios/crash-analyzer/README.md +69 -0
- package/agents/ios/crash-analyzer/agent.md +300 -0
- package/agents/ios/crash-analyzer/example-input.md +83 -0
- package/agents/ios/crash-analyzer/example-output.md +126 -0
- package/agents/ios/swift/agent.md +206 -0
- package/agents/ios/swift-reviewer/README.md +68 -0
- package/agents/ios/swift-reviewer/agent.md +231 -0
- package/agents/ios/swift-reviewer/example-input.md +100 -0
- package/agents/ios/swift-reviewer/example-output.md +127 -0
- package/agents/react-native/bridge/agent.md +212 -0
- package/agents/react-native/performance-optimizer/README.md +81 -0
- package/agents/react-native/performance-optimizer/agent.md +284 -0
- package/agents/react-native/performance-optimizer/example-input.md +104 -0
- package/agents/react-native/performance-optimizer/example-output.md +132 -0
- package/agents/unity/shader-generator/README.md +77 -0
- package/agents/unity/shader-generator/agent.md +270 -0
- package/agents/unity/shader-generator/example-input.md +70 -0
- package/agents/unity/shader-generator/example-output.md +160 -0
- package/agents/unreal/blueprint-advisor/README.md +71 -0
- package/agents/unreal/blueprint-advisor/agent.md +311 -0
- package/agents/unreal/blueprint-advisor/example-input.md +73 -0
- package/agents/unreal/blueprint-advisor/example-output.md +217 -0
- package/cli/index.js +1091 -0
- package/docs/agent-guide.md +138 -0
- package/docs/chatgpt-integration.md +219 -0
- package/docs/core-loops.md +143 -0
- package/docs/cursor-integration.md +143 -0
- package/docs/getting-started.md +132 -0
- package/docs/index.html +711 -0
- package/docs/installation.md +271 -0
- package/docs/mobile-harness.md +160 -0
- package/docs/mobile-mcp.md +172 -0
- package/docs/mobile-memory.md +349 -0
- package/docs/release-process.md +85 -0
- package/docs/releases/release-v1.0.0.md +165 -0
- package/docs/roadmap/github-issues.md +239 -0
- package/docs/skill-categories.md +125 -0
- package/docs/vscode-copilot-integration.md +104 -0
- package/docs/wiki.md +615 -0
- package/install.sh +507 -0
- package/mobile-karpathy.md +79 -0
- package/package.json +57 -0
- package/skills/android/README.md +31 -0
- package/skills/android/android-tdd.md +89 -0
- package/skills/android/anr-investigation.md +251 -0
- package/skills/android/code-review.md +98 -0
- package/skills/android/compose-migration.md +48 -0
- package/skills/android/compose-review.md +78 -0
- package/skills/android/kotlin-modernize.md +51 -0
- package/skills/android/memory-leak-investigation.md +256 -0
- package/skills/android/proguard-rules.md +48 -0
- package/skills/cross-platform/accessibility-audit.md +63 -0
- package/skills/cross-platform/api-versioning.md +59 -0
- package/skills/cross-platform/clean-code-audit.md +239 -0
- package/skills/cross-platform/crash-triage.md +53 -0
- package/skills/cross-platform/deeplink-debug.md +57 -0
- package/skills/cross-platform/feature-slice.md +48 -0
- package/skills/cross-platform/grill-mobile.md +64 -0
- package/skills/cross-platform/mobile-mcp-qa.md +193 -0
- package/skills/cross-platform/mobile-memory-graph.md +179 -0
- package/skills/cross-platform/mobile-memory-save.md +210 -0
- package/skills/cross-platform/mobile-memory-search.md +154 -0
- package/skills/cross-platform/perf-audit.md +61 -0
- package/skills/cross-platform/prd-verification.md +324 -0
- package/skills/cross-platform/release-prep.md +64 -0
- package/skills/cross-platform/security-audit.md +281 -0
- package/skills/cross-platform/store-listing.md +75 -0
- package/skills/flutter/README.md +32 -0
- package/skills/flutter/dart-modernize.md +47 -0
- package/skills/flutter/flutter-review.md +59 -0
- package/skills/flutter/flutter-tdd.md +73 -0
- package/skills/flutter/widget-extract.md +41 -0
- package/skills/flutter/widget-gen.md +131 -0
- package/skills/gaming/blueprint-to-cpp.md +51 -0
- package/skills/gaming/game-perf.md +54 -0
- package/skills/gaming/shader-gen.md +44 -0
- package/skills/gaming/unity-tdd.md +85 -0
- package/skills/ios/README.md +45 -0
- package/skills/ios/data-persistence.md +151 -0
- package/skills/ios/ios-tdd.md +90 -0
- package/skills/ios/networking.md +139 -0
- package/skills/ios/performance.md +122 -0
- package/skills/ios/swift-concurrency.md +57 -0
- package/skills/ios/swift-review.md +124 -0
- package/skills/ios/swiftui-review.md +49 -0
- package/skills/ios/swiftui-state.md +122 -0
- package/skills/ios/unit-testing.md +144 -0
- package/skills/ios/xcode-warnings.md +37 -0
- package/skills/react-native/README.md +42 -0
- package/skills/react-native/bridge-audit.md +104 -0
- package/skills/react-native/expo-optimize.md +55 -0
- package/skills/react-native/new-arch-migrate.md +53 -0
- package/skills/react-native/performance.md +124 -0
- package/skills/react-native/rn-review.md +53 -0
- package/skills/react-native/rn-tdd.md +76 -0
- package/skills/shared/README.md +46 -0
- package/skills/shared/accessibility-audit.md +132 -0
- package/skills/shared/crash-analysis.md +110 -0
- package/skills/shared/security-scan.md +149 -0
- package/skills/unity/README.md +31 -0
- package/skills/unity/shader-review.md +110 -0
- package/templates/agent-template.md +88 -0
- package/templates/prompt-template.md +50 -0
- package/templates/skill-template.md +64 -0
- package/templates/workflow-template.md +48 -0
- package/workflows/app-launch.md +66 -0
- package/workflows/appforge-workflow.md +232 -0
- package/workflows/ci-setup.md +77 -0
- package/workflows/crash-to-fix.md +71 -0
- package/workflows/feature-ship.md +61 -0
- package/workflows/game-level.md +72 -0
- package/workflows/mobile-harness.md +319 -0
- package/workflows/mobile-mcp-qa.md +228 -0
- package/workflows/mobile-memory-workflow.md +243 -0
- package/workflows/new-project-setup.md +93 -0
- package/workflows/new-screen.md +68 -0
- package/workflows/perf-sprint.md +78 -0
- package/workflows/release-cycle.md +71 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Skill — /android-tdd
|
|
2
|
+
|
|
3
|
+
**Platform:** Android (Kotlin)
|
|
4
|
+
**Slash Command:** `/android-tdd`
|
|
5
|
+
**Composable With:** agents/android/axiom/agent.md
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Runs the red-green-refactor TDD loop for Android — JUnit5 unit tests, Compose UI tests, and ViewModel tests with Turbine for StateFlow. Generates a failing test first, then the minimal implementation that makes it pass.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Skill Prompt
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Run the Android TDD loop for the described feature or function:
|
|
19
|
+
|
|
20
|
+
STEP 1 — RED: Write a failing test first.
|
|
21
|
+
- For business logic: JUnit5 test class using @Test, @BeforeEach, MockK or Mockito.
|
|
22
|
+
- For ViewModel: use TestCoroutineDispatcher + Turbine to test StateFlow emissions.
|
|
23
|
+
- For Compose UI: use ComposeTestRule + semantic matchers (onNodeWithText, performClick).
|
|
24
|
+
- Test must fail for the right reason (not compile error, but assertion failure).
|
|
25
|
+
|
|
26
|
+
STEP 2 — GREEN: Write the minimal implementation to make the test pass.
|
|
27
|
+
- No extra logic, no future-proofing. Just enough to pass the test.
|
|
28
|
+
|
|
29
|
+
STEP 3 — REFACTOR: Clean up without breaking the test.
|
|
30
|
+
- Extract functions, improve naming, add sealed class if needed.
|
|
31
|
+
|
|
32
|
+
Format each step clearly:
|
|
33
|
+
--- RED (failing test) ---
|
|
34
|
+
<test code>
|
|
35
|
+
|
|
36
|
+
--- GREEN (implementation) ---
|
|
37
|
+
<minimal production code>
|
|
38
|
+
|
|
39
|
+
--- REFACTOR (cleaned up) ---
|
|
40
|
+
<final production code>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Example
|
|
46
|
+
|
|
47
|
+
**Input:** "TDD a CalculateDiscountUseCase that applies 20% off when total > 100"
|
|
48
|
+
|
|
49
|
+
**Output:**
|
|
50
|
+
```kotlin
|
|
51
|
+
--- RED (failing test) ---
|
|
52
|
+
class CalculateDiscountUseCaseTest {
|
|
53
|
+
private val useCase = CalculateDiscountUseCase()
|
|
54
|
+
|
|
55
|
+
@Test
|
|
56
|
+
fun `applies 20 percent discount when total exceeds 100`() {
|
|
57
|
+
val result = useCase(120.0)
|
|
58
|
+
assertEquals(96.0, result, 0.01)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Test
|
|
62
|
+
fun `no discount when total is 100 or less`() {
|
|
63
|
+
val result = useCase(100.0)
|
|
64
|
+
assertEquals(100.0, result, 0.01)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
--- GREEN (implementation) ---
|
|
69
|
+
class CalculateDiscountUseCase {
|
|
70
|
+
operator fun invoke(total: Double): Double =
|
|
71
|
+
if (total > 100.0) total * 0.80 else total
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
--- REFACTOR ---
|
|
75
|
+
private const val DISCOUNT_THRESHOLD = 100.0
|
|
76
|
+
private const val DISCOUNT_RATE = 0.80
|
|
77
|
+
|
|
78
|
+
class CalculateDiscountUseCase {
|
|
79
|
+
operator fun invoke(total: Double): Double =
|
|
80
|
+
if (total > DISCOUNT_THRESHOLD) total * DISCOUNT_RATE else total
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Notes
|
|
87
|
+
|
|
88
|
+
- Always write the test before asking for the implementation.
|
|
89
|
+
- For coroutine-heavy code, add `@OptIn(ExperimentalCoroutinesApi::class)` and use `runTest`.
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Skill — /anr-investigation
|
|
2
|
+
|
|
3
|
+
**Platform:** Android
|
|
4
|
+
**Slash Command:** `/anr-investigation`
|
|
5
|
+
**Composable With:** Android Crash Analyzer, AXIOM, PERF, MOBILE-HARNESS
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Investigate Android ANRs from Play Console, Firebase Crashlytics, `traces.txt`, `/data/anr/anr_*`, `ApplicationExitInfo`, bug reports, or source code. Identify the unresponsive thread, blocking dependency, root cause, safe fix, and verification plan.
|
|
12
|
+
|
|
13
|
+
This skill is evidence-first. Do not blame the top app frame without checking thread state, locks, binder calls, and owner threads.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Input Format
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
COMMAND: /anr-investigation
|
|
21
|
+
APP_VERSION: <version/build>
|
|
22
|
+
ANDROID_VERSION: <version or unknown>
|
|
23
|
+
DEVICE: <model or unknown>
|
|
24
|
+
ANR_SOURCE: <Play Console | Crashlytics | traces.txt | bugreport | ApplicationExitInfo>
|
|
25
|
+
ANR_REASON:
|
|
26
|
+
<reason, cluster title, or timeout message>
|
|
27
|
+
USER_ACTION:
|
|
28
|
+
<what the user was doing>
|
|
29
|
+
TRACE:
|
|
30
|
+
<full ANR trace or all available thread stacks>
|
|
31
|
+
RELATED_CODE:
|
|
32
|
+
<relevant Activity, ViewModel, repository, service, receiver, worker, or database code>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Skill Prompt
|
|
38
|
+
|
|
39
|
+
````text
|
|
40
|
+
Investigate the Android ANR using the supplied evidence.
|
|
41
|
+
|
|
42
|
+
STEP 1 — VERIFY EVIDENCE
|
|
43
|
+
- Confirm whether the full trace and ANR reason are present.
|
|
44
|
+
- Require the main thread plus any thread that may own a lock or binder response.
|
|
45
|
+
- If only one frame or a partial trace is available, mark confidence LOW and list the missing evidence.
|
|
46
|
+
- Do not invent line numbers, locks, timing, or thread ownership.
|
|
47
|
+
|
|
48
|
+
STEP 2 — CLASSIFY THE ANR
|
|
49
|
+
Classify as one of:
|
|
50
|
+
- Input dispatch timeout
|
|
51
|
+
- Service execution timeout
|
|
52
|
+
- Foreground service start timeout
|
|
53
|
+
- BroadcastReceiver timeout
|
|
54
|
+
- JobService timeout
|
|
55
|
+
- Main-thread I/O or computation
|
|
56
|
+
- Binder stall
|
|
57
|
+
- Lock contention
|
|
58
|
+
- Deadlock
|
|
59
|
+
- Slow startup
|
|
60
|
+
- Unknown
|
|
61
|
+
|
|
62
|
+
STEP 3 — READ THREAD STATES
|
|
63
|
+
- Locate the "main" thread and record RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, or NATIVE.
|
|
64
|
+
- RUNNABLE: inspect expensive computation, disk/network/database I/O, class loading, Compose/layout work, or synchronous SDK initialization.
|
|
65
|
+
- BLOCKED: identify the monitor/lock and find the owning thread.
|
|
66
|
+
- WAITING: identify Future.get, CountDownLatch.await, join, runBlocking, wait, semaphore, mutex, or synchronous callback.
|
|
67
|
+
- NATIVE: inspect binder, file, database, graphics, or native SDK frames.
|
|
68
|
+
- For deadlocks, show the complete wait-for cycle.
|
|
69
|
+
|
|
70
|
+
STEP 4 — CORRELATE WITH CODE
|
|
71
|
+
Check for:
|
|
72
|
+
- Disk, Room/SQLite, SharedPreferences commit, file, JSON, bitmap, crypto, or network work on main.
|
|
73
|
+
- runBlocking, Future.get, Thread.join, CountDownLatch.await, synchronized, locks, semaphores, or blocking callbacks.
|
|
74
|
+
- Slow Application/ContentProvider/Activity startup and eager dependency initialization.
|
|
75
|
+
- BroadcastReceiver.onReceive doing long work or goAsync without PendingResult.finish.
|
|
76
|
+
- Service lifecycle methods doing blocking work.
|
|
77
|
+
- startForegroundService without startForeground within the required window.
|
|
78
|
+
- JobService callbacks blocking instead of returning quickly.
|
|
79
|
+
- Synchronous binder calls or third-party SDK initialization.
|
|
80
|
+
- Compose recomposition/layout loops only when trace evidence supports them.
|
|
81
|
+
|
|
82
|
+
STEP 5 — PROPOSE THE SMALLEST SAFE FIX
|
|
83
|
+
- Fix the proven blocking path, not merely the top stack frame.
|
|
84
|
+
- Use structured coroutines and appropriate dispatchers, but do not wrap unknown code in Dispatchers.IO blindly.
|
|
85
|
+
- Avoid replacing one ANR with lost work, races, lifecycle leaks, or unbounded background work.
|
|
86
|
+
- Use WorkManager for deferrable persistent work; keep receiver/service/job callbacks short.
|
|
87
|
+
- Reduce lock scope or redesign ownership for contention/deadlock.
|
|
88
|
+
- Provide before/after Kotlin when source is available.
|
|
89
|
+
|
|
90
|
+
STEP 6 — VERIFY
|
|
91
|
+
Include:
|
|
92
|
+
- Deterministic reproduction steps.
|
|
93
|
+
- StrictMode or tracing setup where relevant.
|
|
94
|
+
- Low-end device and cold-start testing.
|
|
95
|
+
- Macrobenchmark/startup measurement where relevant.
|
|
96
|
+
- Regression test or test seam.
|
|
97
|
+
- Play Console ANR cluster and user-perceived ANR monitoring.
|
|
98
|
+
|
|
99
|
+
Output normal Markdown. Do not wrap the full report in a code block.
|
|
100
|
+
|
|
101
|
+
ANDROID ANR INVESTIGATION
|
|
102
|
+
=========================
|
|
103
|
+
Result: CONFIRMED | LIKELY | INCONCLUSIVE
|
|
104
|
+
Confidence: HIGH | MEDIUM | LOW
|
|
105
|
+
ANR Type:
|
|
106
|
+
Trigger:
|
|
107
|
+
|
|
108
|
+
Evidence Summary:
|
|
109
|
+
| Evidence | Observation |
|
|
110
|
+
|---|---|
|
|
111
|
+
|
|
112
|
+
Thread Analysis:
|
|
113
|
+
| Thread | State | Waiting On / Work | Significance |
|
|
114
|
+
|---|---|---|---|
|
|
115
|
+
|
|
116
|
+
Root Cause:
|
|
117
|
+
<proven causal chain, or what remains unknown>
|
|
118
|
+
|
|
119
|
+
Fix:
|
|
120
|
+
<smallest safe fix>
|
|
121
|
+
|
|
122
|
+
Updated Code:
|
|
123
|
+
```kotlin
|
|
124
|
+
<corrected code, or "Not available without related source">
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Verification:
|
|
128
|
+
- <step>
|
|
129
|
+
|
|
130
|
+
Missing Evidence:
|
|
131
|
+
- <item or "None">
|
|
132
|
+
|
|
133
|
+
Next Action:
|
|
134
|
+
<one concrete action>
|
|
135
|
+
````
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Example
|
|
140
|
+
|
|
141
|
+
### Input
|
|
142
|
+
|
|
143
|
+
```text
|
|
144
|
+
COMMAND: /anr-investigation
|
|
145
|
+
APP_VERSION: 4.8.0 (480)
|
|
146
|
+
ANDROID_VERSION: 14
|
|
147
|
+
DEVICE: Pixel 6a
|
|
148
|
+
ANR_SOURCE: Play Console
|
|
149
|
+
ANR_REASON:
|
|
150
|
+
Input dispatching timed out
|
|
151
|
+
USER_ACTION:
|
|
152
|
+
Cold launch, then tapped Sign in.
|
|
153
|
+
TRACE:
|
|
154
|
+
"main" prio=5 tid=1 Blocked
|
|
155
|
+
at com.example.session.SessionStore.read(SessionStore.kt:42)
|
|
156
|
+
- waiting to lock <0x1234> held by thread 18
|
|
157
|
+
at com.example.MainActivity.onCreate(MainActivity.kt:31)
|
|
158
|
+
|
|
159
|
+
"DefaultDispatcher-worker-3" prio=5 tid=18 Runnable
|
|
160
|
+
at com.example.session.SessionStore.refresh(SessionStore.kt:68)
|
|
161
|
+
- locked <0x1234>
|
|
162
|
+
at com.example.session.SessionRepository.refresh(SessionRepository.kt:51)
|
|
163
|
+
RELATED_CODE:
|
|
164
|
+
class SessionStore {
|
|
165
|
+
@Synchronized
|
|
166
|
+
fun read(): Session? = cachedSession
|
|
167
|
+
|
|
168
|
+
@Synchronized
|
|
169
|
+
fun refresh(): Session {
|
|
170
|
+
val response = blockingApi.refreshToken()
|
|
171
|
+
return response.toSession().also { cachedSession = it }
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Output
|
|
177
|
+
|
|
178
|
+
````markdown
|
|
179
|
+
ANDROID ANR INVESTIGATION
|
|
180
|
+
=========================
|
|
181
|
+
Result: CONFIRMED
|
|
182
|
+
Confidence: HIGH
|
|
183
|
+
ANR Type: Lock contention causing input dispatch timeout
|
|
184
|
+
Trigger: Cold launch while token refresh holds SessionStore monitor
|
|
185
|
+
|
|
186
|
+
Evidence Summary:
|
|
187
|
+
| Evidence | Observation |
|
|
188
|
+
|---|---|
|
|
189
|
+
| Main thread | BLOCKED in SessionStore.read |
|
|
190
|
+
| Monitor | `0x1234`, owned by thread 18 |
|
|
191
|
+
| Owner thread | Performs blocking token refresh |
|
|
192
|
+
| Timeout reason | Input dispatching timed out |
|
|
193
|
+
|
|
194
|
+
Thread Analysis:
|
|
195
|
+
| Thread | State | Waiting On / Work | Significance |
|
|
196
|
+
|---|---|---|---|
|
|
197
|
+
| main | BLOCKED | SessionStore monitor | Cannot process input |
|
|
198
|
+
| worker-3 | RUNNABLE | Blocking network refresh | Holds required monitor |
|
|
199
|
+
|
|
200
|
+
Root Cause:
|
|
201
|
+
`SessionStore.refresh()` holds the object monitor during a blocking network request. `MainActivity.onCreate()` calls `read()`, which requires the same monitor. The main thread remains blocked until the network request returns, causing the input timeout.
|
|
202
|
+
|
|
203
|
+
Fix:
|
|
204
|
+
Do not hold the session lock during network I/O. Perform refresh outside the critical section and lock only the in-memory assignment. Expose session reads without waiting on network work.
|
|
205
|
+
|
|
206
|
+
Updated Code:
|
|
207
|
+
```kotlin
|
|
208
|
+
class SessionStore(
|
|
209
|
+
private val api: SessionApi,
|
|
210
|
+
) {
|
|
211
|
+
@Volatile
|
|
212
|
+
private var cachedSession: Session? = null
|
|
213
|
+
|
|
214
|
+
fun read(): Session? = cachedSession
|
|
215
|
+
|
|
216
|
+
suspend fun refresh(): Session {
|
|
217
|
+
val refreshed = withContext(Dispatchers.IO) {
|
|
218
|
+
api.refreshToken().toSession()
|
|
219
|
+
}
|
|
220
|
+
cachedSession = refreshed
|
|
221
|
+
return refreshed
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Verification:
|
|
227
|
+
- Reproduce cold launch while delaying refresh by 10 seconds.
|
|
228
|
+
- Enable StrictMode and confirm no main-thread network/disk violations.
|
|
229
|
+
- Capture a system trace and verify main remains runnable.
|
|
230
|
+
- Repeat launch and sign-in on a low-end Android device.
|
|
231
|
+
- Monitor the Play Console ANR cluster after staged rollout.
|
|
232
|
+
|
|
233
|
+
Missing Evidence:
|
|
234
|
+
- None
|
|
235
|
+
|
|
236
|
+
Next Action:
|
|
237
|
+
Remove network I/O from the SessionStore monitor, then rerun the delayed-refresh cold-launch test.
|
|
238
|
+
````
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Usage Notes
|
|
243
|
+
|
|
244
|
+
- A full thread dump is required for high-confidence lock and deadlock analysis.
|
|
245
|
+
- The main thread's top frame can be a victim rather than the cause; always inspect the thread holding its dependency.
|
|
246
|
+
- Pair with PERF for startup/system-trace work and Android Crash Analyzer for broader incident triage.
|
|
247
|
+
- This skill supports issue #2; a dedicated ANR agent can embed it and add expanded examples.
|
|
248
|
+
|
|
249
|
+
## Official Reference
|
|
250
|
+
|
|
251
|
+
- [Android Developers: ANRs](https://developer.android.com/topic/performance/vitals/anr)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Skill — Android Code Review
|
|
2
|
+
|
|
3
|
+
**Platform:** Android (Kotlin)
|
|
4
|
+
**Category:** Code Quality
|
|
5
|
+
**Composable With:** agents/android/code-reviewer/agent.md, skills/shared/clean-architecture-check.md
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Adds Android-specific code review rules to any LLM session. Use this as a skill module to prime a review session without running the full agent.
|
|
12
|
+
|
|
13
|
+
## When to Use
|
|
14
|
+
|
|
15
|
+
- When you want a quick inline review during a pair-programming session
|
|
16
|
+
- When composing a larger review workflow that covers multiple files
|
|
17
|
+
- When you want only Android-specific checks without the full structured output format
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Skill Prompt
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
When reviewing Android Kotlin code, check for these issues:
|
|
25
|
+
|
|
26
|
+
COROUTINE SAFETY
|
|
27
|
+
- Never use GlobalScope. Use viewModelScope (in ViewModel), lifecycleScope (in Activity/Fragment), or a custom CoroutineScope with a Job that is cancelled appropriately.
|
|
28
|
+
- Coroutines that call suspend functions should handle exceptions with try/catch or a CoroutineExceptionHandler. Fire-and-forget coroutines that swallow exceptions are bugs waiting to happen.
|
|
29
|
+
- UI state updates (LiveData.value, StateFlow updates) must happen on the Main dispatcher.
|
|
30
|
+
|
|
31
|
+
KOTLIN IDIOMS
|
|
32
|
+
- Prefer data class for value-holding types.
|
|
33
|
+
- Prefer sealed class for state/result types over Boolean flags or nullable + exception patterns.
|
|
34
|
+
- Prefer StateFlow + collectAsStateWithLifecycle over LiveData in new code.
|
|
35
|
+
- Use `?.let`, `?.run`, `?:` for null safety. Flag every `!!` operator as a candidate for removal.
|
|
36
|
+
- Prefer `when` expressions over chains of if/else.
|
|
37
|
+
|
|
38
|
+
DEPENDENCY INJECTION
|
|
39
|
+
- No `new MyRepository()` inside a ViewModel or Fragment. Dependencies must be injected (Hilt, Koin, manual constructor injection).
|
|
40
|
+
- No singletons held as companion object properties for testability-sensitive objects.
|
|
41
|
+
|
|
42
|
+
CLEAN ARCHITECTURE
|
|
43
|
+
- Domain layer (use cases, entities): zero Android framework imports.
|
|
44
|
+
- Data layer (repositories, data sources): no UI-level types, no Context except for file/preference access.
|
|
45
|
+
- Presentation layer (ViewModel): no database calls directly, no network calls directly — only use cases.
|
|
46
|
+
|
|
47
|
+
COMPOSE (if applicable)
|
|
48
|
+
- Side effects belong in LaunchedEffect, not in composable bodies.
|
|
49
|
+
- Expensive calculations belong in remember { } or derivedStateOf { }.
|
|
50
|
+
- Avoid reading mutableStateOf values outside of composition.
|
|
51
|
+
- collectAsStateWithLifecycle is preferred over collectAsState for lifecycle awareness.
|
|
52
|
+
|
|
53
|
+
For each issue found, state: the line or function, what is wrong, and a concrete fix.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Example
|
|
59
|
+
|
|
60
|
+
**Input (after applying skill prompt):**
|
|
61
|
+
```
|
|
62
|
+
Review this ViewModel:
|
|
63
|
+
|
|
64
|
+
class OrderViewModel : ViewModel() {
|
|
65
|
+
fun placeOrder(items: List<Item>) {
|
|
66
|
+
GlobalScope.launch {
|
|
67
|
+
OrderRepository().submit(items)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Output:**
|
|
74
|
+
```
|
|
75
|
+
Line 3 — GlobalScope leak: Replace with viewModelScope.launch { ... }
|
|
76
|
+
Line 4 — Direct repository instantiation: Inject OrderRepository via constructor.
|
|
77
|
+
No error handling: If submit() throws, the exception is silently dropped.
|
|
78
|
+
Suggestion: Wrap in try/catch and expose error state via a StateFlow<OrderState>.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Composition Example
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
Prepend this skill prompt before the Android Code Reviewer system prompt to add
|
|
87
|
+
a focused lens on coroutines and Compose alongside the full structured review output.
|
|
88
|
+
|
|
89
|
+
Or use standalone in a Claude Code chat session — paste this skill, then paste
|
|
90
|
+
your Kotlin file and ask "Review this for the issues listed above."
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Notes
|
|
96
|
+
|
|
97
|
+
- This skill covers Kotlin only. For Java Android code, the coroutine rules do not apply but the DI and Clean Architecture rules still hold.
|
|
98
|
+
- Compose checks require Compose to be in use — skip those rules for View-based UIs.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Skill — /compose-migration
|
|
2
|
+
|
|
3
|
+
**Platform:** Android
|
|
4
|
+
**Slash Command:** `/compose-migration`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Systematically converts Android XML layouts to Jetpack Compose. Handles ConstraintLayout, RecyclerView, ViewPager2, and custom views. Produces idiomatic Compose code with proper state lifting.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Skill Prompt
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Migrate the provided Android XML layout (or View-based code) to Jetpack Compose:
|
|
18
|
+
|
|
19
|
+
MIGRATION RULES:
|
|
20
|
+
1. Layout mapping:
|
|
21
|
+
- LinearLayout (vertical) → Column
|
|
22
|
+
- LinearLayout (horizontal) → Row
|
|
23
|
+
- FrameLayout / merge → Box
|
|
24
|
+
- ConstraintLayout → ConstraintLayout (Compose) or restructured Column/Row/Box
|
|
25
|
+
- ScrollView → Column inside verticalScroll(rememberScrollState())
|
|
26
|
+
- RecyclerView → LazyColumn / LazyRow with items(key = { ... })
|
|
27
|
+
- ViewPager2 → HorizontalPager (Accompanist/Foundation)
|
|
28
|
+
|
|
29
|
+
2. Attribute mapping:
|
|
30
|
+
- android:layout_width="match_parent" → Modifier.fillMaxWidth()
|
|
31
|
+
- android:layout_width="wrap_content" → default (no modifier needed)
|
|
32
|
+
- android:padding → Modifier.padding()
|
|
33
|
+
- android:gravity / layout_gravity → Arrangement + Alignment
|
|
34
|
+
- android:visibility → if (condition) { Composable() }
|
|
35
|
+
- android:background → Modifier.background()
|
|
36
|
+
- android:textSize / textColor / fontStyle → TextStyle or MaterialTheme.typography
|
|
37
|
+
|
|
38
|
+
3. State lifting:
|
|
39
|
+
- View state (setVisibility, setText) → hoist to ViewModel StateFlow
|
|
40
|
+
- ClickListeners → lambda parameters on the composable
|
|
41
|
+
- TextWatcher → onValueChange with mutableStateOf
|
|
42
|
+
|
|
43
|
+
4. Custom views:
|
|
44
|
+
- AndroidView { } wrapper for views with no Compose equivalent
|
|
45
|
+
- Migrate incrementally — keep complex custom views as AndroidView until full migration
|
|
46
|
+
|
|
47
|
+
Output the complete Compose equivalent. Note any migration challenges or manual steps needed.
|
|
48
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Skill — /compose-review
|
|
2
|
+
|
|
3
|
+
**Platform:** Android (Jetpack Compose)
|
|
4
|
+
**Slash Command:** `/compose-review`
|
|
5
|
+
**Composable With:** agents/android/axiom/agent.md
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Recomposition audit for Jetpack Compose files. Flags unnecessary recompositions, incorrect state usage, missing `const` constructors, and lambda instability before PR merge.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Skill Prompt
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Audit the provided Jetpack Compose code for recomposition issues:
|
|
19
|
+
|
|
20
|
+
1. UNNECESSARY RECOMPOSITIONS
|
|
21
|
+
- Lambdas passed as parameters that are recreated every composition.
|
|
22
|
+
Fix: wrap in remember { } or move to ViewModel.
|
|
23
|
+
- Objects created inline in composable bodies (val list = listOf(...) inside Composable).
|
|
24
|
+
Fix: hoist to remember { } or to the ViewModel.
|
|
25
|
+
- Reading State inside a composable that also writes it (causes infinite recomposition).
|
|
26
|
+
|
|
27
|
+
2. STATE USAGE
|
|
28
|
+
- remember vs rememberSaveable: use rememberSaveable for state that survives config changes.
|
|
29
|
+
- derivedStateOf: use when computing a value that depends on other state to minimize recompositions.
|
|
30
|
+
- collectAsStateWithLifecycle: always prefer over collectAsState for lifecycle safety.
|
|
31
|
+
- mutableStateListOf / mutableStateMapOf: flag direct mutations that don't trigger recomposition.
|
|
32
|
+
|
|
33
|
+
3. COMPOSITION KEYS
|
|
34
|
+
- LazyList items missing key parameter → unnecessary recomposition on list changes.
|
|
35
|
+
- key { } block containing a mutable value that changes without semantic identity change.
|
|
36
|
+
|
|
37
|
+
4. SIDE EFFECTS
|
|
38
|
+
- Bare code in composable body that has side effects (file I/O, network, logging).
|
|
39
|
+
Fix: wrap in SideEffect, LaunchedEffect, or DisposableEffect as appropriate.
|
|
40
|
+
- LaunchedEffect with Unit key that should restart on specific input changes.
|
|
41
|
+
|
|
42
|
+
5. PERFORMANCE
|
|
43
|
+
- Composables that could be @Stable or marked as stable data classes.
|
|
44
|
+
- Heavy computations not wrapped in remember { } with appropriate keys.
|
|
45
|
+
|
|
46
|
+
For each issue: state the composable name, line (if given), what triggers the recomposition, and the fix.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Example
|
|
52
|
+
|
|
53
|
+
**Input:**
|
|
54
|
+
```kotlin
|
|
55
|
+
@Composable
|
|
56
|
+
fun UserList(users: List<User>) {
|
|
57
|
+
val filtered = users.filter { it.isActive }
|
|
58
|
+
LazyColumn {
|
|
59
|
+
items(filtered) { user ->
|
|
60
|
+
UserRow(user = user, onClick = { navigateToProfile(user.id) })
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Output:**
|
|
67
|
+
```
|
|
68
|
+
Line 3 — List filtered in composable body
|
|
69
|
+
Every recomposition re-runs users.filter { } creating a new list.
|
|
70
|
+
Fix: val filtered = remember(users) { users.filter { it.isActive } }
|
|
71
|
+
|
|
72
|
+
LazyColumn items — missing key parameter
|
|
73
|
+
Without key, LazyColumn re-renders ALL items when the list changes.
|
|
74
|
+
Fix: items(filtered, key = { it.id }) { user -> ... }
|
|
75
|
+
|
|
76
|
+
Line 4 — Lambda { navigateToProfile(user.id) } recreated per item per recomposition
|
|
77
|
+
Fix: val onUserClick = remember(user.id) { { navigateToProfile(user.id) } }
|
|
78
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Skill — /kotlin-modernize
|
|
2
|
+
|
|
3
|
+
**Platform:** Android (Kotlin)
|
|
4
|
+
**Slash Command:** `/kotlin-modernize`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Upgrades Java-style Kotlin or pre-2.0 Kotlin code to modern Kotlin idioms. Converts verbose patterns to concise equivalents, introduces sealed classes, coroutines, and Flow where appropriate.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Skill Prompt
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Modernize the provided Kotlin code using current idiomatic patterns:
|
|
18
|
+
|
|
19
|
+
KOTLIN MODERNIZATION CHECKLIST:
|
|
20
|
+
1. Null safety:
|
|
21
|
+
- Replace `if (x != null)` with `x?.let { }` or `x ?: default`
|
|
22
|
+
- Remove all `!!` operators — replace with safe call + Elvis or requireNotNull with message
|
|
23
|
+
- Replace nullable + isInitialized patterns with lateinit + try/catch or by lazy { }
|
|
24
|
+
|
|
25
|
+
2. Data structures:
|
|
26
|
+
- Java-style Builder pattern → named parameters + default values
|
|
27
|
+
- Value objects with equals/hashCode → data class
|
|
28
|
+
- Enum with methods → sealed class with data objects/data classes
|
|
29
|
+
|
|
30
|
+
3. Collections:
|
|
31
|
+
- Imperative loops → map, filter, flatMap, fold, groupBy, associate
|
|
32
|
+
- Mutable collections passed as function params → immutable + return new list
|
|
33
|
+
- Java stream() → Kotlin collection functions (simpler, no stream overhead on Android)
|
|
34
|
+
|
|
35
|
+
4. Coroutines (if async code present):
|
|
36
|
+
- Callback hell → suspend functions + coroutines
|
|
37
|
+
- AsyncTask → viewModelScope.launch + suspend function
|
|
38
|
+
- RxJava (if present) → Flow equivalents: Observable → Flow, Single → suspend fun
|
|
39
|
+
|
|
40
|
+
5. Scope functions:
|
|
41
|
+
- Multi-line null checks → let
|
|
42
|
+
- Object initialization chains → apply or also
|
|
43
|
+
- Result transformation → run or with
|
|
44
|
+
|
|
45
|
+
6. String handling:
|
|
46
|
+
- String concatenation in loops → buildString { }
|
|
47
|
+
- Format strings → string templates
|
|
48
|
+
- Multi-line strings → trimIndent() triple-quoted strings
|
|
49
|
+
|
|
50
|
+
Show before and after for each significant transformation.
|
|
51
|
+
```
|