opencode-skills-collection 3.0.42 → 3.0.43

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 (26) hide show
  1. package/README.md +10 -0
  2. package/bundled-skills/.antigravity-install-manifest.json +3 -1
  3. package/bundled-skills/2slides-ppt-generator/SKILL.md +8 -18
  4. package/bundled-skills/accesslint-diff/SKILL.md +5 -2
  5. package/bundled-skills/android-dev/SKILL.md +524 -0
  6. package/bundled-skills/android-dev/references/flutter.md +269 -0
  7. package/bundled-skills/android-dev/references/hybrid.md +158 -0
  8. package/bundled-skills/android-dev/references/java-android.md +586 -0
  9. package/bundled-skills/android-dev/references/kmm.md +206 -0
  10. package/bundled-skills/android-dev/references/native-android.md +239 -0
  11. package/bundled-skills/android-dev/references/react-native.md +242 -0
  12. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  13. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  14. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  15. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  16. package/bundled-skills/docs/users/bundles.md +1 -1
  17. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  18. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  19. package/bundled-skills/docs/users/getting-started.md +1 -1
  20. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  21. package/bundled-skills/docs/users/usage.md +4 -4
  22. package/bundled-skills/docs/users/visual-guide.md +4 -4
  23. package/bundled-skills/event-staffing-ordering/SKILL.md +2 -17
  24. package/bundled-skills/unship/SKILL.md +138 -0
  25. package/package.json +1 -1
  26. package/skills_index.json +44 -0
@@ -0,0 +1,206 @@
1
+ # Kotlin Multiplatform (KMM) Reference
2
+
3
+ ## Project Structure
4
+
5
+ ```
6
+ project/
7
+ ├── shared/ # Shared KMM module
8
+ │ ├── src/
9
+ │ │ ├── commonMain/kotlin/ # Business logic, domain, data
10
+ │ │ │ ├── domain/
11
+ │ │ │ │ ├── model/
12
+ │ │ │ │ ├── repository/ # Interfaces
13
+ │ │ │ │ └── usecase/
14
+ │ │ │ ├── data/
15
+ │ │ │ │ ├── remote/ # Ktor client + DTOs
16
+ │ │ │ │ ├── local/ # SQLDelight DAOs
17
+ │ │ │ │ └── repository/ # Implementations
18
+ │ │ │ └── di/ # Koin modules
19
+ │ │ ├── androidMain/kotlin/ # Android-specific actual implementations
20
+ │ │ └── iosMain/kotlin/ # iOS-specific actual (if needed)
21
+ │ └── build.gradle.kts
22
+ ├── androidApp/ # Android app module
23
+ │ ├── src/main/java/
24
+ │ │ ├── ui/ # Jetpack Compose screens
25
+ │ │ ├── presentation/ # Android ViewModels
26
+ │ │ └── di/ # Android-specific DI
27
+ │ └── build.gradle.kts
28
+ └── build.gradle.kts
29
+ ```
30
+
31
+ ## Shared Module: Ktor HTTP Client
32
+
33
+ ```kotlin
34
+ // commonMain
35
+ expect fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient
36
+
37
+ // androidMain
38
+ actual fun httpClient(config: HttpClientConfig<*>.() -> Unit): HttpClient =
39
+ HttpClient(OkHttp) {
40
+ config(this)
41
+ engine { addInterceptor(/* logging, auth */) }
42
+ }
43
+
44
+ // Shared usage
45
+ val client = httpClient {
46
+ install(ContentNegotiation) { json() }
47
+ install(HttpTimeout) { requestTimeoutMillis = 10_000 }
48
+ defaultRequest {
49
+ url(BuildKonfig.BASE_URL)
50
+ header(HttpHeaders.ContentType, ContentType.Application.Json)
51
+ }
52
+ }
53
+ ```
54
+
55
+ ## SQLDelight Setup
56
+
57
+ ```sql
58
+ -- ItemEntity.sq
59
+ CREATE TABLE ItemEntity (
60
+ id TEXT NOT NULL PRIMARY KEY,
61
+ title TEXT NOT NULL,
62
+ updatedAt INTEGER NOT NULL DEFAULT 0
63
+ );
64
+
65
+ selectAll:
66
+ SELECT * FROM ItemEntity ORDER BY updatedAt DESC;
67
+
68
+ upsertItem:
69
+ INSERT OR REPLACE INTO ItemEntity (id, title, updatedAt)
70
+ VALUES (?, ?, ?);
71
+ ```
72
+
73
+ ```kotlin
74
+ // commonMain — Database driver expect/actual
75
+ expect class DatabaseDriverFactory {
76
+ fun createDriver(): SqlDriver
77
+ }
78
+
79
+ // androidMain
80
+ actual class DatabaseDriverFactory(private val context: Context) {
81
+ actual fun createDriver(): SqlDriver =
82
+ AndroidSqliteDriver(AppDatabase.Schema, context, "app.db")
83
+ }
84
+ ```
85
+
86
+ ## Shared Repository
87
+
88
+ ```kotlin
89
+ // commonMain
90
+ class ItemRepositoryImpl(
91
+ private val remoteSource: ItemRemoteDataSource,
92
+ private val localSource: ItemLocalDataSource,
93
+ ) : ItemRepository {
94
+
95
+ override fun observeItems(): Flow<List<Item>> =
96
+ localSource.observeAll().map { entities ->
97
+ entities.map { it.toDomain() }
98
+ }
99
+
100
+ override suspend fun refreshItems(): Result<Unit> = runCatching {
101
+ val items = remoteSource.fetchItems()
102
+ localSource.upsertAll(items.map { it.toEntity() })
103
+ }
104
+ }
105
+ ```
106
+
107
+ ## Android ViewModel consuming shared Flow
108
+
109
+ ```kotlin
110
+ @HiltViewModel
111
+ class HomeViewModel @Inject constructor(
112
+ private val observeItems: ObserveItemsUseCase, // from shared module
113
+ private val refreshItems: RefreshItemsUseCase // from shared module
114
+ ) : ViewModel() {
115
+
116
+ val uiState = observeItems()
117
+ .map { HomeUiState.Success(it) as HomeUiState }
118
+ .stateIn(
119
+ scope = viewModelScope,
120
+ started = SharingStarted.WhileSubscribed(5_000),
121
+ initialValue = HomeUiState.Loading
122
+ )
123
+ }
124
+ ```
125
+
126
+ ## Koin DI (Shared + Android)
127
+
128
+ ```kotlin
129
+ // commonMain — shared Koin modules
130
+ val sharedModule = module {
131
+ single { DatabaseDriverFactory(get()) }
132
+ single { AppDatabase(get<DatabaseDriverFactory>().createDriver()) }
133
+ single<ItemRepository> { ItemRepositoryImpl(get(), get()) }
134
+ factory { ObserveItemsUseCase(get()) }
135
+ factory { RefreshItemsUseCase(get()) }
136
+ }
137
+
138
+ // androidApp — Android-specific module
139
+ val androidModule = module {
140
+ single<Context> { androidApplication() }
141
+ viewModel { HomeViewModel(get(), get()) }
142
+ }
143
+
144
+ // Application class
145
+ class MyApp : Application() {
146
+ override fun onCreate() {
147
+ super.onCreate()
148
+ startKoin {
149
+ androidContext(this@MyApp)
150
+ modules(sharedModule, androidModule)
151
+ }
152
+ }
153
+ }
154
+ ```
155
+
156
+ ## Key Gradle Dependencies (shared/build.gradle.kts)
157
+
158
+ ```kotlin
159
+ kotlin {
160
+ androidTarget()
161
+ // Add other targets as needed (jvm, iosArm64, etc.)
162
+
163
+ sourceSets {
164
+ commonMain.dependencies {
165
+ implementation(libs.ktor.client.core)
166
+ implementation(libs.ktor.client.content.negotiation)
167
+ implementation(libs.ktor.serialization.kotlinx.json)
168
+ implementation(libs.sqldelight.runtime)
169
+ implementation(libs.koin.core)
170
+ implementation(libs.kotlinx.coroutines.core)
171
+ implementation(libs.kotlinx.serialization.json)
172
+ }
173
+ androidMain.dependencies {
174
+ implementation(libs.ktor.client.okhttp)
175
+ implementation(libs.sqldelight.android.driver)
176
+ implementation(libs.koin.android)
177
+ }
178
+ }
179
+ }
180
+ ```
181
+
182
+ ## Compose Multiplatform (for shared UI)
183
+
184
+ Use when you want to share UI across Android + Desktop + Web:
185
+
186
+ ```kotlin
187
+ // commonMain — shared composable
188
+ @Composable
189
+ fun HomeScreenContent(
190
+ state: HomeUiState,
191
+ onRetry: () -> Unit
192
+ ) {
193
+ when (state) {
194
+ is HomeUiState.Loading -> CircularProgressIndicator()
195
+ is HomeUiState.Success -> ItemList(state.items)
196
+ is HomeUiState.Error -> ErrorView(state.message, onRetry)
197
+ }
198
+ }
199
+
200
+ // androidApp — wraps with Android ViewModel
201
+ @Composable
202
+ fun HomeScreen(viewModel: HomeViewModel = koinViewModel()) {
203
+ val state by viewModel.uiState.collectAsStateWithLifecycle()
204
+ HomeScreenContent(state, onRetry = viewModel::refresh)
205
+ }
206
+ ```
@@ -0,0 +1,239 @@
1
+ # Native Android Reference (Kotlin + Jetpack Compose)
2
+
3
+ ## Project Structure
4
+
5
+ ```
6
+ app/
7
+ ├── src/
8
+ │ ├── main/
9
+ │ │ ├── AndroidManifest.xml
10
+ │ │ ├── java/com.example.app/
11
+ │ │ │ ├── MyApp.kt # Application class, Hilt entry point
12
+ │ │ │ ├── MainActivity.kt # Single activity, NavHost host
13
+ │ │ │ ├── ui/
14
+ │ │ │ │ ├── theme/ # MaterialTheme, Color, Type, Shape
15
+ │ │ │ │ ├── components/ # Shared design system composables
16
+ │ │ │ │ └── feature/
17
+ │ │ │ │ ├── home/
18
+ │ │ │ │ │ ├── HomeScreen.kt
19
+ │ │ │ │ │ ├── HomeViewModel.kt
20
+ │ │ │ │ │ └── HomeUiState.kt
21
+ │ │ │ ├── domain/
22
+ │ │ │ │ ├── model/ # Domain models (pure Kotlin, no Android deps)
23
+ │ │ │ │ ├── repository/ # Interfaces only
24
+ │ │ │ │ └── usecase/ # One class per use case
25
+ │ │ │ ├── data/
26
+ │ │ │ │ ├── remote/ # Retrofit services, DTOs, mappers
27
+ │ │ │ │ ├── local/ # Room DB, DAOs, entities
28
+ │ │ │ │ └── repository/ # Repository implementations
29
+ │ │ │ └── di/ # Hilt modules
30
+ │ └── test/ # Unit tests
31
+ │ └── androidTest/ # Instrumented tests
32
+ ├── build.gradle.kts
33
+ └── proguard-rules.pro
34
+ ```
35
+
36
+ ## ViewModel Pattern
37
+
38
+ ```kotlin
39
+ // UiState — sealed class for exhaustive when()
40
+ sealed class HomeUiState {
41
+ object Loading : HomeUiState()
42
+ data class Success(val items: List<Item>) : HomeUiState()
43
+ data class Error(val message: String) : HomeUiState()
44
+ }
45
+
46
+ // UiEvent — one-shot events (navigation, snackbars)
47
+ sealed class HomeUiEvent {
48
+ data class NavigateTo(val route: String) : HomeUiEvent()
49
+ data class ShowSnackbar(val message: String) : HomeUiEvent()
50
+ }
51
+
52
+ @HiltViewModel
53
+ class HomeViewModel @Inject constructor(
54
+ private val getItemsUseCase: GetItemsUseCase
55
+ ) : ViewModel() {
56
+
57
+ private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
58
+ val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()
59
+
60
+ private val _uiEvent = Channel<HomeUiEvent>()
61
+ val uiEvent = _uiEvent.receiveAsFlow()
62
+
63
+ init { loadItems() }
64
+
65
+ fun loadItems() {
66
+ viewModelScope.launch {
67
+ _uiState.value = HomeUiState.Loading
68
+ getItemsUseCase()
69
+ .onSuccess { _uiState.value = HomeUiState.Success(it) }
70
+ .onFailure { _uiState.value = HomeUiState.Error(it.message ?: "Unknown error") }
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ ## Repository Pattern
77
+
78
+ ```kotlin
79
+ // Interface in domain layer
80
+ interface ItemRepository {
81
+ fun observeItems(): Flow<List<Item>>
82
+ suspend fun refreshItems(): Result<Unit>
83
+ suspend fun getItemById(id: String): Result<Item>
84
+ }
85
+
86
+ // Implementation in data layer
87
+ class ItemRepositoryImpl @Inject constructor(
88
+ private val remoteSource: ItemRemoteDataSource,
89
+ private val localSource: ItemLocalDataSource,
90
+ private val mapper: ItemMapper
91
+ ) : ItemRepository {
92
+
93
+ override fun observeItems(): Flow<List<Item>> =
94
+ localSource.observeAll().map { mapper.toDomain(it) }
95
+
96
+ override suspend fun refreshItems(): Result<Unit> = runCatching {
97
+ val dto = remoteSource.fetchItems()
98
+ localSource.insertAll(mapper.toEntity(dto))
99
+ }
100
+
101
+ override suspend fun getItemById(id: String): Result<Item> = runCatching {
102
+ // Example implementation fetching from local cache
103
+ val entity = localSource.getById(id) ?: throw Exception("Item not found")
104
+ mapper.toDomain(entity)
105
+ }
106
+ }
107
+ ```
108
+
109
+ ## Compose Screen
110
+
111
+ ```kotlin
112
+ @Composable
113
+ fun HomeScreen(
114
+ viewModel: HomeViewModel = hiltViewModel(),
115
+ onNavigate: (String) -> Unit
116
+ ) {
117
+ val uiState by viewModel.uiState.collectAsStateWithLifecycle()
118
+ val snackbarHostState = remember { SnackbarHostState() }
119
+
120
+ // One-shot event handling
121
+ LaunchedEffect(Unit) {
122
+ viewModel.uiEvent.collect { event ->
123
+ when (event) {
124
+ is HomeUiEvent.NavigateTo -> onNavigate(event.route)
125
+ is HomeUiEvent.ShowSnackbar -> snackbarHostState.showSnackbar(event.message)
126
+ }
127
+ }
128
+ }
129
+
130
+ Scaffold(snackbarHost = { SnackbarHost(snackbarHostState) }) { padding ->
131
+ when (val state = uiState) {
132
+ is HomeUiState.Loading -> LoadingContent()
133
+ is HomeUiState.Success -> HomeContent(state.items, Modifier.padding(padding))
134
+ is HomeUiState.Error -> ErrorContent(state.message, onRetry = viewModel::loadItems)
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ ## Room Database
141
+
142
+ ```kotlin
143
+ @Entity(tableName = "items")
144
+ data class ItemEntity(
145
+ @PrimaryKey val id: String,
146
+ val title: String,
147
+ val updatedAt: Long = System.currentTimeMillis()
148
+ )
149
+
150
+ @Dao
151
+ interface ItemDao {
152
+ @Query("SELECT * FROM items ORDER BY updatedAt DESC")
153
+ fun observeAll(): Flow<List<ItemEntity>>
154
+
155
+ @Upsert
156
+ suspend fun upsertAll(items: List<ItemEntity>)
157
+
158
+ @Query("DELETE FROM items")
159
+ suspend fun deleteAll()
160
+ }
161
+
162
+ @Database(entities = [ItemEntity::class], version = 1, exportSchema = true)
163
+ abstract class AppDatabase : RoomDatabase() {
164
+ abstract fun itemDao(): ItemDao
165
+ }
166
+ ```
167
+
168
+ ## Hilt DI Setup
169
+
170
+ ```kotlin
171
+ @Module
172
+ @InstallIn(SingletonComponent::class)
173
+ object NetworkModule {
174
+ @Provides @Singleton
175
+ fun provideRetrofit(): Retrofit = Retrofit.Builder()
176
+ .baseUrl(BuildConfig.API_BASE_URL)
177
+ .addConverterFactory(GsonConverterFactory.create())
178
+ .client(buildOkHttpClient())
179
+ .build()
180
+ }
181
+
182
+ @Module
183
+ @InstallIn(SingletonComponent::class)
184
+ abstract class RepositoryModule {
185
+ @Binds @Singleton
186
+ abstract fun bindItemRepository(impl: ItemRepositoryImpl): ItemRepository
187
+ }
188
+ ```
189
+
190
+ ## Key Dependencies (libs.versions.toml)
191
+
192
+ ```toml
193
+ [versions]
194
+ kotlin = "2.0.0"
195
+ compose-bom = "2024.06.00"
196
+ hilt = "2.51"
197
+ room = "2.6.1"
198
+ retrofit = "2.11.0"
199
+ coroutines = "1.8.1"
200
+ lifecycle = "2.8.2"
201
+
202
+ [libraries]
203
+ compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
204
+ compose-ui = { group = "androidx.compose.ui", name = "ui" }
205
+ compose-material3 = { group = "androidx.compose.material3", name = "material3" }
206
+ hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
207
+ hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
208
+ room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
209
+ room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
210
+ room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
211
+ retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
212
+ ```
213
+
214
+ ## Testing Setup
215
+
216
+ ```kotlin
217
+ // ViewModel unit test
218
+ @OptIn(ExperimentalCoroutinesApi::class)
219
+ class HomeViewModelTest {
220
+ @get:Rule val mainDispatcherRule = MainDispatcherRule()
221
+
222
+ private val getItemsUseCase = mockk<GetItemsUseCase>()
223
+ private lateinit var viewModel: HomeViewModel
224
+
225
+ @BeforeEach
226
+ fun setup() { viewModel = HomeViewModel(getItemsUseCase) }
227
+
228
+ @Test
229
+ fun `loadItems emits Success when use case succeeds`() = runTest {
230
+ val items = listOf(Item("1", "Test"))
231
+ coEvery { getItemsUseCase() } returns Result.success(items)
232
+
233
+ viewModel.uiState.test {
234
+ skipItems(1) // Loading
235
+ assertThat(awaitItem()).isEqualTo(HomeUiState.Success(items))
236
+ }
237
+ }
238
+ }
239
+ ```
@@ -0,0 +1,242 @@
1
+ # React Native Reference (TypeScript)
2
+
3
+ ## Project Structure
4
+
5
+ ```
6
+ src/
7
+ ├── app/
8
+ │ ├── App.tsx # Root component, providers
9
+ │ ├── navigation/ # React Navigation stacks + types
10
+ │ └── store/ # RTK store setup
11
+ ├── features/
12
+ │ └── home/
13
+ │ ├── api/ # RTK Query endpoints
14
+ │ ├── components/ # Screen-specific components
15
+ │ ├── hooks/ # Feature-level custom hooks
16
+ │ ├── screens/ # Screen components
17
+ │ ├── store/ # Zustand slice or RTK slice
18
+ │ └── types.ts # Feature types
19
+ ├── shared/
20
+ │ ├── components/ # Design system components
21
+ │ ├── hooks/ # Shared hooks
22
+ │ ├── theme/ # Colors, typography, spacing constants
23
+ │ └── utils/ # Utilities
24
+ └── services/
25
+ ├── api/ # Axios/fetch client + interceptors
26
+ └── storage/ # MMKV wrapper
27
+ ```
28
+
29
+ ## Navigation Setup (React Navigation v7)
30
+
31
+ ```typescript
32
+ export type RootStackParamList = {
33
+ Auth: undefined;
34
+ Home: undefined;
35
+ Detail: { id: string };
36
+ Settings: undefined;
37
+ };
38
+
39
+ export type RootStackScreenProps<T extends keyof RootStackParamList> =
40
+ NativeStackScreenProps<RootStackParamList, T>;
41
+
42
+ const Stack = createNativeStackNavigator<RootStackParamList>();
43
+
44
+ export const RootNavigator = () => {
45
+ const isLoggedIn = useAuthStore((s) => s.isLoggedIn);
46
+
47
+ return (
48
+ <Stack.Navigator screenOptions={{ headerShown: false }}>
49
+ {isLoggedIn ? (
50
+ <>
51
+ <Stack.Screen name="Home" component={HomeScreen} />
52
+ <Stack.Screen name="Detail" component={DetailScreen} />
53
+ </>
54
+ ) : (
55
+ <Stack.Screen name="Auth" component={AuthScreen} />
56
+ )}
57
+ </Stack.Navigator>
58
+ );
59
+ };
60
+ ```
61
+
62
+ ## State Management (Zustand + React Query)
63
+
64
+ ```typescript
65
+ // Client state — Zustand
66
+ interface AuthState {
67
+ token: string | null;
68
+ isLoggedIn: boolean;
69
+ setToken: (token: string) => void;
70
+ logout: () => void;
71
+ }
72
+
73
+ export const useAuthStore = create<AuthState>()(
74
+ persist(
75
+ (set) => ({
76
+ token: null,
77
+ isLoggedIn: false,
78
+ setToken: (token) => set({ token, isLoggedIn: true }),
79
+ logout: () => set({ token: null, isLoggedIn: false }),
80
+ }),
81
+ { name: 'auth-storage', storage: createJSONStorage(() => mmkvStorage) }
82
+ )
83
+ );
84
+
85
+ // Server state — React Query
86
+ export const useItems = () =>
87
+ useQuery({
88
+ queryKey: ['items'],
89
+ queryFn: itemsApi.getAll,
90
+ staleTime: 5 * 60 * 1000, // 5 minutes
91
+ });
92
+
93
+ export const useRefreshItems = () =>
94
+ useMutation({
95
+ mutationFn: itemsApi.refresh,
96
+ onSuccess: () => queryClient.invalidateQueries({ queryKey: ['items'] }),
97
+ });
98
+ ```
99
+
100
+ ## Screen Pattern
101
+
102
+ ```typescript
103
+ type HomeScreenProps = RootStackScreenProps<'Home'>;
104
+
105
+ export const HomeScreen: FC<HomeScreenProps> = ({ navigation }) => {
106
+ const { data: items, isLoading, isError, refetch } = useItems();
107
+
108
+ if (isLoading) return <LoadingView />;
109
+ if (isError) return <ErrorView onRetry={refetch} />;
110
+
111
+ return (
112
+ <SafeAreaView style={styles.container}>
113
+ <FlatList
114
+ data={items}
115
+ keyExtractor={(item) => item.id}
116
+ renderItem={({ item }) => (
117
+ <ItemCard
118
+ item={item}
119
+ onPress={() => navigation.navigate('Detail', { id: item.id })}
120
+ />
121
+ )}
122
+ ListEmptyComponent={<EmptyView />}
123
+ refreshControl={
124
+ <RefreshControl refreshing={isLoading} onRefresh={refetch} />
125
+ }
126
+ />
127
+ </SafeAreaView>
128
+ );
129
+ };
130
+ ```
131
+
132
+ ## API Client (Axios with interceptors)
133
+
134
+ ```typescript
135
+ const apiClient = axios.create({
136
+ baseURL: Config.API_BASE_URL,
137
+ timeout: 10_000,
138
+ headers: { 'Content-Type': 'application/json' },
139
+ });
140
+
141
+ // Auth token injection
142
+ apiClient.interceptors.request.use((config) => {
143
+ const token = useAuthStore.getState().token;
144
+ if (token) config.headers.Authorization = `Bearer ${token}`;
145
+ return config;
146
+ });
147
+
148
+ // Token refresh on 401
149
+ apiClient.interceptors.response.use(
150
+ (res) => res,
151
+ async (error: AxiosError) => {
152
+ if (error.response?.status === 401) {
153
+ const newToken = await refreshToken();
154
+ if (newToken) {
155
+ useAuthStore.getState().setToken(newToken);
156
+ return apiClient(error.config!);
157
+ }
158
+ useAuthStore.getState().logout();
159
+ }
160
+ return Promise.reject(error);
161
+ }
162
+ );
163
+ ```
164
+
165
+ ## API Response Validation (Zod)
166
+
167
+ ```typescript
168
+ const ItemSchema = z.object({
169
+ id: z.string(),
170
+ title: z.string(),
171
+ description: z.string().optional(),
172
+ createdAt: z.string().datetime(),
173
+ });
174
+
175
+ const ItemsResponseSchema = z.array(ItemSchema);
176
+ type Item = z.infer<typeof ItemSchema>;
177
+
178
+ const getItems = async (): Promise<Item[]> => {
179
+ const { data } = await apiClient.get('/items');
180
+ return ItemsResponseSchema.parse(data); // throws ZodError on invalid shape
181
+ };
182
+ ```
183
+
184
+ ## Key Dependencies
185
+
186
+ ```json
187
+ {
188
+ "dependencies": {
189
+ "react-native": "0.74.x",
190
+ "@react-navigation/native": "^7.0.0",
191
+ "@react-navigation/native-stack": "^7.0.0",
192
+ "@tanstack/react-query": "^5.45.0",
193
+ "zustand": "^4.5.4",
194
+ "axios": "^1.7.2",
195
+ "zod": "^3.23.8",
196
+ "react-native-mmkv": "^2.12.2",
197
+ "react-native-safe-area-context": "^4.10.1",
198
+ "react-native-screens": "^3.32.0"
199
+ },
200
+ "devDependencies": {
201
+ "typescript": "^5.4.5",
202
+ "@testing-library/react-native": "^12.5.1",
203
+ "msw": "^2.3.1",
204
+ "jest": "^29.7.0"
205
+ }
206
+ }
207
+ ```
208
+
209
+ ## New Architecture (Bridgeless) Notes
210
+ - Enable New Architecture in `android/gradle.properties`: `newArchEnabled=true`
211
+ - Use TurboModules for native modules; avoid legacy NativeModules API
212
+ - Use Fabric for custom native views
213
+ - Test with Hermes JS engine always enabled
214
+
215
+ ## Performance Tips
216
+ - Use `useCallback` + `memo` on `renderItem` / list item components
217
+ - `FlatList` `windowSize`, `initialNumToRender`, `maxToRenderPerBatch` tuned
218
+ - Avoid anonymous inline functions in JSX
219
+ - `InteractionManager.runAfterInteractions` for heavy post-navigation work
220
+ - `react-native-reanimated` for 60fps animations (runs on UI thread)
221
+
222
+ ## Testing
223
+
224
+ ```typescript
225
+ describe('HomeScreen', () => {
226
+ it('shows items when query succeeds', async () => {
227
+ server.use(
228
+ http.get(`${API_URL}/items`, () =>
229
+ HttpResponse.json([{ id: '1', title: 'Test Item' }])
230
+ )
231
+ );
232
+
233
+ const { getByText } = render(
234
+ <QueryClientProvider client={testQueryClient}>
235
+ <HomeScreen navigation={mockNavigation} route={mockRoute} />
236
+ </QueryClientProvider>
237
+ );
238
+
239
+ expect(await findByText('Test Item')).toBeTruthy();
240
+ });
241
+ });
242
+ ```
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  title: Jetski/Cortex + Gemini Integration Guide
3
- description: "Use antigravity-awesome-skills with Jetski/Cortex without hitting context-window overflow with 1,525+ skills."
3
+ description: "Use antigravity-awesome-skills with Jetski/Cortex without hitting context-window overflow with 1,527+ skills."
4
4
  ---
5
5
 
6
- # Jetski/Cortex + Gemini: safe integration with 1,525+ skills
6
+ # Jetski/Cortex + Gemini: safe integration with 1,527+ skills
7
7
 
8
8
  This guide shows how to integrate the `antigravity-awesome-skills` repository with an agent based on **Jetski/Cortex + Gemini** (or similar frameworks) **without exceeding the model context window**.
9
9
 
@@ -23,7 +23,7 @@ Never do:
23
23
  - concatenate all `SKILL.md` content into a single system prompt;
24
24
  - re-inject the entire library for **every** request.
25
25
 
26
- With 1,525+ skills, this approach fills the context window before user messages are even added, causing truncation.
26
+ With 1,527+ skills, this approach fills the context window before user messages are even added, causing truncation.
27
27
 
28
28
  ---
29
29