@buivietphi/skill-mobile-mt 1.4.2 → 1.4.3

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.

Potentially problematic release.


This version of @buivietphi/skill-mobile-mt might be problematic. Click here for more details.

package/AGENTS.md CHANGED
@@ -40,7 +40,7 @@ skill-mobile-mt/
40
40
  │ └── ios-native.md ← Swift + UIKit/SwiftUI patterns (1,452 tokens)
41
41
 
42
42
  ├── android/
43
- │ └── android-native.md ← Kotlin + Compose patterns (2,100 tokens)
43
+ │ └── android-native.md ← Kotlin + Compose + Java legacy patterns (4,400 tokens)
44
44
 
45
45
  └── shared/
46
46
 
@@ -71,8 +71,8 @@ skill-mobile-mt/
71
71
  ```
72
72
 
73
73
  **Token totals:**
74
- - Smart load (1 platform + core shared): **~38,600 tokens** (30.2% of 128K)
75
- - Full load (all files): **~74,700 tokens** (58.4% of 128K)
74
+ - Smart load (1 platform + core shared): **~40,900 tokens** (31.9% of 128K)
75
+ - Full load (all files): **~77,000 tokens** (60.2% of 128K)
76
76
 
77
77
  ---
78
78
 
@@ -122,7 +122,7 @@ The agent reads the task, then decides which extra file to load:
122
122
 
123
123
  **No automatic trigger.** Full load happens when the AI reads every file without being selective — either because it's over-eager, or because the user explicitly asks for it.
124
124
 
125
- **Total:** ~70,000 tokens (54.7% of 128K, 35% of 200K)
125
+ **Total:** ~72,300 tokens (56.5% of 128K, 36% of 200K)
126
126
 
127
127
  **How it actually works:**
128
128
  - `@skill-mobile-mt` only injects SKILL.md into context
@@ -214,9 +214,9 @@ skill:
214
214
  java: ".java files in app/src/"
215
215
 
216
216
  context_budget:
217
- max_tokens: 74700
218
- smart_load_tokens: 38600
219
- savings: "~48%"
217
+ max_tokens: 77000
218
+ smart_load_tokens: 40900
219
+ savings: "~47%"
220
220
  ```
221
221
 
222
222
  ---
@@ -463,10 +463,10 @@ npx @buivietphi/skill-mobile-mt --init all # → all files
463
463
  {
464
464
  "id": "skill-mobile-mt",
465
465
  "name": "skill-mobile-mt",
466
- "version": "1.4.0",
466
+ "version": "1.4.3",
467
467
  "author": "buivietphi",
468
468
  "category": "engineering",
469
- "description": "Master Senior Mobile Engineer. Pre-built patterns from 18 production apps + project adaptation. Auto-detects language and framework. React Native, Flutter, iOS, Android.",
469
+ "description": "Master Senior Mobile Engineer. Pre-built patterns from 30+ production repos + project adaptation. Auto-detects language and framework. React Native, Flutter, iOS, Android.",
470
470
  "risk": "low",
471
471
  "source": "buivietphi (MIT)",
472
472
  "platforms": ["react-native", "flutter", "ios", "android"],
package/README.md CHANGED
@@ -72,6 +72,73 @@ Reads your current project first, then follows **your** conventions:
72
72
  - Clones the most similar existing feature when scaffolding new ones
73
73
  - Never suggests migrations or imposes different architecture
74
74
 
75
+ ## Humanizer — Mobile Copy
76
+
77
+ Installed automatically alongside the main skill. Removes AI writing patterns from mobile app text.
78
+
79
+ ```
80
+ @humanizer-mobile
81
+ ```
82
+
83
+ Use for: app store descriptions, release notes, error messages, onboarding, push notifications, permission prompts, paywall copy.
84
+
85
+ **App Store Description**
86
+ ```
87
+ ❌ "TaskFlow is a powerful, comprehensive task management application that
88
+ seamlessly integrates with your existing workflow."
89
+
90
+ ✅ "TaskFlow keeps your team's work in one place. Add tasks, assign them,
91
+ set deadlines — everything syncs in real time. Works with Slack and Notion."
92
+ ```
93
+
94
+ **Release Notes**
95
+ ```
96
+ ❌ "Version 2.1.0 introduces significant enhancements to the overall user
97
+ experience including robust improvements to performance and reliability."
98
+
99
+ ✅ "2.1.0
100
+ - Faster load times on older Android devices (was 4s, now 1.2s)
101
+ - Fixed crash when opening notifications while offline
102
+ - Dark mode now remembers your setting between sessions"
103
+ ```
104
+
105
+ **Error Messages**
106
+ ```
107
+ ❌ "We apologize for the inconvenience. An unexpected error has occurred."
108
+
109
+ ✅ "Couldn't save — no internet connection.
110
+ [Try again] [Save for later]"
111
+ ```
112
+
113
+ **Push Notifications**
114
+ ```
115
+ ❌ "You have received a new message from a team member."
116
+ ✅ "Alex commented on "Landing page redesign""
117
+ ```
118
+
119
+ **Paywall**
120
+ ```
121
+ ❌ "Unlock the full potential of our comprehensive premium features."
122
+
123
+ ✅ "Go Pro
124
+ • Unlimited projects (free plan: 3)
125
+ • Team sharing
126
+ [Start 7-day free trial]"
127
+ ```
128
+
129
+ Covers 24 AI patterns across: content inflation, chatbot artifacts, style issues, mobile-specific copy (App Store limits, permission prompts, rating requests, subscription CTAs).
130
+
131
+ ### Works with all agents
132
+
133
+ | Agent | Invocation |
134
+ |-------|-----------|
135
+ | Claude Code | `@humanizer-mobile` |
136
+ | Gemini CLI | `@humanizer-mobile` |
137
+ | Codex / Kimi / Antigravity | `@humanizer-mobile` |
138
+ | Cline / Roo Code / Cursor / Windsurf / Copilot | Paste the text and say "humanize this app copy" |
139
+
140
+ ---
141
+
75
142
  ## Quick Start Examples
76
143
 
77
144
  ### Step 1: Install the skill
@@ -101,6 +168,15 @@ You'll see an interactive checkbox — use arrow keys to navigate, space to sele
101
168
  ◯ Antigravity [not found]
102
169
  ```
103
170
 
171
+ Install output:
172
+
173
+ ```
174
+ ✓ skill-mobile-mt/ → Claude Code (~/.claude/skills/skill-mobile-mt)
175
+ ✓ humanizer-mobile/ → Claude Code (~/.claude/skills/humanizer-mobile)
176
+ ```
177
+
178
+ Both are installed automatically. Use `@humanizer-mobile` for app store copy, release notes, and UX text.
179
+
104
180
  ### Step 2: Generate project rules
105
181
 
106
182
  ```bash
@@ -231,9 +307,9 @@ iOS only?
231
307
  |----------|-------:|----------:|----------:|
232
308
  | SKILL.md only | ~13,200 | 10.3% | 6.6% |
233
309
  | + 1 platform + core shared/ | ~38,600 | 30.2% | 19.3% |
234
- | Cross-platform (RN/Flutter + iOS + Android) | ~53,000 | 41.4% | 26.5% |
235
- | All files loaded | ~74,700 | 58.4% | 37.4% |
236
- | **Smart load (recommended)** | **~38,600** | **30.2%** | **19.3%** |
310
+ | Cross-platform (RN/Flutter + iOS + Android) | ~55,300 | 43.2% | 27.7% |
311
+ | All files loaded | ~77,000 | 60.2% | 38.5% |
312
+ | **Smart load (recommended)** | **~40,900** | **31.9%** | **20.5%** |
237
313
 
238
314
  ### Per-file token breakdown
239
315
 
@@ -244,7 +320,7 @@ iOS only?
244
320
  | `react-native/react-native.md` | 5,108 |
245
321
  | `flutter/flutter.md` | 2,100 |
246
322
  | `ios/ios-native.md` | 1,452 |
247
- | `android/android-native.md` | 2,100 |
323
+ | `android/android-native.md` | 4,400 |
248
324
  | `shared/code-review.md` | 865 |
249
325
  | `shared/bug-detection.md` | 499 |
250
326
  | `shared/prompt-engineering.md` | 3,927 |
@@ -263,7 +339,7 @@ iOS only?
263
339
  | `shared/ci-cd.md` | 2,500 |
264
340
  | `shared/claude-md-template.md` | ~500 |
265
341
  | `shared/agent-rules-template.md` | ~2,500 |
266
- | **Total** | **~53,500** |
342
+ | **Total** | **~55,800** |
267
343
 
268
344
  ## Installed Structure
269
345
 
@@ -279,7 +355,7 @@ iOS only?
279
355
  ├── ios/
280
356
  │ └── ios-native.md iOS Swift patterns
281
357
  ├── android/
282
- │ └── android-native.md Android Kotlin patterns
358
+ │ └── android-native.md Android Kotlin + Java patterns
283
359
  └── shared/
284
360
  ├── code-review.md Senior review checklist
285
361
  ├── bug-detection.md Auto bug scanner
@@ -427,66 +503,6 @@ your-project/
427
503
  | **Kiro** | Reads `.kiro/steering/` from project root | `npx skill-mobile-mt --init kiro` |
428
504
  | **Antigravity** | Reads from `~/.agents/skills/` | `npx skill-mobile-mt --antigravity` |
429
505
 
430
- ## Humanizer — Mobile Copy
431
-
432
- Installed automatically alongside the main skill. Removes AI writing patterns from mobile app text.
433
-
434
- ```
435
- @humanizer-mobile
436
- ```
437
-
438
- Use for: app store descriptions, release notes, error messages, onboarding, push notifications, permission prompts, paywall copy.
439
-
440
- ### Examples
441
-
442
- **App Store Description**
443
- ```
444
- ❌ "TaskFlow is a powerful, comprehensive task management application that
445
- seamlessly integrates with your existing workflow."
446
-
447
- ✅ "TaskFlow keeps your team's work in one place. Add tasks, assign them,
448
- set deadlines — everything syncs in real time. Works with Slack and Notion."
449
- ```
450
-
451
- **Release Notes**
452
- ```
453
- ❌ "Version 2.1.0 introduces significant enhancements to the overall user
454
- experience including robust improvements to performance and reliability."
455
-
456
- ✅ "2.1.0
457
- - Faster load times on older Android devices (was 4s, now 1.2s)
458
- - Fixed crash when opening notifications while offline
459
- - Dark mode now remembers your setting between sessions"
460
- ```
461
-
462
- **Error Messages**
463
- ```
464
- ❌ "We apologize for the inconvenience. An unexpected error has occurred."
465
-
466
- ✅ "Couldn't save — no internet connection.
467
- [Try again] [Save for later]"
468
- ```
469
-
470
- **Push Notifications**
471
- ```
472
- ❌ "You have received a new message from a team member."
473
- ✅ "Alex commented on "Landing page redesign""
474
- ```
475
-
476
- **Paywall**
477
- ```
478
- ❌ "Unlock the full potential of our comprehensive premium features."
479
-
480
- ✅ "Go Pro
481
- • Unlimited projects (free plan: 3)
482
- • Team sharing
483
- [Start 7-day free trial]"
484
- ```
485
-
486
- Covers 24 AI patterns across: content inflation, chatbot artifacts, style issues, mobile-specific copy (App Store limits, permission prompts, rating requests, subscription CTAs).
487
-
488
- ---
489
-
490
506
  ## License
491
507
 
492
508
  MIT — by [buivietphi](https://github.com/buivietphi)
package/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: skill-mobile-mt
3
3
  description: "Master Senior Mobile Engineer. Patterns from 30+ production repos (200k+ GitHub stars: Ignite, Expensify, Mattermost, Immich, AppFlowy, Now in Android, TCA). Use when: building mobile features, fixing mobile bugs, reviewing mobile code, mobile architecture, React Native, Flutter, iOS Swift, Android Kotlin, mobile performance, mobile security audit, mobile code review, app release. Two modes: (1) default = pre-built production patterns, (2) 'project' = reads current project and adapts."
4
- version: "1.4.2"
4
+ version: "1.4.3"
5
5
  author: buivietphi
6
6
  priority: high
7
7
  user-invocable: true
@@ -254,5 +254,227 @@ dependencies {
254
254
 
255
255
  ---
256
256
 
257
+ ## Java Interop (Legacy Projects)
258
+
259
+ > For projects still using Java. New code should use Kotlin.
260
+
261
+ ### Activity + XML Layout (Java)
262
+
263
+ ```java
264
+ // MainActivity.java
265
+ @AndroidEntryPoint
266
+ public class MainActivity extends AppCompatActivity {
267
+
268
+ private MainViewModel viewModel;
269
+ private ActivityMainBinding binding;
270
+
271
+ @Override
272
+ protected void onCreate(Bundle savedInstanceState) {
273
+ super.onCreate(savedInstanceState);
274
+ binding = ActivityMainBinding.inflate(getLayoutInflater());
275
+ setContentView(binding.getRoot());
276
+
277
+ viewModel = new ViewModelProvider(this).get(MainViewModel.class);
278
+
279
+ // Observe LiveData (Java equivalent of collectAsStateWithLifecycle)
280
+ viewModel.getUiState().observe(this, state -> {
281
+ if (state instanceof UiState.Loading) {
282
+ binding.progressBar.setVisibility(View.VISIBLE);
283
+ binding.recyclerView.setVisibility(View.GONE);
284
+ } else if (state instanceof UiState.Error) {
285
+ binding.progressBar.setVisibility(View.GONE);
286
+ Toast.makeText(this, ((UiState.Error) state).getMessage(), Toast.LENGTH_SHORT).show();
287
+ } else if (state instanceof UiState.Success) {
288
+ binding.progressBar.setVisibility(View.GONE);
289
+ binding.recyclerView.setVisibility(View.VISIBLE);
290
+ adapter.submitList(((UiState.Success<List<Product>>) state).getData());
291
+ }
292
+ });
293
+
294
+ binding.retryButton.setOnClickListener(v -> viewModel.load());
295
+ }
296
+ }
297
+ ```
298
+
299
+ ### ViewModel + LiveData (Java)
300
+
301
+ ```java
302
+ // ProductListViewModel.java
303
+ @HiltViewModel
304
+ public class ProductListViewModel extends ViewModel {
305
+
306
+ private final MutableLiveData<UiState<List<Product>>> _uiState =
307
+ new MutableLiveData<>(new UiState.Loading<>());
308
+ private final LiveData<UiState<List<Product>>> uiState = _uiState;
309
+
310
+ private final GetProductsUseCase getProducts;
311
+
312
+ @Inject
313
+ public ProductListViewModel(GetProductsUseCase getProducts) {
314
+ this.getProducts = getProducts;
315
+ load();
316
+ }
317
+
318
+ public LiveData<UiState<List<Product>>> getUiState() { return uiState; }
319
+
320
+ public void load() {
321
+ _uiState.setValue(new UiState.Loading<>());
322
+ // Use RxJava or ExecutorService for async in Java
323
+ ExecutorService executor = Executors.newSingleThreadExecutor();
324
+ executor.execute(() -> {
325
+ try {
326
+ List<Product> items = getProducts.executeSync(); // blocking call
327
+ new Handler(Looper.getMainLooper()).post(() -> {
328
+ if (items.isEmpty()) _uiState.setValue(new UiState.Empty<>());
329
+ else _uiState.setValue(new UiState.Success<>(items));
330
+ });
331
+ } catch (Exception e) {
332
+ new Handler(Looper.getMainLooper()).post(() ->
333
+ _uiState.setValue(new UiState.Error<>(e.getMessage()))
334
+ );
335
+ } finally {
336
+ executor.shutdown();
337
+ }
338
+ });
339
+ }
340
+ }
341
+ ```
342
+
343
+ ### Retrofit + Callback (Java)
344
+
345
+ ```java
346
+ // ProductApi.java
347
+ public interface ProductApi {
348
+ @GET("products")
349
+ Call<ApiResponse<List<ProductDto>>> getProducts();
350
+ }
351
+
352
+ // ProductRepositoryImpl.java
353
+ public class ProductRepositoryImpl implements ProductRepository {
354
+ private final ProductApi api;
355
+ private final ProductDao dao;
356
+
357
+ @Inject
358
+ public ProductRepositoryImpl(ProductApi api, ProductDao dao) {
359
+ this.api = api;
360
+ this.dao = dao;
361
+ }
362
+
363
+ @Override
364
+ public void getProducts(Callback<List<Product>> callback) {
365
+ api.getProducts().enqueue(new retrofit2.Callback<ApiResponse<List<ProductDto>>>() {
366
+ @Override
367
+ public void onResponse(Call<ApiResponse<List<ProductDto>>> call,
368
+ Response<ApiResponse<List<ProductDto>>> response) {
369
+ if (response.isSuccessful() && response.body() != null) {
370
+ List<Product> items = mapToDomain(response.body().getData());
371
+ callback.onSuccess(items);
372
+ } else {
373
+ callback.onError("Server error: " + response.code());
374
+ }
375
+ }
376
+
377
+ @Override
378
+ public void onFailure(Call<ApiResponse<List<ProductDto>>> call, Throwable t) {
379
+ callback.onError(t.getMessage());
380
+ }
381
+ });
382
+ }
383
+ }
384
+ ```
385
+
386
+ ### Room DAO (Java)
387
+
388
+ ```java
389
+ // ProductDao.java
390
+ @Dao
391
+ public interface ProductDao {
392
+ @Query("SELECT * FROM products")
393
+ LiveData<List<ProductEntity>> getAll(); // LiveData for Java observers
394
+
395
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
396
+ void insertAll(List<ProductEntity> items);
397
+
398
+ @Query("DELETE FROM products")
399
+ void deleteAll();
400
+ }
401
+ ```
402
+
403
+ ### Java-Kotlin Interop Annotations
404
+
405
+ ```kotlin
406
+ // When writing Kotlin code that will be called from Java:
407
+
408
+ // @JvmStatic — allows calling companion object functions as static
409
+ class ProductMapper {
410
+ companion object {
411
+ @JvmStatic
412
+ fun toDomain(dto: ProductDto): Product = Product(dto.id, dto.name)
413
+ }
414
+ }
415
+ // Java: ProductMapper.toDomain(dto) ✅ (without @JvmStatic: ProductMapper.Companion.toDomain(dto))
416
+
417
+ // @JvmField — exposes Kotlin property as Java field (no getter/setter)
418
+ class Config {
419
+ companion object {
420
+ @JvmField val BASE_URL = "https://api.example.com"
421
+ }
422
+ }
423
+ // Java: Config.BASE_URL ✅
424
+
425
+ // @JvmOverloads — generates overloaded methods for default parameters
426
+ class ProductService @JvmOverloads constructor(
427
+ val baseUrl: String,
428
+ val timeout: Int = 30,
429
+ val retries: Int = 3,
430
+ )
431
+ // Java: new ProductService("url") ✅ (without: must pass all 3 params)
432
+
433
+ // @Throws — declares checked exceptions for Java callers
434
+ @Throws(IOException::class)
435
+ fun readFile(path: String): String { /* ... */ }
436
+ ```
437
+
438
+ ### Calling Kotlin Suspend from Java (Bridge Pattern)
439
+
440
+ ```java
441
+ // Use CoroutineScope from Java via CoroutinesInstrumentationHelper or wrapper
442
+ // ⚠️ Recommended: write a non-suspend wrapper in Kotlin
443
+
444
+ // Kotlin wrapper (bridge.kt)
445
+ object ProductBridge {
446
+ @JvmStatic
447
+ fun getProducts(scope: CoroutineScope, callback: ProductCallback) {
448
+ scope.launch {
449
+ try {
450
+ val items = getProductsUseCase()
451
+ callback.onSuccess(items)
452
+ } catch (e: Exception) {
453
+ callback.onError(e.message ?: "Error")
454
+ }
455
+ }
456
+ }
457
+ }
458
+
459
+ // Java side
460
+ ProductBridge.getProducts(lifecycleScope, new ProductCallback() {
461
+ @Override public void onSuccess(List<Product> items) { /* update UI */ }
462
+ @Override public void onError(String message) { /* show error */ }
463
+ });
464
+ ```
465
+
466
+ ### Java Common Pitfalls
467
+
468
+ | Pitfall | Fix |
469
+ |---------|-----|
470
+ | NullPointerException | `@NonNull` / `@Nullable` + null checks |
471
+ | Memory leak (Activity in async) | `WeakReference<Activity>` or cancel on `onDestroy` |
472
+ | Main thread network call | `Executors.newSingleThreadExecutor()` |
473
+ | No `Call.cancel()` | Store reference, cancel in `onDestroy` |
474
+ | Anonymous inner class holding outer ref | Use static inner class |
475
+
476
+ ---
477
+
257
478
  > Multi-module Gradle + Hilt + Compose + offline-first.
258
479
  > Clean Architecture with domain module having zero dependencies.
480
+ > Java legacy: use LiveData + Retrofit callbacks. Bridge Kotlin suspend with wrapper functions.
package/bin/install.mjs CHANGED
@@ -70,7 +70,7 @@ const fail = m => log(` ${c.red}✗${c.reset} ${m}`);
70
70
 
71
71
  function banner() {
72
72
  log(`\n${c.bold}${c.cyan} ┌──────────────────────────────────────────────────┐`);
73
- log(` │ 📱 @buivietphi/skill-mobile-mt v1.4.2 │`);
73
+ log(` │ 📱 @buivietphi/skill-mobile-mt v1.4.3 │`);
74
74
  log(` │ Master Senior Mobile Engineer │`);
75
75
  log(` │ │`);
76
76
  log(` │ Claude · Cline · Roo Code · Cursor · Windsurf │`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@buivietphi/skill-mobile-mt",
3
- "version": "1.4.2",
4
- "description": "Master Senior Mobile Engineer skill for AI agents. Pre-built patterns from 18 production apps + local project adaptation. React Native, Flutter, iOS, Android. Supports Claude, Gemini, Kimi, Cursor, Copilot, Antigravity.",
3
+ "version": "1.4.3",
4
+ "description": "Master Senior Mobile Engineer skill for AI agents. Pre-built patterns from 30+ production repos. React Native, Flutter, iOS, Android. Supports Claude, Cline, Cursor, Windsurf, Copilot, Codex, Gemini, Kimi, Kilo Code, Kiro, Antigravity.",
5
5
  "author": "buivietphi",
6
6
  "license": "MIT",
7
7
  "keywords": [