create-cmp-cli 0.2.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 (139) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/bin/create-cmp.mjs +91 -0
  4. package/options.schema.json +110 -0
  5. package/package.json +52 -0
  6. package/src/bootstrap/checks.mjs +283 -0
  7. package/src/bootstrap/exec.mjs +90 -0
  8. package/src/commands/clean.mjs +195 -0
  9. package/src/commands/create.mjs +223 -0
  10. package/src/commands/doctor.mjs +256 -0
  11. package/src/commands/upgrade.mjs +196 -0
  12. package/src/commands/verify.mjs +94 -0
  13. package/src/doctor.mjs +109 -0
  14. package/src/lib/args.mjs +38 -0
  15. package/src/lib/clean.mjs +72 -0
  16. package/src/lib/fsutil.mjs +90 -0
  17. package/src/lib/log.mjs +40 -0
  18. package/src/lib/project-doctor.mjs +329 -0
  19. package/src/lib/registry.mjs +102 -0
  20. package/src/lib/rename.mjs +116 -0
  21. package/src/lib/schema.mjs +123 -0
  22. package/src/lib/toggle.mjs +130 -0
  23. package/src/lib/tokens.mjs +96 -0
  24. package/src/lib/toml.mjs +137 -0
  25. package/src/lib/upgrade.mjs +159 -0
  26. package/src/lib/verify.mjs +97 -0
  27. package/src/scaffold.mjs +347 -0
  28. package/src/verify.mjs +4 -0
  29. package/src/versions/registry.json +42 -0
  30. package/template/.github/workflows/verify.yml +70 -0
  31. package/template/build.gradle.kts +17 -0
  32. package/template/composeApp/build.gradle.kts +257 -0
  33. package/template/composeApp/google-services.json +29 -0
  34. package/template/composeApp/proguard-rules.pro +34 -0
  35. package/template/composeApp/src/androidDebug/AndroidManifest.xml +13 -0
  36. package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/ComposeRootRegistry.kt +40 -0
  37. package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/InspectorCatalog.kt +80 -0
  38. package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/InspectorHttpServer.kt +322 -0
  39. package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/InspectorInit.kt +16 -0
  40. package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/LiveSemanticsJson.kt +102 -0
  41. package/template/composeApp/src/androidDebug/kotlin/com/example/app/inspector/RemoteControlPage.kt +106 -0
  42. package/template/composeApp/src/androidDebug/res/xml/debug_network_security_config.xml +9 -0
  43. package/template/composeApp/src/androidMain/AndroidManifest.xml +28 -0
  44. package/template/composeApp/src/androidMain/kotlin/com/example/app/AppApplication.kt +72 -0
  45. package/template/composeApp/src/androidMain/kotlin/com/example/app/MainActivity.kt +24 -0
  46. package/template/composeApp/src/androidMain/kotlin/com/example/app/core/connectivity/NetworkMonitor.kt +42 -0
  47. package/template/composeApp/src/androidMain/kotlin/com/example/app/data/local/DatabaseBuilder.android.kt +13 -0
  48. package/template/composeApp/src/androidMain/kotlin/com/example/app/di/AndroidModule.kt +9 -0
  49. package/template/composeApp/src/androidMain/kotlin/com/example/app/presentation/components/TestTagAutomation.android.kt +11 -0
  50. package/template/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml +9 -0
  51. package/template/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
  52. package/template/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
  53. package/template/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png +0 -0
  54. package/template/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
  55. package/template/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  56. package/template/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png +0 -0
  57. package/template/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
  58. package/template/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  59. package/template/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png +0 -0
  60. package/template/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
  61. package/template/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  62. package/template/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  63. package/template/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
  64. package/template/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  65. package/template/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  66. package/template/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
  67. package/template/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  68. package/template/composeApp/src/androidMain/res/values/colors.xml +6 -0
  69. package/template/composeApp/src/androidMain/res/values/themes.xml +9 -0
  70. package/template/composeApp/src/androidMain/res/values-v31/themes.xml +8 -0
  71. package/template/composeApp/src/androidRelease/kotlin/com/example/app/inspector/InspectorInit.kt +13 -0
  72. package/template/composeApp/src/commonMain/composeResources/font/DMSans_Bold.ttf +0 -0
  73. package/template/composeApp/src/commonMain/composeResources/font/DMSans_Medium.ttf +0 -0
  74. package/template/composeApp/src/commonMain/composeResources/font/DMSans_Regular.ttf +0 -0
  75. package/template/composeApp/src/commonMain/composeResources/font/DMSans_SemiBold.ttf +0 -0
  76. package/template/composeApp/src/commonMain/kotlin/com/example/app/App.kt +7 -0
  77. package/template/composeApp/src/commonMain/kotlin/com/example/app/core/connectivity/NetworkMonitor.kt +7 -0
  78. package/template/composeApp/src/commonMain/kotlin/com/example/app/data/local/AppDatabase.kt +28 -0
  79. package/template/composeApp/src/commonMain/kotlin/com/example/app/data/local/DatabaseBuilder.kt +14 -0
  80. package/template/composeApp/src/commonMain/kotlin/com/example/app/data/local/ItemDao.kt +18 -0
  81. package/template/composeApp/src/commonMain/kotlin/com/example/app/data/remote/FirebaseConfig.kt +5 -0
  82. package/template/composeApp/src/commonMain/kotlin/com/example/app/data/remote/ItemRepositoryImpl.kt +22 -0
  83. package/template/composeApp/src/commonMain/kotlin/com/example/app/di/AppModule.kt +23 -0
  84. package/template/composeApp/src/commonMain/kotlin/com/example/app/domain/model/Item.kt +8 -0
  85. package/template/composeApp/src/commonMain/kotlin/com/example/app/domain/repository/ItemRepository.kt +8 -0
  86. package/template/composeApp/src/commonMain/kotlin/com/example/app/domain/usecase/GetItemsUseCase.kt +12 -0
  87. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/App.kt +13 -0
  88. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/components/BaseScreen.kt +69 -0
  89. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/components/TestTagAutomation.kt +18 -0
  90. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/home/DetailScreen.kt +39 -0
  91. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/home/HomeScreen.kt +87 -0
  92. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/home/HomeViewModel.kt +35 -0
  93. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/navigation/AppNavHost.kt +43 -0
  94. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/navigation/AppShell.kt +144 -0
  95. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/navigation/AppTab.kt +25 -0
  96. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/navigation/Screen.kt +15 -0
  97. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/profile/ProfileScreen.kt +43 -0
  98. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/DesignToken.kt +25 -0
  99. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/Shape.kt +12 -0
  100. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/Theme.kt +64 -0
  101. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/Tokens.kt +19 -0
  102. package/template/composeApp/src/commonMain/kotlin/com/example/app/presentation/theme/Typography.kt +36 -0
  103. package/template/composeApp/src/desktopMain/kotlin/com/example/app/core/connectivity/NetworkMonitor.desktop.kt +9 -0
  104. package/template/composeApp/src/desktopMain/kotlin/com/example/app/data/local/DatabaseBuilder.desktop.kt +13 -0
  105. package/template/composeApp/src/desktopMain/kotlin/com/example/app/di/DesktopModule.kt +32 -0
  106. package/template/composeApp/src/desktopMain/kotlin/com/example/app/main.kt +29 -0
  107. package/template/composeApp/src/desktopMain/kotlin/com/example/app/presentation/components/TestTagAutomation.desktop.kt +6 -0
  108. package/template/composeApp/src/iosMain/kotlin/com/example/app/KoinHelper.kt +50 -0
  109. package/template/composeApp/src/iosMain/kotlin/com/example/app/MainViewController.kt +10 -0
  110. package/template/composeApp/src/iosMain/kotlin/com/example/app/core/connectivity/NetworkMonitor.kt +32 -0
  111. package/template/composeApp/src/iosMain/kotlin/com/example/app/data/local/DatabaseBuilder.ios.kt +10 -0
  112. package/template/composeApp/src/iosMain/kotlin/com/example/app/presentation/components/TestTagAutomation.ios.kt +11 -0
  113. package/template/docs/dev-client.md +52 -0
  114. package/template/gitignore +21 -0
  115. package/template/gradle/libs.versions.toml +100 -0
  116. package/template/gradle/wrapper/gradle-wrapper.jar +0 -0
  117. package/template/gradle/wrapper/gradle-wrapper.properties +7 -0
  118. package/template/gradle.properties +9 -0
  119. package/template/gradlew +152 -0
  120. package/template/gradlew.bat +94 -0
  121. package/template/iosApp/Podfile +27 -0
  122. package/template/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png +0 -0
  123. package/template/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
  124. package/template/iosApp/iosApp/Assets.xcassets/Contents.json +6 -0
  125. package/template/iosApp/iosApp/ContentView.swift +17 -0
  126. package/template/iosApp/iosApp/GoogleService-Info.plist +34 -0
  127. package/template/iosApp/iosApp/Info.plist +43 -0
  128. package/template/iosApp/iosApp/PrivacyInfo.xcprivacy +42 -0
  129. package/template/iosApp/iosApp/iOSApp.swift +33 -0
  130. package/template/iosApp/project.yml +56 -0
  131. package/template/local.properties.example +2 -0
  132. package/template/manifest.json +125 -0
  133. package/template/qa/appium/README.md +23 -0
  134. package/template/qa/appium/lib/appium-client.mjs +225 -0
  135. package/template/qa/appium/package.json +8 -0
  136. package/template/qa/appium/run-android-smoke.mjs +39 -0
  137. package/template/settings.gradle.kts +34 -0
  138. package/template/tests/appium/cmp/conftest.py +96 -0
  139. package/template/tests/appium/cmp/test_smoke.py +17 -0
@@ -0,0 +1,257 @@
1
+ import org.jetbrains.compose.resources.ResourcesExtension
2
+ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
3
+ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
4
+
5
+ plugins {
6
+ alias(libs.plugins.kotlin.multiplatform)
7
+ alias(libs.plugins.kotlin.serialization)
8
+ alias(libs.plugins.compose.multiplatform)
9
+ alias(libs.plugins.compose.compiler)
10
+ alias(libs.plugins.android.application)
11
+ // >>> cmp:feature firebase
12
+ alias(libs.plugins.google.services)
13
+ // <<< cmp:feature firebase
14
+ // >>> cmp:feature room
15
+ alias(libs.plugins.ksp)
16
+ alias(libs.plugins.room)
17
+ // <<< cmp:feature room
18
+ // >>> cmp:feature dev-client
19
+ alias(libs.plugins.compose.hot.reload)
20
+ // <<< cmp:feature dev-client
21
+ }
22
+
23
+ kotlin {
24
+ compilerOptions {
25
+ // kotlinx-datetime 0.7.x Clock/Instant delegate to the experimental kotlin.time
26
+ // types on Kotlin 2.2.20; opt in project-wide.
27
+ optIn.add("kotlin.time.ExperimentalTime")
28
+ // >>> cmp:feature ios
29
+ // iosMain cinterop Foreign APIs (NWPathMonitor, NSHomeDirectory, etc.)
30
+ optIn.add("kotlinx.cinterop.ExperimentalForeignApi")
31
+ // <<< cmp:feature ios
32
+ }
33
+
34
+ androidTarget {
35
+ @OptIn(ExperimentalKotlinGradlePluginApi::class)
36
+ compilerOptions {
37
+ jvmTarget.set(JvmTarget.JVM_17)
38
+ }
39
+ }
40
+
41
+ // >>> cmp:feature ios
42
+ listOf(
43
+ iosX64(),
44
+ iosArm64(),
45
+ iosSimulatorArm64()
46
+ ).forEach { iosTarget ->
47
+ iosTarget.binaries.framework {
48
+ baseName = "ComposeApp"
49
+ isStatic = true
50
+ }
51
+ }
52
+ // <<< cmp:feature ios
53
+
54
+ // >>> cmp:feature dev-client
55
+ // Desktop dev-client: runs the shared commonMain UI in a live JVM window — the daily dev
56
+ // loop. Compose Hot Reload attaches to this target (task: hotRunDesktop). See docs/dev-client.md.
57
+ jvm("desktop") {
58
+ @OptIn(ExperimentalKotlinGradlePluginApi::class)
59
+ compilerOptions {
60
+ jvmTarget.set(JvmTarget.JVM_17)
61
+ }
62
+ }
63
+ // <<< cmp:feature dev-client
64
+
65
+ sourceSets {
66
+ commonMain.dependencies {
67
+ implementation(compose.runtime)
68
+ implementation(compose.foundation)
69
+ implementation(compose.material3)
70
+ implementation(compose.materialIconsExtended)
71
+ implementation(compose.ui)
72
+ implementation(compose.components.resources)
73
+
74
+ // Lifecycle / ViewModel
75
+ implementation(libs.lifecycle.viewmodel)
76
+ implementation(libs.lifecycle.viewmodel.compose)
77
+ implementation(libs.lifecycle.runtime.compose)
78
+
79
+ // Navigation
80
+ implementation(libs.navigation.compose)
81
+
82
+ // Koin DI
83
+ implementation(libs.koin.core)
84
+ implementation(libs.koin.compose)
85
+ implementation(libs.koin.compose.viewmodel)
86
+
87
+ // Ktor
88
+ implementation(libs.ktor.client.core)
89
+ implementation(libs.ktor.client.content.negotiation)
90
+ implementation(libs.ktor.serialization.kotlinx.json)
91
+
92
+ // >>> cmp:feature firebase
93
+ implementation(libs.firebase.auth)
94
+ implementation(libs.firebase.firestore)
95
+ implementation(libs.firebase.functions)
96
+ implementation(libs.firebase.storage)
97
+ implementation(libs.firebase.messaging)
98
+ implementation(libs.firebase.config)
99
+ // <<< cmp:feature firebase
100
+
101
+ // >>> cmp:feature room
102
+ implementation(libs.room.runtime)
103
+ implementation(libs.sqlite.bundled)
104
+ // <<< cmp:feature room
105
+
106
+ // Kotlinx
107
+ implementation(libs.kotlinx.serialization.json)
108
+ implementation(libs.kotlinx.datetime)
109
+ implementation(libs.kotlinx.coroutines.core)
110
+
111
+ // Coil image loading
112
+ implementation(libs.coil.compose)
113
+ implementation(libs.coil.network.ktor)
114
+ }
115
+
116
+ androidMain.dependencies {
117
+ implementation(libs.androidx.core.ktx)
118
+ implementation(libs.androidx.activity.compose)
119
+ implementation(libs.ktor.client.cio)
120
+ implementation(libs.koin.android)
121
+ implementation(libs.kotlinx.coroutines.android)
122
+ // >>> cmp:feature room
123
+ implementation(libs.room.runtime.android)
124
+ // <<< cmp:feature room
125
+ }
126
+
127
+ // >>> cmp:feature ios
128
+ iosMain.dependencies {
129
+ implementation(libs.ktor.client.darwin)
130
+ }
131
+ // <<< cmp:feature ios
132
+
133
+ // >>> cmp:feature dev-client
134
+ val desktopMain by getting {
135
+ dependencies {
136
+ implementation(compose.desktop.currentOs)
137
+ implementation(libs.kotlinx.coroutines.swing)
138
+ implementation(libs.ktor.client.cio)
139
+ }
140
+ }
141
+ // <<< cmp:feature dev-client
142
+
143
+ commonTest.dependencies {
144
+ implementation(libs.kotlin.test)
145
+ implementation(libs.koin.test)
146
+ implementation(libs.kotlinx.coroutines.test)
147
+ }
148
+ }
149
+ }
150
+
151
+ android {
152
+ namespace = "__PACKAGE__"
153
+ compileSdk = 35
154
+
155
+ defaultConfig {
156
+ applicationId = "__PACKAGE__"
157
+ minSdk = 24
158
+ targetSdk = 35
159
+ versionCode = 1
160
+ versionName = "1.0.0"
161
+ }
162
+
163
+ packaging {
164
+ resources {
165
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
166
+ }
167
+ }
168
+
169
+ buildFeatures {
170
+ buildConfig = true
171
+ }
172
+
173
+ buildTypes {
174
+ // >>> cmp:feature firebase
175
+ getByName("debug") {
176
+ // Debug builds point GitLive Firebase at the local emulators (see Application/KoinHelper).
177
+ // 10.0.2.2 is the Android emulator's host-loopback alias.
178
+ buildConfigField("boolean", "USE_FIREBASE_EMULATORS", "true")
179
+ buildConfigField("String", "FIREBASE_EMULATOR_HOST", "\"10.0.2.2\"")
180
+ buildConfigField("int", "FIREBASE_AUTH_PORT", "9099")
181
+ buildConfigField("int", "FIREBASE_FIRESTORE_PORT", "8080")
182
+ buildConfigField("int", "FIREBASE_FUNCTIONS_PORT", "5001")
183
+ buildConfigField("int", "FIREBASE_STORAGE_PORT", "9199")
184
+ manifestPlaceholders["usesCleartextTraffic"] = "true"
185
+ }
186
+ getByName("release") {
187
+ isMinifyEnabled = true
188
+ isShrinkResources = true
189
+ buildConfigField("boolean", "USE_FIREBASE_EMULATORS", "false")
190
+ manifestPlaceholders["usesCleartextTraffic"] = "false"
191
+ proguardFiles(
192
+ getDefaultProguardFile("proguard-android-optimize.txt"),
193
+ "proguard-rules.pro"
194
+ )
195
+ }
196
+ // <<< cmp:feature firebase
197
+ // >>> cmp:feature !firebase
198
+ getByName("release") {
199
+ isMinifyEnabled = true
200
+ isShrinkResources = true
201
+ manifestPlaceholders["usesCleartextTraffic"] = "false"
202
+ proguardFiles(
203
+ getDefaultProguardFile("proguard-android-optimize.txt"),
204
+ "proguard-rules.pro"
205
+ )
206
+ }
207
+ getByName("debug") {
208
+ manifestPlaceholders["usesCleartextTraffic"] = "true"
209
+ }
210
+ // <<< cmp:feature !firebase
211
+ }
212
+
213
+ compileOptions {
214
+ sourceCompatibility = JavaVersion.VERSION_17
215
+ targetCompatibility = JavaVersion.VERSION_17
216
+ isCoreLibraryDesugaringEnabled = true
217
+ }
218
+ }
219
+
220
+ dependencies {
221
+ // >>> cmp:feature room
222
+ add("kspAndroid", libs.room.compiler)
223
+ // >>> cmp:feature ios
224
+ add("kspIosSimulatorArm64", libs.room.compiler)
225
+ add("kspIosX64", libs.room.compiler)
226
+ add("kspIosArm64", libs.room.compiler)
227
+ // <<< cmp:feature ios
228
+ // >>> cmp:feature dev-client
229
+ add("kspDesktop", libs.room.compiler)
230
+ // <<< cmp:feature dev-client
231
+ // <<< cmp:feature room
232
+ add("coreLibraryDesugaring", libs.android.desugar.jdk)
233
+ }
234
+
235
+ // Pin the generated resources accessor package so `__PACKAGE__.generated.resources.Res`
236
+ // is stable regardless of the Gradle project name. The default would derive from
237
+ // rootProject.name (slugified), which couples imports to the app-name token.
238
+ compose.resources {
239
+ publicResClass = true
240
+ packageOfResClass = "__PACKAGE__.generated.resources"
241
+ generateResClass = ResourcesExtension.ResourceClassGeneration.Always
242
+ }
243
+
244
+ // >>> cmp:feature room
245
+ room {
246
+ schemaDirectory("$projectDir/schemas")
247
+ }
248
+ // <<< cmp:feature room
249
+
250
+ // >>> cmp:feature dev-client
251
+ // Entry point for the desktop dev-client window (and the class Compose Hot Reload launches).
252
+ compose.desktop {
253
+ application {
254
+ mainClass = "__PACKAGE__.MainKt"
255
+ }
256
+ }
257
+ // <<< cmp:feature dev-client
@@ -0,0 +1,29 @@
1
+ {
2
+ "project_info": {
3
+ "project_number": "000000000000",
4
+ "project_id": "REPLACE_ME_PROJECT_ID",
5
+ "storage_bucket": "REPLACE_ME_PROJECT_ID.appspot.com"
6
+ },
7
+ "client": [
8
+ {
9
+ "client_info": {
10
+ "mobilesdk_app_id": "1:000000000000:android:0000000000000000000000",
11
+ "android_client_info": {
12
+ "package_name": "__PACKAGE__"
13
+ }
14
+ },
15
+ "oauth_client": [],
16
+ "api_key": [
17
+ {
18
+ "current_key": "REPLACE_ME_ANDROID_API_KEY"
19
+ }
20
+ ],
21
+ "services": {
22
+ "appinvite_service": {
23
+ "other_platform_oauth_client": []
24
+ }
25
+ }
26
+ }
27
+ ],
28
+ "configuration_version": "1"
29
+ }
@@ -0,0 +1,34 @@
1
+ # Kotlin Serialization
2
+ -keepattributes *Annotation*, InnerClasses
3
+ -dontnote kotlinx.serialization.AnnotationsKt
4
+ -keepclassmembers class kotlinx.serialization.json.** { *** Companion; }
5
+ -keepclasseswithmembers class kotlinx.serialization.json.** { kotlinx.serialization.KSerializer serializer(...); }
6
+ -keep,includedescriptorclasses class __PACKAGE__.**$$serializer { *; }
7
+ -keepclassmembers class __PACKAGE__.** {
8
+ *** Companion;
9
+ }
10
+ -keepclasseswithmembers class __PACKAGE__.** {
11
+ kotlinx.serialization.KSerializer serializer(...);
12
+ }
13
+
14
+ # Koin
15
+ -keep class org.koin.** { *; }
16
+ -keepnames class org.koin.**
17
+
18
+ # Firebase
19
+ -keep class com.google.firebase.** { *; }
20
+ -keep class dev.gitlive.firebase.** { *; }
21
+ -dontwarn com.google.firebase.**
22
+
23
+ # Coroutines
24
+ -keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
25
+ -keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
26
+
27
+ # Coil
28
+ -dontwarn okio.**
29
+
30
+ # Navigation
31
+ -keepnames class androidx.navigation.**
32
+
33
+ # Compose
34
+ -keep class androidx.compose.** { *; }
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+
4
+ <!-- >>> cmp:feature inspector -->
5
+ <!-- The debug inspector server needs socket permission even if a future template fork
6
+ drops INTERNET from the main manifest; loopback-only bind, never on the LAN. -->
7
+ <uses-permission android:name="android.permission.INTERNET" />
8
+ <!-- <<< cmp:feature inspector -->
9
+
10
+ <application
11
+ android:networkSecurityConfig="@xml/debug_network_security_config"
12
+ android:usesCleartextTraffic="true" />
13
+ </manifest>
@@ -0,0 +1,40 @@
1
+ package __PACKAGE__.inspector
2
+
3
+ import android.annotation.SuppressLint
4
+ import androidx.compose.ui.platform.ViewRootForTest
5
+ import java.lang.ref.WeakReference
6
+ import java.util.concurrent.CopyOnWriteArrayList
7
+
8
+ /**
9
+ * Debug-only registry of live Compose roots, discovered via the public
10
+ * [ViewRootForTest.Companion.onViewCreatedCallback] hook — the same mechanism the Compose
11
+ * test framework uses. Installed from [startInspector] in Application.onCreate, BEFORE any
12
+ * Activity exists, so every root (including dialogs/popups, each its own AndroidComposeView)
13
+ * is captured.
14
+ *
15
+ * `@SuppressLint("VisibleForTests")`: ViewRootForTest is public API carrying a lint-severity
16
+ * `@VisibleForTesting` annotation — debug-only usage is precisely its spirit. This class never
17
+ * ships in release (the whole `inspector` package exists only in the androidDebug source set).
18
+ */
19
+ @SuppressLint("VisibleForTests")
20
+ object ComposeRootRegistry {
21
+
22
+ private val roots = CopyOnWriteArrayList<WeakReference<ViewRootForTest>>()
23
+
24
+ /** Install the root-discovery callback. Must run before the first Activity's setContent. */
25
+ fun install() {
26
+ ViewRootForTest.onViewCreatedCallback = { root ->
27
+ roots.removeAll { it.get() == null }
28
+ roots += WeakReference(root)
29
+ }
30
+ }
31
+
32
+ /**
33
+ * The topmost live root: attached to a window, preferring the one with window focus
34
+ * (so an open dialog/popup wins over the screen beneath it).
35
+ */
36
+ fun current(): ViewRootForTest? {
37
+ val live = roots.mapNotNull { it.get() }.filter { it.view.isAttachedToWindow }
38
+ return live.lastOrNull { it.view.hasWindowFocus() } ?: live.lastOrNull()
39
+ }
40
+ }
@@ -0,0 +1,80 @@
1
+ package __PACKAGE__.inspector
2
+
3
+ import androidx.compose.ui.graphics.Color
4
+ import androidx.compose.ui.graphics.toArgb
5
+ import androidx.compose.ui.unit.Dp
6
+ import __PACKAGE__.presentation.theme.__THEME_PREFIX__Colors
7
+ import __PACKAGE__.presentation.theme.__THEME_PREFIX__Tokens
8
+ import kotlinx.serialization.json.Json
9
+ import kotlinx.serialization.json.JsonElement
10
+ import kotlinx.serialization.json.JsonPrimitive
11
+ import kotlinx.serialization.json.buildJsonObject
12
+ import kotlinx.serialization.json.put
13
+
14
+ /**
15
+ * The declared design-system catalog, served on GET /inspect/design-system in the shape the
16
+ * cmp-inspector MCP consumes: `{ "colors": {name: "#RRGGBB"}, "dimens": {name: "16dp"} }`.
17
+ *
18
+ * Hand-registry by design (no kotlin-reflect, no codegen): values are read from the REAL
19
+ * `__THEME_PREFIX__Colors` / `__THEME_PREFIX__Tokens` objects — never string-literal
20
+ * duplicates — so renaming a token breaks this file at compile time. If you ADD a token to
21
+ * the theme, add it here too (`create-cmp doctor` warns when a declared token is missing).
22
+ */
23
+ object InspectorCatalog {
24
+
25
+ private val prettyJson = Json { prettyPrint = true }
26
+
27
+ fun json(): String {
28
+ val doc = buildJsonObject {
29
+ put("colors", buildJsonObject {
30
+ put("Primary", __THEME_PREFIX__Colors.Primary.toHex())
31
+ put("OnPrimary", __THEME_PREFIX__Colors.OnPrimary.toHex())
32
+ put("Accent", __THEME_PREFIX__Colors.Accent.toHex())
33
+ put("OnAccent", __THEME_PREFIX__Colors.OnAccent.toHex())
34
+ put("Secondary", __THEME_PREFIX__Colors.Secondary.toHex())
35
+ put("Error", __THEME_PREFIX__Colors.Error.toHex())
36
+ put("Success", __THEME_PREFIX__Colors.Success.toHex())
37
+ put("Warning", __THEME_PREFIX__Colors.Warning.toHex())
38
+ put("Info", __THEME_PREFIX__Colors.Info.toHex())
39
+ put("Background", __THEME_PREFIX__Colors.Background.toHex())
40
+ put("Surface", __THEME_PREFIX__Colors.Surface.toHex())
41
+ put("SurfaceVariant", __THEME_PREFIX__Colors.SurfaceVariant.toHex())
42
+ put("OnSurface", __THEME_PREFIX__Colors.OnSurface.toHex())
43
+ put("OnSurfaceVariant", __THEME_PREFIX__Colors.OnSurfaceVariant.toHex())
44
+ put("Outline", __THEME_PREFIX__Colors.Outline.toHex())
45
+ put("OutlineVariant", __THEME_PREFIX__Colors.OutlineVariant.toHex())
46
+ put("Divider", __THEME_PREFIX__Colors.Divider.toHex())
47
+ })
48
+ put("dimens", buildJsonObject {
49
+ put("ElevationCard", __THEME_PREFIX__Tokens.ElevationCard.token())
50
+ put("ElevationModal", __THEME_PREFIX__Tokens.ElevationModal.token())
51
+ put("PaddingPage", __THEME_PREFIX__Tokens.PaddingPage.token())
52
+ put("PaddingCard", __THEME_PREFIX__Tokens.PaddingCard.token())
53
+ put("GapCard", __THEME_PREFIX__Tokens.GapCard.token())
54
+ put("BottomNavHeight", __THEME_PREFIX__Tokens.BottomNavHeight.token())
55
+ put("RadiusCard", __THEME_PREFIX__Tokens.RadiusCard.token())
56
+ put("RadiusPill", __THEME_PREFIX__Tokens.RadiusPill.token())
57
+ put("RadiusModal", __THEME_PREFIX__Tokens.RadiusModal.token())
58
+ put("RadiusInput", __THEME_PREFIX__Tokens.RadiusInput.token())
59
+ })
60
+ }
61
+ return prettyJson.encodeToString(JsonElement.serializer(), doc)
62
+ }
63
+
64
+ /** "#RRGGBB" for fully-opaque colours (the catalog convention), "#AARRGGBB" otherwise. */
65
+ private fun Color.toHex(): String {
66
+ val argb = toArgb()
67
+ val alpha = (argb ushr 24) and 0xFF
68
+ return if (alpha == 0xFF) {
69
+ "#%06X".format(argb and 0xFFFFFF)
70
+ } else {
71
+ "#%08X".format(argb)
72
+ }
73
+ }
74
+
75
+ /** "16dp" (integer dp values render without the decimal point). */
76
+ private fun Dp.token(): String {
77
+ val v = value
78
+ return if (v == v.toInt().toFloat()) "${v.toInt()}dp" else "${v}dp"
79
+ }
80
+ }