@buivietphi/skill-mobile-mt 1.1.0 → 1.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.
Potentially problematic release.
This version of @buivietphi/skill-mobile-mt might be problematic. Click here for more details.
- package/AGENTS.md +53 -25
- package/README.md +195 -42
- package/SKILL.md +1 -1
- package/bin/install.mjs +436 -4
- package/package.json +7 -2
package/AGENTS.md
CHANGED
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
## Agent Compatibility Matrix
|
|
8
8
|
|
|
9
|
-
| Agent |
|
|
10
|
-
|
|
11
|
-
| Claude Code | `~/.claude/skills
|
|
12
|
-
| Codex | `~/.codex/skills
|
|
13
|
-
| Gemini CLI | `~/.gemini/skills
|
|
14
|
-
| Kimi | `~/.kimi/skills
|
|
15
|
-
| Cursor |
|
|
16
|
-
| Copilot |
|
|
17
|
-
| Windsurf |
|
|
18
|
-
| Antigravity | `~/.agents/skills
|
|
9
|
+
| Agent | How it loads rules | Setup | Think Block |
|
|
10
|
+
|-------|-------------------|-------|-------------|
|
|
11
|
+
| Claude Code | `~/.claude/skills/` (auto) | `npx skill-mobile-mt --claude` | `<think>...</think>` |
|
|
12
|
+
| Codex | `~/.codex/skills/` (auto) | `npx skill-mobile-mt --codex` | `<think>...</think>` |
|
|
13
|
+
| Gemini CLI | `~/.gemini/skills/` (auto) | `npx skill-mobile-mt --gemini` | `## Thinking:` block |
|
|
14
|
+
| Kimi | `~/.kimi/skills/` (manual) | `npx skill-mobile-mt --kimi` | `【思考】` or markdown |
|
|
15
|
+
| **Cursor** | **`.cursorrules` in project root** | **`npx skill-mobile-mt --init cursor`** | Inline reasoning |
|
|
16
|
+
| **Copilot** | **`.github/copilot-instructions.md`** | **`npx skill-mobile-mt --init copilot`** | `// PLAN:` comments |
|
|
17
|
+
| **Windsurf** | **`.windsurfrules` in project root** | **`npx skill-mobile-mt --init windsurf`** | Inline reasoning |
|
|
18
|
+
| Antigravity | `~/.agents/skills/` (auto) | `npx skill-mobile-mt --antigravity` | Agent-native format |
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -137,7 +137,7 @@ The agent reads the task, then decides which extra file to load:
|
|
|
137
137
|
```yaml
|
|
138
138
|
skill:
|
|
139
139
|
name: skill-mobile-mt
|
|
140
|
-
version: "1.
|
|
140
|
+
version: "1.2.0"
|
|
141
141
|
author: buivietphi
|
|
142
142
|
category: engineering
|
|
143
143
|
tags:
|
|
@@ -299,10 +299,23 @@ Priority 6 (ON-DEMAND): shared/common-pitfalls.md — Known issue patterns
|
|
|
299
299
|
- Supports both Chinese and English prompts
|
|
300
300
|
- Think blocks use `【思考】` format
|
|
301
301
|
|
|
302
|
-
### Cursor
|
|
303
|
-
-
|
|
304
|
-
-
|
|
305
|
-
-
|
|
302
|
+
### Cursor
|
|
303
|
+
- **Does NOT read from `~/.cursor/skills/`** — reads `.cursorrules` from project root
|
|
304
|
+
- Run `npx @buivietphi/skill-mobile-mt --init cursor` in your project to generate `.cursorrules`
|
|
305
|
+
- The generated file includes auto-detected framework, rules, and security patterns
|
|
306
|
+
- Think blocks embedded as inline reasoning in Composer
|
|
307
|
+
|
|
308
|
+
### GitHub Copilot
|
|
309
|
+
- **Does NOT read from `~/.copilot/skills/`** — reads `.github/copilot-instructions.md`
|
|
310
|
+
- Run `npx @buivietphi/skill-mobile-mt --init copilot` in your project to generate the file
|
|
311
|
+
- The generated file includes code patterns, required templates, and rules
|
|
312
|
+
- Think blocks as `// PLAN:` comments before code
|
|
313
|
+
|
|
314
|
+
### Windsurf
|
|
315
|
+
- **Does NOT read from `~/.windsurf/skills/`** — reads `.windsurfrules` from project root
|
|
316
|
+
- Run `npx @buivietphi/skill-mobile-mt --init windsurf` in your project to generate `.windsurfrules`
|
|
317
|
+
- The generated file includes coding rules, security rules, and architecture patterns
|
|
318
|
+
- Think blocks as inline reasoning
|
|
306
319
|
|
|
307
320
|
### Antigravity
|
|
308
321
|
- Orchestrator loads based on detected project type
|
|
@@ -340,6 +353,8 @@ Copy the relevant section to your project to enable auto-check rules in every se
|
|
|
340
353
|
|
|
341
354
|
## Installation Paths
|
|
342
355
|
|
|
356
|
+
### Skill directory install (agents that read from skills/)
|
|
357
|
+
|
|
343
358
|
```bash
|
|
344
359
|
# Claude Code (global)
|
|
345
360
|
~/.claude/skills/skill-mobile-mt/
|
|
@@ -356,15 +371,6 @@ Copy the relevant section to your project to enable auto-check rules in every se
|
|
|
356
371
|
# Kimi
|
|
357
372
|
~/.kimi/skills/skill-mobile-mt/
|
|
358
373
|
|
|
359
|
-
# Cursor
|
|
360
|
-
~/.cursor/skills/skill-mobile-mt/
|
|
361
|
-
|
|
362
|
-
# Windsurf
|
|
363
|
-
~/.windsurf/skills/skill-mobile-mt/
|
|
364
|
-
|
|
365
|
-
# Copilot
|
|
366
|
-
~/.copilot/skills/skill-mobile-mt/
|
|
367
|
-
|
|
368
374
|
# Antigravity (shared agent directory)
|
|
369
375
|
~/.agents/skills/skill-mobile-mt/
|
|
370
376
|
|
|
@@ -372,6 +378,28 @@ Copy the relevant section to your project to enable auto-check rules in every se
|
|
|
372
378
|
npx @buivietphi/skill-mobile-mt --path /your/custom/path
|
|
373
379
|
```
|
|
374
380
|
|
|
381
|
+
### Project-level files (agents that read from project root)
|
|
382
|
+
|
|
383
|
+
These agents read rules from project-level files, NOT from a skills directory.
|
|
384
|
+
Use `--init` to generate them:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
# Generate all project-level files (interactive selector)
|
|
388
|
+
npx @buivietphi/skill-mobile-mt --init
|
|
389
|
+
|
|
390
|
+
# Generate specific agent file
|
|
391
|
+
npx @buivietphi/skill-mobile-mt --init cursor # → .cursorrules
|
|
392
|
+
npx @buivietphi/skill-mobile-mt --init copilot # → .github/copilot-instructions.md
|
|
393
|
+
npx @buivietphi/skill-mobile-mt --init windsurf # → .windsurfrules
|
|
394
|
+
npx @buivietphi/skill-mobile-mt --init all # → all three files
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**What `--init` does:**
|
|
398
|
+
1. Auto-detects your project (framework, language, state management, etc.)
|
|
399
|
+
2. Generates rules files pre-filled with your detected stack
|
|
400
|
+
3. Includes all mobile best practices, security rules, and quality gates
|
|
401
|
+
4. Won't overwrite existing files (safe to run multiple times)
|
|
402
|
+
|
|
375
403
|
---
|
|
376
404
|
|
|
377
405
|
## Metadata
|
|
@@ -380,7 +408,7 @@ npx @buivietphi/skill-mobile-mt --path /your/custom/path
|
|
|
380
408
|
{
|
|
381
409
|
"id": "skill-mobile-mt",
|
|
382
410
|
"name": "skill-mobile-mt",
|
|
383
|
-
"version": "1.
|
|
411
|
+
"version": "1.2.0",
|
|
384
412
|
"author": "buivietphi",
|
|
385
413
|
"category": "engineering",
|
|
386
414
|
"description": "Master Senior Mobile Engineer. Pre-built patterns from 18 production apps + project adaptation. Auto-detects language and framework. React Native, Flutter, iOS, Android.",
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Master Senior Mobile Engineer** — AI skill for Claude Code, Codex, Gemini CLI, Kimi, Cursor, Copilot, Windsurf, and Antigravity.
|
|
4
4
|
|
|
5
|
-
Pre-built architecture patterns from **
|
|
5
|
+
Pre-built architecture patterns from **30+ production repos (200k+ GitHub stars)** including Ignite, Expensify, Mattermost, Immich, AppFlowy, Now in Android, TCA + auto-adaptation to your current project.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -10,20 +10,38 @@ Pre-built architecture patterns from **18 production mobile apps + 4 production
|
|
|
10
10
|
npx @buivietphi/skill-mobile-mt
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Interactive
|
|
13
|
+
Interactive checkbox UI — detects which AI agents are installed, lets you select with arrow keys + space.
|
|
14
14
|
|
|
15
15
|
### Install to specific agents
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npx @buivietphi/skill-mobile-mt --claude # Claude Code
|
|
19
|
-
npx @buivietphi/skill-mobile-mt --codex # Codex
|
|
20
|
-
npx @buivietphi/skill-mobile-mt --gemini # Gemini CLI
|
|
21
|
-
npx @buivietphi/skill-mobile-mt --kimi # Kimi
|
|
22
|
-
npx @buivietphi/skill-mobile-mt --antigravity # Antigravity
|
|
23
|
-
npx @buivietphi/skill-mobile-mt --all # All
|
|
18
|
+
npx @buivietphi/skill-mobile-mt --claude # Claude Code
|
|
19
|
+
npx @buivietphi/skill-mobile-mt --codex # Codex
|
|
20
|
+
npx @buivietphi/skill-mobile-mt --gemini # Gemini CLI
|
|
21
|
+
npx @buivietphi/skill-mobile-mt --kimi # Kimi
|
|
22
|
+
npx @buivietphi/skill-mobile-mt --antigravity # Antigravity
|
|
23
|
+
npx @buivietphi/skill-mobile-mt --all # All agents
|
|
24
24
|
npx @buivietphi/skill-mobile-mt --path ./dir # Custom directory
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
### Generate project-level rules (Cursor, Copilot, Windsurf)
|
|
28
|
+
|
|
29
|
+
Cursor, Copilot, and Windsurf read rules from **project-level files**, not from a skills directory. Run `--init` inside your project to generate them:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx @buivietphi/skill-mobile-mt --init # Interactive selector
|
|
33
|
+
npx @buivietphi/skill-mobile-mt --init cursor # .cursorrules
|
|
34
|
+
npx @buivietphi/skill-mobile-mt --init copilot # .github/copilot-instructions.md
|
|
35
|
+
npx @buivietphi/skill-mobile-mt --init windsurf # .windsurfrules
|
|
36
|
+
npx @buivietphi/skill-mobile-mt --init all # All three files
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**What `--init` does:**
|
|
40
|
+
1. Auto-detects your project (framework, language, state management, navigation, API client, package manager)
|
|
41
|
+
2. Generates rules files pre-filled with your detected stack
|
|
42
|
+
3. Includes mobile best practices, security rules, and quality gates
|
|
43
|
+
4. Won't overwrite existing files (safe to run multiple times)
|
|
44
|
+
|
|
27
45
|
## Usage
|
|
28
46
|
|
|
29
47
|
### Mode 1: Pre-Built Architecture (default)
|
|
@@ -32,11 +50,11 @@ npx @buivietphi/skill-mobile-mt --path ./dir # Custom directory
|
|
|
32
50
|
@skill-mobile-mt
|
|
33
51
|
```
|
|
34
52
|
|
|
35
|
-
Uses battle-tested patterns
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
38
|
-
- **
|
|
39
|
-
- **
|
|
53
|
+
Uses battle-tested patterns from 30+ production repos:
|
|
54
|
+
- **React Native** — Ignite (19.7k stars), Obytes Template, Expensify/App, Mattermost Mobile, Artsy Eigen
|
|
55
|
+
- **Flutter** — Immich (93.5k stars), AppFlowy (68.2k), Spotube (44.6k), Hiddify, Ente Photos
|
|
56
|
+
- **iOS** — TCA / Point-Free (14.4k), Clean Arch SwiftUI, Modern Clean Arch
|
|
57
|
+
- **Android** — Now in Android (20.7k), Android Showcase, Mihon (18.8k)
|
|
40
58
|
|
|
41
59
|
### Mode 2: Adapt to Your Project (project)
|
|
42
60
|
|
|
@@ -47,8 +65,123 @@ Uses battle-tested patterns extracted from real production apps:
|
|
|
47
65
|
Reads your current project first, then follows **your** conventions:
|
|
48
66
|
- Detects framework, language, package manager, state management, navigation
|
|
49
67
|
- Matches your naming, imports, file structure, patterns
|
|
68
|
+
- Clones the most similar existing feature when scaffolding new ones
|
|
50
69
|
- Never suggests migrations or imposes different architecture
|
|
51
70
|
|
|
71
|
+
## Quick Start Examples
|
|
72
|
+
|
|
73
|
+
### Step 1: Install the skill
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Install globally (one-time setup)
|
|
77
|
+
npx @buivietphi/skill-mobile-mt
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
You'll see an interactive checkbox — use arrow keys to navigate, space to select, Enter to confirm:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Select agents to install:
|
|
84
|
+
↑↓ navigate Space toggle A select all Enter confirm Q cancel
|
|
85
|
+
|
|
86
|
+
› ◉ Claude Code [detected]
|
|
87
|
+
◯ Cursor [detected]
|
|
88
|
+
◯ Windsurf [not found]
|
|
89
|
+
◯ Copilot [not found]
|
|
90
|
+
◯ Codex [not found]
|
|
91
|
+
◉ Gemini CLI [detected]
|
|
92
|
+
◯ Kimi [not found]
|
|
93
|
+
◯ Antigravity [not found]
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Step 2 (Cursor/Copilot/Windsurf only): Generate project rules
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# cd into your mobile project first
|
|
100
|
+
cd ~/projects/my-app
|
|
101
|
+
|
|
102
|
+
# Generate rules for your agents
|
|
103
|
+
npx @buivietphi/skill-mobile-mt --init all
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Output:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
📁 Project directory: /Users/you/projects/my-app
|
|
110
|
+
🔍 Detected: Expo (React Native) (TypeScript)
|
|
111
|
+
|
|
112
|
+
✓ .cursorrules → Cursor (auto-detected: Expo (React Native))
|
|
113
|
+
✓ .github/copilot-instructions.md → GitHub Copilot
|
|
114
|
+
✓ .windsurfrules → Windsurf
|
|
115
|
+
|
|
116
|
+
✅ Done! → 3 file(s) generated
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Step 3: Use in your AI agent
|
|
120
|
+
|
|
121
|
+
#### Claude Code
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# In Claude Code terminal, type:
|
|
125
|
+
@skill-mobile-mt
|
|
126
|
+
|
|
127
|
+
# Then ask anything:
|
|
128
|
+
> Create auth feature with login and register screens
|
|
129
|
+
|
|
130
|
+
# Or with project mode (reads YOUR code first):
|
|
131
|
+
@skill-mobile-mt project
|
|
132
|
+
> Add cart feature following the same pattern as ProductList
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### Cursor
|
|
136
|
+
|
|
137
|
+
After running `--init cursor`, Cursor auto-loads `.cursorrules` every session. Just open your project and code — Cursor follows the rules automatically.
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
# In Cursor Composer, just ask:
|
|
141
|
+
> Create a login screen with email/password
|
|
142
|
+
> Fix the crash in ProductDetail when images is null
|
|
143
|
+
> Review this PR for mobile best practices
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### GitHub Copilot
|
|
147
|
+
|
|
148
|
+
After running `--init copilot`, Copilot reads `.github/copilot-instructions.md` as workspace context.
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
# In VS Code with Copilot Chat:
|
|
152
|
+
> Add pagination to the product list
|
|
153
|
+
> Handle offline mode for the cart feature
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Windsurf
|
|
157
|
+
|
|
158
|
+
After running `--init windsurf`, Windsurf auto-loads `.windsurfrules`. Just code normally.
|
|
159
|
+
|
|
160
|
+
#### Gemini CLI
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# In Gemini CLI:
|
|
164
|
+
@skill-mobile-mt
|
|
165
|
+
> Setup a new Flutter project with Riverpod + clean architecture
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Codex / Kimi / Antigravity
|
|
169
|
+
|
|
170
|
+
Same as Claude Code — the skill is loaded from the skills directory.
|
|
171
|
+
|
|
172
|
+
### Example Prompts (all agents)
|
|
173
|
+
|
|
174
|
+
| What you want | What to type |
|
|
175
|
+
|--------------|-------------|
|
|
176
|
+
| New feature | `Create auth feature with login, register, forgot password` |
|
|
177
|
+
| New screen | `Add settings screen with profile, notifications, theme toggle` |
|
|
178
|
+
| Fix bug | `Fix crash when product.images is undefined` |
|
|
179
|
+
| Code review | `Review src/features/cart/ for mobile best practices` |
|
|
180
|
+
| Performance | `Optimize ProductList — it's janky when scrolling 100+ items` |
|
|
181
|
+
| Architecture | `Setup project structure for a new Expo app with Zustand + TanStack Query` |
|
|
182
|
+
| Release | `Prepare the app for App Store submission` |
|
|
183
|
+
| Security | `Audit the auth flow for security vulnerabilities` |
|
|
184
|
+
|
|
52
185
|
## Auto-Detect
|
|
53
186
|
|
|
54
187
|
The skill automatically detects before any action:
|
|
@@ -102,6 +235,7 @@ iOS only?
|
|
|
102
235
|
| `shared/code-review.md` | 865 |
|
|
103
236
|
| `shared/bug-detection.md` | 499 |
|
|
104
237
|
| `shared/prompt-engineering.md` | 3,927 |
|
|
238
|
+
| `shared/architecture-intelligence.md` | 4,500 |
|
|
105
239
|
| `shared/common-pitfalls.md` | 1,160 |
|
|
106
240
|
| `shared/error-recovery.md` | 2,435 |
|
|
107
241
|
| `shared/document-analysis.md` | 1,200 |
|
|
@@ -111,36 +245,51 @@ iOS only?
|
|
|
111
245
|
| `shared/platform-excellence.md` | 1,500 |
|
|
112
246
|
| `shared/version-management.md` | 3,500 |
|
|
113
247
|
| `shared/observability.md` | 3,000 |
|
|
114
|
-
|
|
|
248
|
+
| `shared/claude-md-template.md` | ~500 |
|
|
249
|
+
| `shared/agent-rules-template.md` | ~2,500 |
|
|
250
|
+
| **Total** | **~46,000** |
|
|
115
251
|
|
|
116
252
|
## Installed Structure
|
|
117
253
|
|
|
118
254
|
```
|
|
119
255
|
~/.claude/skills/ (or ~/.gemini/skills/, ~/.agents/skills/, etc.)
|
|
120
256
|
└── skill-mobile-mt/
|
|
121
|
-
├── SKILL.md
|
|
122
|
-
├── AGENTS.md
|
|
257
|
+
├── SKILL.md Entry point + auto-detect + quality gates
|
|
258
|
+
├── AGENTS.md Multi-agent compatibility
|
|
123
259
|
├── react-native/
|
|
124
|
-
│ └── react-native.md
|
|
260
|
+
│ └── react-native.md React Native + Expo patterns
|
|
125
261
|
├── flutter/
|
|
126
|
-
│ └── flutter.md
|
|
262
|
+
│ └── flutter.md Flutter + Dart patterns
|
|
127
263
|
├── ios/
|
|
128
|
-
│ └── ios-native.md
|
|
264
|
+
│ └── ios-native.md iOS Swift patterns
|
|
129
265
|
├── android/
|
|
130
|
-
│ └── android-native.md
|
|
266
|
+
│ └── android-native.md Android Kotlin patterns
|
|
131
267
|
└── shared/
|
|
132
|
-
├── code-review.md
|
|
133
|
-
├── bug-detection.md
|
|
134
|
-
├── prompt-engineering.md
|
|
135
|
-
├──
|
|
136
|
-
├──
|
|
137
|
-
├──
|
|
138
|
-
├──
|
|
139
|
-
├──
|
|
140
|
-
├──
|
|
141
|
-
├──
|
|
142
|
-
├──
|
|
143
|
-
|
|
268
|
+
├── code-review.md Senior review checklist
|
|
269
|
+
├── bug-detection.md Auto bug scanner
|
|
270
|
+
├── prompt-engineering.md Auto-think + prompt templates
|
|
271
|
+
├── architecture-intelligence.md Patterns from 30+ production repos
|
|
272
|
+
├── common-pitfalls.md Problem → Symptoms → Solution
|
|
273
|
+
├── error-recovery.md 16 build/runtime error fixes
|
|
274
|
+
├── document-analysis.md Parse docs/images → code
|
|
275
|
+
├── anti-patterns.md PII, cardinality, payload detection
|
|
276
|
+
├── performance-prediction.md Frame budget, FPS prediction
|
|
277
|
+
├── platform-excellence.md iOS 18+ vs Android 15+ guidelines
|
|
278
|
+
├── version-management.md SDK compatibility matrix
|
|
279
|
+
├── observability.md Sessions as 4th pillar
|
|
280
|
+
├── release-checklist.md Pre-release verification
|
|
281
|
+
├── claude-md-template.md CLAUDE.md template for projects
|
|
282
|
+
└── agent-rules-template.md Rules templates for all agents
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Project-level files (generated by `--init`)
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
your-project/
|
|
289
|
+
├── .cursorrules Cursor rules (auto-detected stack)
|
|
290
|
+
├── .windsurfrules Windsurf rules (auto-detected stack)
|
|
291
|
+
└── .github/
|
|
292
|
+
└── copilot-instructions.md Copilot rules (auto-detected stack)
|
|
144
293
|
```
|
|
145
294
|
|
|
146
295
|
## What's Included
|
|
@@ -183,6 +332,10 @@ iOS only?
|
|
|
183
332
|
- Requirements Extraction: user stories, screen flows, data models, business rules
|
|
184
333
|
- Document → Code pipeline: read → extract → map features → scaffold
|
|
185
334
|
|
|
335
|
+
### Architecture Intelligence (from 30+ production repos)
|
|
336
|
+
|
|
337
|
+
- **Architecture Intelligence** (`architecture-intelligence.md`): Cross-platform patterns from Ignite, Immich, AppFlowy, TCA, Now in Android and more. Includes: dual state management, feature-based modules, bootstrap/startup pattern, functional error handling, architecture validation (Konsist), production folder structure templates, and decision matrices for state/nav/testing.
|
|
338
|
+
|
|
186
339
|
### Production Patterns (from Senaiverse, Mhuxain, VoltAgent, Nexus)
|
|
187
340
|
|
|
188
341
|
- **Anti-Pattern Detection** (`anti-patterns.md`): Detect PII leaks (CRITICAL), high cardinality tags, unbounded payloads, unstructured logs, sync telemetry on main thread — with auto-fix suggestions
|
|
@@ -208,16 +361,16 @@ iOS only?
|
|
|
208
361
|
|
|
209
362
|
## Supported Agents
|
|
210
363
|
|
|
211
|
-
| Agent |
|
|
212
|
-
|
|
213
|
-
| Claude Code | `~/.claude/skills
|
|
214
|
-
| Codex | `~/.codex/skills
|
|
215
|
-
| Gemini CLI | `~/.gemini/skills
|
|
216
|
-
| Kimi | `~/.kimi/skills
|
|
217
|
-
|
|
|
218
|
-
|
|
|
219
|
-
|
|
|
220
|
-
|
|
|
364
|
+
| Agent | How it works | Setup command |
|
|
365
|
+
|-------|-------------|---------------|
|
|
366
|
+
| **Claude Code** | Reads from `~/.claude/skills/` | `npx skill-mobile-mt --claude` |
|
|
367
|
+
| **Codex** | Reads from `~/.codex/skills/` | `npx skill-mobile-mt --codex` |
|
|
368
|
+
| **Gemini CLI** | Reads from `~/.gemini/skills/` | `npx skill-mobile-mt --gemini` |
|
|
369
|
+
| **Kimi** | Reads from `~/.kimi/skills/` | `npx skill-mobile-mt --kimi` |
|
|
370
|
+
| **Antigravity** | Reads from `~/.agents/skills/` | `npx skill-mobile-mt --antigravity` |
|
|
371
|
+
| **Cursor** | Reads `.cursorrules` from project root | `npx skill-mobile-mt --init cursor` |
|
|
372
|
+
| **Copilot** | Reads `.github/copilot-instructions.md` | `npx skill-mobile-mt --init copilot` |
|
|
373
|
+
| **Windsurf** | Reads `.windsurfrules` from project root | `npx skill-mobile-mt --init windsurf` |
|
|
221
374
|
|
|
222
375
|
## License
|
|
223
376
|
|
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
|
+
version: "1.2.0"
|
|
5
5
|
author: buivietphi
|
|
6
6
|
priority: high
|
|
7
7
|
user-invocable: true
|
package/bin/install.mjs
CHANGED
|
@@ -14,9 +14,14 @@
|
|
|
14
14
|
* npx @buivietphi/skill-mobile --antigravity # Antigravity
|
|
15
15
|
* npx @buivietphi/skill-mobile --auto # Auto-detect (postinstall)
|
|
16
16
|
* npx @buivietphi/skill-mobile --path DIR # Custom path
|
|
17
|
+
* npx @buivietphi/skill-mobile --init # Generate project-level rules (interactive)
|
|
18
|
+
* npx @buivietphi/skill-mobile --init cursor # Generate .cursorrules
|
|
19
|
+
* npx @buivietphi/skill-mobile --init copilot # Generate .github/copilot-instructions.md
|
|
20
|
+
* npx @buivietphi/skill-mobile --init windsurf # Generate .windsurfrules
|
|
21
|
+
* npx @buivietphi/skill-mobile --init all # Generate all project-level files
|
|
17
22
|
*/
|
|
18
23
|
|
|
19
|
-
import { existsSync, mkdirSync, cpSync, readFileSync } from 'node:fs';
|
|
24
|
+
import { existsSync, mkdirSync, cpSync, readFileSync, writeFileSync } from 'node:fs';
|
|
20
25
|
import { join, resolve, dirname } from 'node:path';
|
|
21
26
|
import { homedir } from 'node:os';
|
|
22
27
|
import { fileURLToPath } from 'node:url';
|
|
@@ -56,7 +61,7 @@ const fail = m => log(` ${c.red}✗${c.reset} ${m}`);
|
|
|
56
61
|
|
|
57
62
|
function banner() {
|
|
58
63
|
log(`\n${c.bold}${c.cyan} ┌──────────────────────────────────────────────┐`);
|
|
59
|
-
log(` │ 📱 @buivietphi/skill-mobile-mt v1.
|
|
64
|
+
log(` │ 📱 @buivietphi/skill-mobile-mt v1.2.0 │`);
|
|
60
65
|
log(` │ Master Senior Mobile Engineer │`);
|
|
61
66
|
log(` │ │`);
|
|
62
67
|
log(` │ Claude · Codex · Gemini · Kimi │`);
|
|
@@ -113,6 +118,368 @@ function install(baseDir, agentName) {
|
|
|
113
118
|
return n;
|
|
114
119
|
}
|
|
115
120
|
|
|
121
|
+
// ─── Project Auto-Detect ─────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
function detectProject(dir) {
|
|
124
|
+
const has = f => existsSync(join(dir, f));
|
|
125
|
+
const readJson = f => { try { return JSON.parse(readFileSync(join(dir, f), 'utf-8')); } catch { return null; } };
|
|
126
|
+
|
|
127
|
+
let framework = '[React Native CLI / Expo / Flutter / iOS / Android]';
|
|
128
|
+
let language = '[TypeScript / Dart / Swift / Kotlin]';
|
|
129
|
+
let state = '[Redux Toolkit / Zustand / Riverpod / BLoC / StateFlow]';
|
|
130
|
+
let nav = '[React Navigation / Expo Router / GoRouter / UIKit / Jetpack]';
|
|
131
|
+
let api = '[axios / fetch / Dio / Firebase / Retrofit]';
|
|
132
|
+
let pkgMgr = '[yarn / npm / bun / flutter pub]';
|
|
133
|
+
|
|
134
|
+
// Detect framework + language
|
|
135
|
+
if (has('pubspec.yaml')) {
|
|
136
|
+
framework = 'Flutter'; language = 'Dart'; pkgMgr = 'flutter pub';
|
|
137
|
+
} else if (has('package.json')) {
|
|
138
|
+
const pkg = readJson('package.json');
|
|
139
|
+
const deps = { ...(pkg?.dependencies || {}), ...(pkg?.devDependencies || {}) };
|
|
140
|
+
if (deps['expo']) { framework = 'Expo (React Native)'; }
|
|
141
|
+
else if (deps['react-native']) { framework = 'React Native CLI'; }
|
|
142
|
+
language = deps['typescript'] || has('tsconfig.json') ? 'TypeScript' : 'JavaScript';
|
|
143
|
+
// State
|
|
144
|
+
if (deps['@reduxjs/toolkit'] || deps['redux']) state = 'Redux Toolkit';
|
|
145
|
+
else if (deps['zustand']) state = 'Zustand';
|
|
146
|
+
else if (deps['mobx-react-lite'] || deps['mobx'])state = 'MobX';
|
|
147
|
+
// Nav
|
|
148
|
+
if (deps['expo-router']) nav = 'Expo Router';
|
|
149
|
+
else if (deps['@react-navigation/native']) nav = 'React Navigation';
|
|
150
|
+
// API
|
|
151
|
+
if (deps['axios']) api = 'axios';
|
|
152
|
+
else if (deps['@apollo/client']) api = 'GraphQL (Apollo)';
|
|
153
|
+
// Pkg manager
|
|
154
|
+
if (has('yarn.lock')) pkgMgr = 'yarn';
|
|
155
|
+
else if (has('pnpm-lock.yaml')) pkgMgr = 'pnpm';
|
|
156
|
+
else if (has('bun.lockb')) pkgMgr = 'bun';
|
|
157
|
+
else pkgMgr = 'npm';
|
|
158
|
+
} else if (has('build.gradle') || has('build.gradle.kts')) {
|
|
159
|
+
framework = 'Android Native'; language = 'Kotlin'; pkgMgr = 'Gradle';
|
|
160
|
+
}
|
|
161
|
+
// iOS detection (*.xcodeproj) is harder — leave as placeholder
|
|
162
|
+
|
|
163
|
+
return { framework, language, state, nav, api, pkgMgr };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ─── Project-Level File Templates ────────────────────────────────────────────
|
|
167
|
+
|
|
168
|
+
const PROJECT_AGENTS = {
|
|
169
|
+
cursor: {
|
|
170
|
+
name: 'Cursor',
|
|
171
|
+
file: '.cursorrules',
|
|
172
|
+
dir: '.',
|
|
173
|
+
generate: (p) => `# ${p.framework} Project — Cursor Rules
|
|
174
|
+
# Generated by @buivietphi/skill-mobile-mt
|
|
175
|
+
|
|
176
|
+
## Project
|
|
177
|
+
- Framework: ${p.framework}
|
|
178
|
+
- Language: ${p.language}
|
|
179
|
+
- State: ${p.state}
|
|
180
|
+
- Navigation: ${p.nav}
|
|
181
|
+
- API: ${p.api}
|
|
182
|
+
- Package Manager: ${p.pkgMgr}
|
|
183
|
+
|
|
184
|
+
## Code Style
|
|
185
|
+
- PascalCase for screens and components
|
|
186
|
+
- camelCase for hooks, services, utils
|
|
187
|
+
- Absolute imports with @/ alias (if configured)
|
|
188
|
+
|
|
189
|
+
## Auto-Check (before every completion)
|
|
190
|
+
- No console.log / print in production code
|
|
191
|
+
- No hardcoded secrets or API keys
|
|
192
|
+
- All async wrapped in try/catch
|
|
193
|
+
- All 4 states: loading / error / empty / success
|
|
194
|
+
- useEffect has cleanup (return () => ...)
|
|
195
|
+
- FlatList (not ScrollView) for dynamic lists > 20 items
|
|
196
|
+
- No implicit 'any' in TypeScript
|
|
197
|
+
- No force unwrap (! / !!) without null check
|
|
198
|
+
- New screens registered in navigator
|
|
199
|
+
|
|
200
|
+
## Performance
|
|
201
|
+
- React.memo / const widget for expensive components
|
|
202
|
+
- useMemo/useCallback for stable references
|
|
203
|
+
- Images cached and resized
|
|
204
|
+
- No main thread blocking
|
|
205
|
+
|
|
206
|
+
## Security (non-negotiable)
|
|
207
|
+
- Tokens → SecureStore / Keychain / EncryptedSharedPreferences
|
|
208
|
+
- API calls → HTTPS only
|
|
209
|
+
- Sensitive data → never in logs
|
|
210
|
+
- User input → sanitize before display
|
|
211
|
+
- Deep links → validate before navigation
|
|
212
|
+
|
|
213
|
+
## Never
|
|
214
|
+
- Change framework or architecture
|
|
215
|
+
- Change state management library
|
|
216
|
+
- Add packages without checking SDK compatibility
|
|
217
|
+
- Mix package managers
|
|
218
|
+
- Use ScrollView for long lists
|
|
219
|
+
- Leave empty catch blocks
|
|
220
|
+
- Store tokens in AsyncStorage / SharedPreferences / UserDefaults
|
|
221
|
+
|
|
222
|
+
## Architecture
|
|
223
|
+
- Dependencies flow inward: UI → Domain → Data
|
|
224
|
+
- Single responsibility per file (max 300 lines)
|
|
225
|
+
- Feature-based organization preferred
|
|
226
|
+
|
|
227
|
+
## Reference
|
|
228
|
+
- Full skill: ~/.cursor/skills/skill-mobile-mt/
|
|
229
|
+
- Patterns from 30+ production repos (200k+ GitHub stars)
|
|
230
|
+
`,
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
copilot: {
|
|
234
|
+
name: 'GitHub Copilot',
|
|
235
|
+
file: 'copilot-instructions.md',
|
|
236
|
+
dir: '.github',
|
|
237
|
+
generate: (p) => `# Copilot Instructions — ${p.framework} Project
|
|
238
|
+
|
|
239
|
+
> Generated by @buivietphi/skill-mobile-mt
|
|
240
|
+
|
|
241
|
+
## Project Context
|
|
242
|
+
- **Framework:** ${p.framework}
|
|
243
|
+
- **Language:** ${p.language}
|
|
244
|
+
- **State Management:** ${p.state}
|
|
245
|
+
- **Navigation:** ${p.nav}
|
|
246
|
+
- **API:** ${p.api}
|
|
247
|
+
- **Package Manager:** ${p.pkgMgr}
|
|
248
|
+
|
|
249
|
+
## Conventions
|
|
250
|
+
- PascalCase: components, screens, classes
|
|
251
|
+
- camelCase: hooks, services, utilities, variables
|
|
252
|
+
- Files named same as their default export
|
|
253
|
+
|
|
254
|
+
## Required Patterns
|
|
255
|
+
|
|
256
|
+
### Every async function
|
|
257
|
+
\`\`\`typescript
|
|
258
|
+
try {
|
|
259
|
+
setLoading(true);
|
|
260
|
+
const result = await apiCall();
|
|
261
|
+
setData(result);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
setError(error.message);
|
|
264
|
+
} finally {
|
|
265
|
+
setLoading(false);
|
|
266
|
+
}
|
|
267
|
+
\`\`\`
|
|
268
|
+
|
|
269
|
+
### Every screen must handle 4 states
|
|
270
|
+
\`\`\`typescript
|
|
271
|
+
if (loading) return <LoadingScreen />;
|
|
272
|
+
if (error) return <ErrorScreen error={error} />;
|
|
273
|
+
if (!data?.length) return <EmptyScreen />;
|
|
274
|
+
return <DataScreen data={data} />;
|
|
275
|
+
\`\`\`
|
|
276
|
+
|
|
277
|
+
### Every useEffect with subscriptions
|
|
278
|
+
\`\`\`typescript
|
|
279
|
+
useEffect(() => {
|
|
280
|
+
const sub = subscribe();
|
|
281
|
+
return () => sub.unsubscribe(); // REQUIRED
|
|
282
|
+
}, []);
|
|
283
|
+
\`\`\`
|
|
284
|
+
|
|
285
|
+
## Rules
|
|
286
|
+
- No console.log / print in production
|
|
287
|
+
- No hardcoded secrets or API keys
|
|
288
|
+
- FlatList (not ScrollView) for dynamic lists
|
|
289
|
+
- Tokens in SecureStore / Keychain only
|
|
290
|
+
- No force unwrap (! / !!) without null check
|
|
291
|
+
- No implicit 'any' in TypeScript
|
|
292
|
+
- No empty catch blocks
|
|
293
|
+
- No inline functions in render/build
|
|
294
|
+
- Images cached and resized
|
|
295
|
+
- New screens registered in navigator
|
|
296
|
+
|
|
297
|
+
## Security
|
|
298
|
+
- Tokens → SecureStore / Keychain / EncryptedSharedPreferences
|
|
299
|
+
- API calls → HTTPS only
|
|
300
|
+
- Sensitive data → never in logs
|
|
301
|
+
- User input → sanitize before rendering
|
|
302
|
+
- Deep links → validate before navigation
|
|
303
|
+
|
|
304
|
+
## Never
|
|
305
|
+
- Suggest migrating to a different framework
|
|
306
|
+
- Change state management library
|
|
307
|
+
- Add packages without checking SDK compatibility
|
|
308
|
+
- Mix package managers (yarn + npm)
|
|
309
|
+
- Use ScrollView for lists > 20 items
|
|
310
|
+
- Store tokens in AsyncStorage / SharedPreferences / UserDefaults
|
|
311
|
+
|
|
312
|
+
## Architecture
|
|
313
|
+
- Clean Architecture: UI → Domain → Data
|
|
314
|
+
- Single responsibility per file (max 300 lines)
|
|
315
|
+
- Feature-based organization preferred
|
|
316
|
+
|
|
317
|
+
## Reference
|
|
318
|
+
Full skill with patterns from 30+ production repos: ~/.copilot/skills/skill-mobile-mt/
|
|
319
|
+
`,
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
windsurf: {
|
|
323
|
+
name: 'Windsurf',
|
|
324
|
+
file: '.windsurfrules',
|
|
325
|
+
dir: '.',
|
|
326
|
+
generate: (p) => `# ${p.framework} Project — Windsurf Rules
|
|
327
|
+
# Generated by @buivietphi/skill-mobile-mt
|
|
328
|
+
|
|
329
|
+
Project: ${p.framework}
|
|
330
|
+
Language: ${p.language}
|
|
331
|
+
State management: ${p.state}
|
|
332
|
+
Navigation: ${p.nav}
|
|
333
|
+
API: ${p.api}
|
|
334
|
+
Package manager: ${p.pkgMgr}
|
|
335
|
+
|
|
336
|
+
## Coding Rules
|
|
337
|
+
|
|
338
|
+
Always:
|
|
339
|
+
- Wrap all async operations in try/catch
|
|
340
|
+
- Handle all 4 states: loading, error, empty, success
|
|
341
|
+
- Add cleanup to useEffect (return () => ...)
|
|
342
|
+
- Use FlatList for dynamic lists (not ScrollView)
|
|
343
|
+
- Use PascalCase for components and screens
|
|
344
|
+
- Use camelCase for hooks, services, and utilities
|
|
345
|
+
- No implicit 'any' in TypeScript
|
|
346
|
+
- No force unwrap (! / !!) without null check
|
|
347
|
+
- New screens registered in navigator
|
|
348
|
+
- React.memo / const widget for expensive components
|
|
349
|
+
- Images cached and resized
|
|
350
|
+
|
|
351
|
+
Never:
|
|
352
|
+
- Leave console.log / print in production code
|
|
353
|
+
- Hardcode secrets, tokens, or API keys
|
|
354
|
+
- Store tokens in AsyncStorage / SharedPreferences / UserDefaults
|
|
355
|
+
- Change the framework or architecture
|
|
356
|
+
- Change state management library
|
|
357
|
+
- Add packages without verifying SDK compatibility
|
|
358
|
+
- Mix yarn and npm
|
|
359
|
+
- Use ScrollView for lists > 20 items
|
|
360
|
+
- Leave empty catch blocks
|
|
361
|
+
- Use index as list key
|
|
362
|
+
|
|
363
|
+
## Security (non-negotiable)
|
|
364
|
+
- Tokens → SecureStore / Keychain / EncryptedSharedPreferences
|
|
365
|
+
- API calls → HTTPS only
|
|
366
|
+
- Sensitive data → never in logs
|
|
367
|
+
- User input → sanitize before display
|
|
368
|
+
- Deep links → validate before navigation
|
|
369
|
+
|
|
370
|
+
## Architecture
|
|
371
|
+
- Clean Architecture: UI → Domain → Data
|
|
372
|
+
- Single responsibility per file (max 300 lines)
|
|
373
|
+
- Feature-based organization preferred
|
|
374
|
+
|
|
375
|
+
## Reference
|
|
376
|
+
Full skill: ~/.windsurf/skills/skill-mobile-mt/
|
|
377
|
+
Patterns from 30+ production repos (200k+ GitHub stars)
|
|
378
|
+
`,
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// Agents that need project-level files (don't just read from skills dir)
|
|
383
|
+
const NEEDS_PROJECT_FILE = new Set(['cursor', 'copilot', 'windsurf']);
|
|
384
|
+
|
|
385
|
+
function initProjectFiles(dir, agents) {
|
|
386
|
+
const project = detectProject(dir);
|
|
387
|
+
let created = 0;
|
|
388
|
+
|
|
389
|
+
for (const key of agents) {
|
|
390
|
+
const agent = PROJECT_AGENTS[key];
|
|
391
|
+
if (!agent) continue;
|
|
392
|
+
|
|
393
|
+
const targetDir = join(dir, agent.dir);
|
|
394
|
+
const targetFile = join(targetDir, agent.file);
|
|
395
|
+
|
|
396
|
+
if (existsSync(targetFile)) {
|
|
397
|
+
info(`${c.yellow}${agent.file}${c.reset} already exists — skipped (won't overwrite)`);
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
mkdirSync(targetDir, { recursive: true });
|
|
402
|
+
writeFileSync(targetFile, agent.generate(project), 'utf-8');
|
|
403
|
+
ok(`${c.bold}${join(agent.dir, agent.file)}${c.reset} → ${agent.name} ${c.dim}(auto-detected: ${project.framework})${c.reset}`);
|
|
404
|
+
created++;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return created;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
async function selectProjectAgents() {
|
|
411
|
+
if (!process.stdin.isTTY) return Object.keys(PROJECT_AGENTS);
|
|
412
|
+
|
|
413
|
+
const keys = Object.keys(PROJECT_AGENTS);
|
|
414
|
+
const selected = new Set(keys); // all selected by default
|
|
415
|
+
let cursor = 0;
|
|
416
|
+
|
|
417
|
+
const UP = '\x1b[A';
|
|
418
|
+
const DOWN = '\x1b[B';
|
|
419
|
+
const ERASE_DN = '\x1b[J';
|
|
420
|
+
const HIDE_CUR = '\x1b[?25l';
|
|
421
|
+
const SHOW_CUR = '\x1b[?25h';
|
|
422
|
+
const moveUp = n => `\x1b[${n}A`;
|
|
423
|
+
const TOTAL_LINES = 3 + keys.length;
|
|
424
|
+
|
|
425
|
+
function render(first) {
|
|
426
|
+
if (!first) process.stdout.write(moveUp(TOTAL_LINES) + ERASE_DN);
|
|
427
|
+
process.stdout.write(`\n${c.bold} Select project-level files to generate:${c.reset}\n`);
|
|
428
|
+
process.stdout.write(` ${c.dim}↑↓ navigate Space toggle A select all Enter confirm Q cancel${c.reset}\n`);
|
|
429
|
+
|
|
430
|
+
for (let i = 0; i < keys.length; i++) {
|
|
431
|
+
const k = keys[i];
|
|
432
|
+
const agent = PROJECT_AGENTS[k];
|
|
433
|
+
const isCur = i === cursor;
|
|
434
|
+
const isSel = selected.has(k);
|
|
435
|
+
|
|
436
|
+
const ptr = isCur ? `${c.cyan}›${c.reset}` : ' ';
|
|
437
|
+
const box = isSel ? `${c.green}◉${c.reset}` : `${c.dim}◯${c.reset}`;
|
|
438
|
+
const name = isCur ? `${c.bold}${c.cyan}${agent.name}${c.reset}` : agent.name;
|
|
439
|
+
const file = `${c.dim}→ ${join(agent.dir, agent.file)}${c.reset}`;
|
|
440
|
+
|
|
441
|
+
process.stdout.write(` ${ptr} ${box} ${name.padEnd(20)}${file}\n`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
process.stdout.write(HIDE_CUR);
|
|
446
|
+
render(true);
|
|
447
|
+
|
|
448
|
+
return new Promise(resolve => {
|
|
449
|
+
process.stdin.setRawMode(true);
|
|
450
|
+
process.stdin.resume();
|
|
451
|
+
process.stdin.setEncoding('utf8');
|
|
452
|
+
|
|
453
|
+
const onKey = key => {
|
|
454
|
+
const done = result => {
|
|
455
|
+
process.stdin.setRawMode(false);
|
|
456
|
+
process.stdin.pause();
|
|
457
|
+
process.stdin.off('data', onKey);
|
|
458
|
+
process.stdout.write(SHOW_CUR + '\n');
|
|
459
|
+
resolve(result);
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
if (key === '\x03') { done(null); process.exit(0); }
|
|
463
|
+
if (key === 'q' || key === 'Q' || key === '\x1b') { done([]); return; }
|
|
464
|
+
if (key === '\r' || key === '\n') { done([...selected]); return; }
|
|
465
|
+
|
|
466
|
+
if (key === UP) cursor = (cursor - 1 + keys.length) % keys.length;
|
|
467
|
+
else if (key === DOWN) cursor = (cursor + 1) % keys.length;
|
|
468
|
+
else if (key === ' ') {
|
|
469
|
+
if (selected.has(keys[cursor])) selected.delete(keys[cursor]);
|
|
470
|
+
else selected.add(keys[cursor]);
|
|
471
|
+
} else if (key === 'a' || key === 'A') {
|
|
472
|
+
if (selected.size === keys.length) selected.clear();
|
|
473
|
+
else keys.forEach(k => selected.add(k));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
render(false);
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
process.stdin.on('data', onKey);
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
116
483
|
// ─── Checkbox UI ─────────────────────────────────────────────────────────────
|
|
117
484
|
|
|
118
485
|
async function selectAgents(detected) {
|
|
@@ -201,6 +568,56 @@ async function main() {
|
|
|
201
568
|
const flags = new Set(args.map(a => a.replace(/^--?/, '')));
|
|
202
569
|
|
|
203
570
|
banner();
|
|
571
|
+
|
|
572
|
+
// ─── --init mode: generate project-level files ─────────────────────────────
|
|
573
|
+
if (flags.has('init')) {
|
|
574
|
+
const cwd = process.cwd();
|
|
575
|
+
log(`${c.bold} 📁 Project directory:${c.reset} ${c.dim}${cwd}${c.reset}`);
|
|
576
|
+
|
|
577
|
+
const project = detectProject(cwd);
|
|
578
|
+
log(`${c.bold} 🔍 Detected:${c.reset} ${c.cyan}${project.framework}${c.reset} (${project.language})\n`);
|
|
579
|
+
|
|
580
|
+
// Determine which agents to init
|
|
581
|
+
let initTargets = [];
|
|
582
|
+
const initIdx = args.indexOf('--init');
|
|
583
|
+
const initArg = args[initIdx + 1];
|
|
584
|
+
|
|
585
|
+
if (initArg === 'all') {
|
|
586
|
+
initTargets = Object.keys(PROJECT_AGENTS);
|
|
587
|
+
} else if (initArg && PROJECT_AGENTS[initArg]) {
|
|
588
|
+
initTargets = [initArg];
|
|
589
|
+
} else if (initArg && !initArg.startsWith('-')) {
|
|
590
|
+
fail(`Unknown agent: ${initArg}. Available: ${Object.keys(PROJECT_AGENTS).join(', ')}, all`);
|
|
591
|
+
process.exit(1);
|
|
592
|
+
} else {
|
|
593
|
+
// Interactive selection
|
|
594
|
+
const chosen = await selectProjectAgents();
|
|
595
|
+
if (!chosen || chosen.length === 0) { info('Cancelled.'); return; }
|
|
596
|
+
initTargets = chosen;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
log(`\n${c.bold} Generating project-level rules...${c.reset}\n`);
|
|
600
|
+
const n = initProjectFiles(cwd, initTargets);
|
|
601
|
+
|
|
602
|
+
if (n > 0) {
|
|
603
|
+
log(`\n${c.green}${c.bold} ✅ Done!${c.reset} → ${n} file(s) generated\n`);
|
|
604
|
+
log(` ${c.bold}Generated files:${c.reset}`);
|
|
605
|
+
for (const k of initTargets) {
|
|
606
|
+
const agent = PROJECT_AGENTS[k];
|
|
607
|
+
if (agent) {
|
|
608
|
+
const fp = join(agent.dir, agent.file);
|
|
609
|
+
log(` ${c.green}●${c.reset} ${agent.name.padEnd(18)} ${c.dim}${fp}${c.reset}`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
log(`\n ${c.dim}Files are auto-detected for ${project.framework}.`);
|
|
613
|
+
log(` Edit the generated files to customize for your project.${c.reset}\n`);
|
|
614
|
+
} else {
|
|
615
|
+
info('No files generated (all already exist).\n');
|
|
616
|
+
}
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// ─── Normal install mode ───────────────────────────────────────────────────
|
|
204
621
|
showContext();
|
|
205
622
|
|
|
206
623
|
let targets = [];
|
|
@@ -237,13 +654,28 @@ async function main() {
|
|
|
237
654
|
|
|
238
655
|
log(`\n${c.green}${c.bold} ✅ Done!${c.reset} → ${targets.length} agent(s)\n`);
|
|
239
656
|
log(` ${c.bold}Usage:${c.reset}`);
|
|
240
|
-
log(` ${c.cyan}@skill-mobile-mt${c.reset} Pre-built patterns (
|
|
657
|
+
log(` ${c.cyan}@skill-mobile-mt${c.reset} Pre-built patterns (30+ production repos)`);
|
|
241
658
|
log(` ${c.cyan}@skill-mobile-mt project${c.reset} Read current project, adapt to it\n`);
|
|
242
659
|
log(` ${c.bold}Installed to:${c.reset}`);
|
|
243
660
|
for (const k of targets) {
|
|
244
661
|
log(` ${c.green}●${c.reset} ${AGENTS[k].name.padEnd(14)} ${c.dim}${AGENTS[k].dir}/${SKILL_NAME}${c.reset}`);
|
|
245
662
|
}
|
|
246
|
-
|
|
663
|
+
|
|
664
|
+
// Show tip for agents that need project-level files
|
|
665
|
+
const needsInit = targets.filter(k => NEEDS_PROJECT_FILE.has(k));
|
|
666
|
+
if (needsInit.length > 0) {
|
|
667
|
+
const names = needsInit.map(k => AGENTS[k].name).join(', ');
|
|
668
|
+
log('');
|
|
669
|
+
log(` ${c.yellow}${c.bold}💡 Important:${c.reset} ${names} read rules from ${c.bold}project-level files${c.reset},`);
|
|
670
|
+
log(` not from the skills directory. Run this in your project root:`);
|
|
671
|
+
log('');
|
|
672
|
+
log(` ${c.cyan}npx @buivietphi/skill-mobile-mt --init${c.reset}`);
|
|
673
|
+
log('');
|
|
674
|
+
log(` This generates ${c.bold}.cursorrules${c.reset}, ${c.bold}.windsurfrules${c.reset}, ${c.bold}.github/copilot-instructions.md${c.reset}`);
|
|
675
|
+
log(` with auto-detected project settings.\n`);
|
|
676
|
+
} else {
|
|
677
|
+
log('');
|
|
678
|
+
}
|
|
247
679
|
}
|
|
248
680
|
|
|
249
681
|
main().catch(e => { fail(e.message); process.exit(1); });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buivietphi/skill-mobile-mt",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
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.",
|
|
5
5
|
"author": "buivietphi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,7 +38,12 @@
|
|
|
38
38
|
"install:claude": "node bin/install.mjs --claude",
|
|
39
39
|
"install:gemini": "node bin/install.mjs --gemini",
|
|
40
40
|
"install:kimi": "node bin/install.mjs --kimi",
|
|
41
|
-
"install:all": "node bin/install.mjs --all"
|
|
41
|
+
"install:all": "node bin/install.mjs --all",
|
|
42
|
+
"init": "node bin/install.mjs --init",
|
|
43
|
+
"init:cursor": "node bin/install.mjs --init cursor",
|
|
44
|
+
"init:copilot": "node bin/install.mjs --init copilot",
|
|
45
|
+
"init:windsurf": "node bin/install.mjs --init windsurf",
|
|
46
|
+
"init:all": "node bin/install.mjs --init all"
|
|
42
47
|
},
|
|
43
48
|
"engines": {
|
|
44
49
|
"node": ">=18"
|