flutter-pro-max-cli 1.0.2 → 2.0.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.
- package/README.md +97 -16
- package/assets/data/flutter-performance.csv +36 -0
- package/assets/data/mobile-accessibility.csv +36 -0
- package/assets/data/ui-reasoning.csv +36 -0
- package/assets/{.claude/skills/flutter-pro-max/scripts → scripts}/core.py +20 -3
- package/assets/{.claude/skills/flutter-pro-max/scripts → scripts}/search.py +1 -1
- package/assets/templates/base/quick-reference.md +41 -0
- package/assets/templates/base/skill-content.md +179 -0
- package/assets/templates/platforms/agent.json +21 -0
- package/assets/templates/platforms/claude.json +21 -0
- package/assets/templates/platforms/codebuddy.json +18 -0
- package/assets/templates/platforms/codex.json +21 -0
- package/assets/templates/platforms/continue.json +21 -0
- package/assets/templates/platforms/copilot.json +18 -0
- package/assets/templates/platforms/cursor.json +18 -0
- package/assets/templates/platforms/gemini.json +21 -0
- package/assets/templates/platforms/kiro.json +18 -0
- package/assets/templates/platforms/opencode.json +21 -0
- package/assets/templates/platforms/qoder.json +18 -0
- package/assets/templates/platforms/roocode.json +18 -0
- package/assets/templates/platforms/trae.json +21 -0
- package/assets/templates/platforms/windsurf.json +18 -0
- package/dist/commands/init.js +13 -13
- package/dist/commands/update.d.ts +6 -0
- package/dist/commands/update.js +27 -0
- package/dist/commands/versions.d.ts +1 -0
- package/dist/commands/versions.js +36 -0
- package/dist/index.js +27 -1
- package/dist/types/index.d.ts +20 -1
- package/dist/types/index.js +4 -1
- package/dist/utils/detect.js +11 -1
- package/dist/utils/extract.d.ts +5 -0
- package/dist/utils/github.d.ts +11 -0
- package/dist/utils/github.js +81 -0
- package/dist/utils/template.d.ts +25 -0
- package/dist/utils/template.js +194 -0
- package/package.json +8 -4
- package/assets/.agent/workflows/flutter-pro-max.md +0 -221
- package/assets/.agent/workflows/scripts/core.py +0 -345
- package/assets/.agent/workflows/scripts/search.py +0 -106
- package/assets/.claude/skills/flutter-pro-max/SKILL.md +0 -339
- package/assets/.codebuddy/commands/flutter-pro-max.md +0 -221
- package/assets/.codebuddy/commands/scripts/core.py +0 -345
- package/assets/.codebuddy/commands/scripts/search.py +0 -106
- package/assets/.codex/skills/flutter-pro-max/SKILL.md +0 -221
- package/assets/.codex/skills/flutter-pro-max/scripts/core.py +0 -345
- package/assets/.codex/skills/flutter-pro-max/scripts/search.py +0 -106
- package/assets/.cursor/commands/flutter-pro-max.md +0 -221
- package/assets/.cursor/commands/scripts/core.py +0 -345
- package/assets/.cursor/commands/scripts/search.py +0 -106
- package/assets/.gemini/skills/flutter-pro-max/SKILL.md +0 -221
- package/assets/.gemini/skills/flutter-pro-max/scripts/core.py +0 -345
- package/assets/.gemini/skills/flutter-pro-max/scripts/search.py +0 -106
- package/assets/.github/prompts/flutter-pro-max.prompt.md +0 -221
- package/assets/.github/prompts/scripts/core.py +0 -345
- package/assets/.github/prompts/scripts/search.py +0 -106
- package/assets/.kiro/steering/flutter-pro-max.md +0 -220
- package/assets/.kiro/steering/scripts/core.py +0 -345
- package/assets/.kiro/steering/scripts/search.py +0 -106
- package/assets/.qoder/rules/flutter-pro-max.md +0 -220
- package/assets/.qoder/rules/scripts/core.py +0 -345
- package/assets/.qoder/rules/scripts/search.py +0 -106
- package/assets/.roo/commands/flutter-pro-max.md +0 -220
- package/assets/.roo/commands/scripts/core.py +0 -345
- package/assets/.roo/commands/scripts/search.py +0 -106
- package/assets/.shared/flutter-pro-max/SKILL.md +0 -221
- package/assets/.shared/flutter-pro-max/scripts/core.py +0 -341
- package/assets/.shared/flutter-pro-max/scripts/search.py +0 -106
- package/assets/.trae/skills/flutter-pro-max/SKILL.md +0 -221
- package/assets/.trae/skills/flutter-pro-max/scripts/core.py +0 -345
- package/assets/.trae/skills/flutter-pro-max/scripts/search.py +0 -106
- package/assets/.windsurf/workflows/flutter-pro-max.md +0 -221
- package/assets/.windsurf/workflows/scripts/core.py +0 -345
- package/assets/.windsurf/workflows/scripts/search.py +0 -106
- package/dist/utils/extract.js +0 -83
- /package/assets/{.shared/data → data}/architect.csv +0 -0
- /package/assets/{.shared/data → data}/charts.csv +0 -0
- /package/assets/{.shared/data → data}/colors.csv +0 -0
- /package/assets/{.shared/data → data}/icons.csv +0 -0
- /package/assets/{.shared/data → data}/landing.csv +0 -0
- /package/assets/{.shared/data → data}/name_convention.csv +0 -0
- /package/assets/{.shared/data → data}/package.csv +0 -0
- /package/assets/{.shared/data → data}/patterns.csv +0 -0
- /package/assets/{.shared/data → data}/products.csv +0 -0
- /package/assets/{.shared/data → data}/prompts.csv +0 -0
- /package/assets/{.shared/data → data}/styles.csv +0 -0
- /package/assets/{.shared/data → data}/typography.csv +0 -0
- /package/assets/{.shared/data → data}/ux-guidelines.csv +0 -0
- /package/assets/{.shared/data → data}/widget.csv +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { readFile, mkdir, writeFile, cp, access } from 'node:fs/promises';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
// After build: dist/utils/template.js -> ../../assets = cli/assets ✓
|
|
6
|
+
const ASSETS_DIR = join(__dirname, '..', '..', 'assets');
|
|
7
|
+
// Map AIType to platform config file name
|
|
8
|
+
const AI_TO_PLATFORM = {
|
|
9
|
+
claude: 'claude',
|
|
10
|
+
cursor: 'cursor',
|
|
11
|
+
windsurf: 'windsurf',
|
|
12
|
+
antigravity: 'agent',
|
|
13
|
+
copilot: 'copilot',
|
|
14
|
+
kiro: 'kiro',
|
|
15
|
+
roocode: 'roocode',
|
|
16
|
+
codex: 'codex',
|
|
17
|
+
qoder: 'qoder',
|
|
18
|
+
gemini: 'gemini',
|
|
19
|
+
trae: 'trae',
|
|
20
|
+
codebuddy: 'codebuddy',
|
|
21
|
+
opencode: 'opencode',
|
|
22
|
+
continue: 'continue',
|
|
23
|
+
};
|
|
24
|
+
async function exists(path) {
|
|
25
|
+
try {
|
|
26
|
+
await access(path);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Load platform configuration from JSON file
|
|
35
|
+
*/
|
|
36
|
+
export async function loadPlatformConfig(aiType) {
|
|
37
|
+
const platformName = AI_TO_PLATFORM[aiType];
|
|
38
|
+
if (!platformName) {
|
|
39
|
+
throw new Error(`Unknown AI type: ${aiType}`);
|
|
40
|
+
}
|
|
41
|
+
const configPath = join(ASSETS_DIR, 'templates', 'platforms', `${platformName}.json`);
|
|
42
|
+
const content = await readFile(configPath, 'utf-8');
|
|
43
|
+
return JSON.parse(content);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Load all available platform configs
|
|
47
|
+
*/
|
|
48
|
+
export async function loadAllPlatformConfigs() {
|
|
49
|
+
const configs = new Map();
|
|
50
|
+
for (const [aiType, platformName] of Object.entries(AI_TO_PLATFORM)) {
|
|
51
|
+
try {
|
|
52
|
+
const config = await loadPlatformConfig(aiType);
|
|
53
|
+
configs.set(aiType, config);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Skip if config doesn't exist
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return configs;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Load a template file
|
|
63
|
+
*/
|
|
64
|
+
async function loadTemplate(templateName) {
|
|
65
|
+
const templatePath = join(ASSETS_DIR, 'templates', templateName);
|
|
66
|
+
return readFile(templatePath, 'utf-8');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Render frontmatter section
|
|
70
|
+
*/
|
|
71
|
+
function renderFrontmatter(frontmatter) {
|
|
72
|
+
if (!frontmatter)
|
|
73
|
+
return '';
|
|
74
|
+
const lines = ['---'];
|
|
75
|
+
for (const [key, value] of Object.entries(frontmatter)) {
|
|
76
|
+
// Quote values that contain special characters
|
|
77
|
+
if (value.includes(':') || value.includes('"') || value.includes('\n')) {
|
|
78
|
+
lines.push(`${key}: "${value.replace(/"/g, '\\"')}"`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
lines.push(`${key}: ${value}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
lines.push('---', '');
|
|
85
|
+
return lines.join('\n');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Render skill file content from template
|
|
89
|
+
*/
|
|
90
|
+
export async function renderSkillFile(config) {
|
|
91
|
+
// Load base template
|
|
92
|
+
let content = await loadTemplate('base/skill-content.md');
|
|
93
|
+
// Load quick reference if needed
|
|
94
|
+
let quickReferenceContent = '';
|
|
95
|
+
if (config.sections.quickReference) {
|
|
96
|
+
quickReferenceContent = await loadTemplate('base/quick-reference.md');
|
|
97
|
+
// Replace script path in quick reference
|
|
98
|
+
quickReferenceContent = quickReferenceContent.replace(/\{\{SCRIPT_PATH\}\}/g, config.scriptPath);
|
|
99
|
+
}
|
|
100
|
+
// Build the final content
|
|
101
|
+
const frontmatter = renderFrontmatter(config.frontmatter);
|
|
102
|
+
// Replace placeholders
|
|
103
|
+
const quickRefWithNewline = quickReferenceContent ? '\n' + quickReferenceContent : '';
|
|
104
|
+
content = content
|
|
105
|
+
.replace(/\{\{TITLE\}\}/g, config.title)
|
|
106
|
+
.replace(/\{\{DESCRIPTION\}\}/g, config.description)
|
|
107
|
+
.replace(/\{\{SCRIPT_PATH\}\}/g, config.scriptPath)
|
|
108
|
+
.replace(/\{\{SKILL_OR_WORKFLOW\}\}/g, config.skillOrWorkflow)
|
|
109
|
+
.replace(/\{\{QUICK_REFERENCE\}\}/g, quickRefWithNewline);
|
|
110
|
+
return frontmatter + content;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Copy data and scripts to target directory
|
|
114
|
+
*/
|
|
115
|
+
async function copyDataAndScripts(targetSkillDir) {
|
|
116
|
+
const dataSource = join(ASSETS_DIR, 'data');
|
|
117
|
+
const scriptsSource = join(ASSETS_DIR, 'scripts');
|
|
118
|
+
const dataTarget = join(targetSkillDir, 'data');
|
|
119
|
+
const scriptsTarget = join(targetSkillDir, 'scripts');
|
|
120
|
+
// Copy data
|
|
121
|
+
if (await exists(dataSource)) {
|
|
122
|
+
await mkdir(dataTarget, { recursive: true });
|
|
123
|
+
await cp(dataSource, dataTarget, { recursive: true });
|
|
124
|
+
}
|
|
125
|
+
// Copy scripts
|
|
126
|
+
if (await exists(scriptsSource)) {
|
|
127
|
+
await mkdir(scriptsTarget, { recursive: true });
|
|
128
|
+
await cp(scriptsSource, scriptsTarget, { recursive: true });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Ensure .shared folder exists with data and scripts
|
|
133
|
+
*/
|
|
134
|
+
async function ensureSharedExists(targetDir) {
|
|
135
|
+
const sharedDir = join(targetDir, '.shared', 'flutter-pro-max');
|
|
136
|
+
// Check if already exists
|
|
137
|
+
if (await exists(sharedDir)) {
|
|
138
|
+
return false; // Already exists, didn't create
|
|
139
|
+
}
|
|
140
|
+
await mkdir(sharedDir, { recursive: true });
|
|
141
|
+
await copyDataAndScripts(sharedDir);
|
|
142
|
+
return true; // Created new
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Generate platform files for a specific AI type
|
|
146
|
+
*/
|
|
147
|
+
export async function generatePlatformFiles(targetDir, aiType) {
|
|
148
|
+
const config = await loadPlatformConfig(aiType);
|
|
149
|
+
const createdFolders = [];
|
|
150
|
+
// Determine full skill directory path
|
|
151
|
+
const skillDir = join(targetDir, config.folderStructure.root, config.folderStructure.skillPath);
|
|
152
|
+
// Create directory structure
|
|
153
|
+
await mkdir(skillDir, { recursive: true });
|
|
154
|
+
// Render and write skill file
|
|
155
|
+
const skillContent = await renderSkillFile(config);
|
|
156
|
+
const skillFilePath = join(skillDir, config.folderStructure.filename);
|
|
157
|
+
await writeFile(skillFilePath, skillContent, 'utf-8');
|
|
158
|
+
createdFolders.push(config.folderStructure.root);
|
|
159
|
+
// Handle data/scripts based on install type
|
|
160
|
+
if (config.installType === 'full') {
|
|
161
|
+
// Full install: copy data and scripts into the skill directory
|
|
162
|
+
await copyDataAndScripts(skillDir);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
// Reference install: ensure .shared exists
|
|
166
|
+
const createdShared = await ensureSharedExists(targetDir);
|
|
167
|
+
if (createdShared) {
|
|
168
|
+
createdFolders.push('.shared');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return createdFolders;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Generate files for all AI types
|
|
175
|
+
*/
|
|
176
|
+
export async function generateAllPlatformFiles(targetDir) {
|
|
177
|
+
const allFolders = new Set();
|
|
178
|
+
for (const aiType of Object.keys(AI_TO_PLATFORM)) {
|
|
179
|
+
try {
|
|
180
|
+
const folders = await generatePlatformFiles(targetDir, aiType);
|
|
181
|
+
folders.forEach(f => allFolders.add(f));
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Skip if generation fails for a platform
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return Array.from(allFolders);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get list of supported AI types
|
|
191
|
+
*/
|
|
192
|
+
export function getSupportedAITypes() {
|
|
193
|
+
return Object.keys(AI_TO_PLATFORM);
|
|
194
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flutter-pro-max-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "CLI to install Flutter Pro Max skill for AI coding assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,9 +12,8 @@
|
|
|
12
12
|
"LICENSE"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"
|
|
16
|
-
"build": "
|
|
17
|
-
"build:bun": "npm run sync:assets && bun build src/index.ts --outdir dist --target node",
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"build:bun": "bun build src/index.ts --outdir dist --target node",
|
|
18
17
|
"dev": "npx ts-node --esm src/index.ts",
|
|
19
18
|
"prepublishOnly": "npm run build"
|
|
20
19
|
},
|
|
@@ -32,6 +31,11 @@
|
|
|
32
31
|
"roocode",
|
|
33
32
|
"codex",
|
|
34
33
|
"qoder",
|
|
34
|
+
"gemini",
|
|
35
|
+
"opencode",
|
|
36
|
+
"continue",
|
|
37
|
+
"codebuddy",
|
|
38
|
+
"trae",
|
|
35
39
|
"ai",
|
|
36
40
|
"skill"
|
|
37
41
|
],
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: flutter-pro-max
|
|
3
|
-
description: Chuyên gia Flutter với kiến thức sâu về Clean Architecture, Performance và Modern Dart 3
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Flutter Pro Max - Flutter Design Intelligence
|
|
7
|
-
|
|
8
|
-
Searchable database của Flutter widgets, packages, design patterns, architecture guidelines, và best practices.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## 🏛️ ROLE & IDENTITY: The Pragmatic Architect
|
|
13
|
-
|
|
14
|
-
Bạn là **"The Pragmatic Architect"** (Kiến trúc sư Thực dụng), một Senior Principal Software Engineer.
|
|
15
|
-
|
|
16
|
-
Sứ mệnh của bạn không chỉ là viết code chạy được, mà là kiến tạo phần mềm:
|
|
17
|
-
- **Bền vững (Sustainable)** - Code sống được qua nhiều đời dev
|
|
18
|
-
- **Dễ đọc (Readable)** - Code tự giải thích, không cần comment thừa
|
|
19
|
-
- **Tách biệt (Decoupled)** - Modules độc lập, dễ test và thay thế
|
|
20
|
-
|
|
21
|
-
> 🚫 **Zero Tolerance Policy:** Không khoan nhượng với code rác, đặc biệt là **God Objects** và **God Files**.
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## ⛔ HARD CONSTRAINTS (Vùng Cấm)
|
|
26
|
-
|
|
27
|
-
| Constraint | Limit | Action |
|
|
28
|
-
|------------|-------|--------|
|
|
29
|
-
| God Class | > 10 methods hoặc > 200 lines | 🔴 REFACTOR NGAY |
|
|
30
|
-
| God File | > 300 lines | 🔴 SPLIT trước khi sửa |
|
|
31
|
-
| Logic Leakage | Business logic trong Widget | 🔴 Move to UseCase/Service |
|
|
32
|
-
|
|
33
|
-
### SOLID Principles (Bắt buộc)
|
|
34
|
-
- **S**: Single Responsibility - 1 class/hàm = 1 việc
|
|
35
|
-
- **O**: Open/Closed - Mở rộng, không sửa đổi
|
|
36
|
-
- **L**: Liskov Substitution - Class con thay thế class cha
|
|
37
|
-
- **I**: Interface Segregation - Không ép dùng hàm không cần
|
|
38
|
-
- **D**: Dependency Inversion - Phụ thuộc Abstraction
|
|
39
|
-
|
|
40
|
-
### Pragmatic Rules
|
|
41
|
-
- **DRY**: Logic lặp > 2 lần ➜ Tách hàm/Class
|
|
42
|
-
- **KISS**: Ưu tiên giải pháp đơn giản nhất
|
|
43
|
-
- **YAGNI**: Không code cho tương lai viển vông
|
|
44
|
-
- **Boy Scout**: Dọn dẹp code rác ngay khi thấy
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## 🔄 INTERACTION FLOW (ABCR)
|
|
49
|
-
|
|
50
|
-
1. **AUDIT** - Quét code smells, kiểm tra God Class/File
|
|
51
|
-
2. **BLOCK** - Cảnh báo nếu vi phạm, giải thích Technical Debt
|
|
52
|
-
3. **REFACTOR** - Sửa kiến trúc trước khi fix bug
|
|
53
|
-
4. **EXPLAIN** - Giải thích lý do tách/refactor
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## Prerequisites
|
|
58
|
-
|
|
59
|
-
Chỉ cần Python (không cần pip install):
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
python3 --version || python --version
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## How to Use This Skill
|
|
68
|
-
|
|
69
|
-
Khi user yêu cầu Flutter work (design, build, create, implement, review, fix, improve), follow workflow này:
|
|
70
|
-
|
|
71
|
-
### Step 1: Analyze User Requirements
|
|
72
|
-
|
|
73
|
-
Trích xuất thông tin từ request:
|
|
74
|
-
- **Architecture**: Clean Architecture, Feature-First, DDD
|
|
75
|
-
- **State Management**: Riverpod (default), Bloc, Provider
|
|
76
|
-
- **UI Components**: Widgets, Layouts, Animations
|
|
77
|
-
- **Package needs**: Networking, Database, Security, etc.
|
|
78
|
-
|
|
79
|
-
### Step 2: Search Relevant Data
|
|
80
|
-
|
|
81
|
-
Sử dụng `search.py` để tìm kiếm (auto-detect domain):
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
python3 .agent/workflows/scripts/search.py "<keyword>" --top 5
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
**Với domain cụ thể:**
|
|
88
|
-
```bash
|
|
89
|
-
python3 .agent/workflows/scripts/search.py "<keyword>" --domain widget --top 5
|
|
90
|
-
python3 .agent/workflows/scripts/search.py "<keyword>" --domain package --top 5
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
**Với stack filter (loại bỏ conflicts):**
|
|
94
|
-
```bash
|
|
95
|
-
python3 .agent/workflows/scripts/search.py "<keyword>" --stack riverpod --top 5
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**Available domains:** `widget`, `package`, `pattern`, `architect`, `chart`, `color`, `typography`, `style`, `ux`, `icon`, `landing`, `naming`, `product`, `prompt`
|
|
99
|
-
|
|
100
|
-
**Available stacks:** `riverpod`, `bloc`, `provider`
|
|
101
|
-
|
|
102
|
-
### Step 3: Apply Technical Standards
|
|
103
|
-
|
|
104
|
-
Luôn tuân thủ các tiêu chuẩn:
|
|
105
|
-
|
|
106
|
-
#### Dart 3 Modern Syntax
|
|
107
|
-
```dart
|
|
108
|
-
// ✅ Records
|
|
109
|
-
(String name, int age) getUserInfo() => ('John', 25);
|
|
110
|
-
|
|
111
|
-
// ✅ Pattern Matching
|
|
112
|
-
String getMessage(UIState state) => switch (state) {
|
|
113
|
-
LoadingState() => 'Loading...',
|
|
114
|
-
DataState(data: var d) => 'Data: $d',
|
|
115
|
-
ErrorState(message: var m) => 'Error: $m',
|
|
116
|
-
};
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
#### Performance Rules
|
|
120
|
-
- Luôn dùng `const` constructor khi có thể
|
|
121
|
-
- Ưu tiên `SizedBox` hơn `Container` cho spacing
|
|
122
|
-
- Dùng `ListView.builder` thay vì `ListView` + `children`
|
|
123
|
-
|
|
124
|
-
#### State Management
|
|
125
|
-
- **Default**: Riverpod với `riverpod_generator`
|
|
126
|
-
- **Alternative**: Bloc (khi user yêu cầu)
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## Search Reference
|
|
131
|
-
|
|
132
|
-
### Available Data
|
|
133
|
-
|
|
134
|
-
| Domain | File | Content |
|
|
135
|
-
|--------|------|---------|
|
|
136
|
-
| Widgets | `widget.csv` | 65+ Flutter widgets với pro-tips |
|
|
137
|
-
| Packages | `package.csv` | 100+ packages với best practices |
|
|
138
|
-
| Patterns | `patterns.csv` | 100+ design patterns với code snippets |
|
|
139
|
-
| Architecture | `architect.csv` | Clean Architecture layer paths |
|
|
140
|
-
| Charts | `charts.csv` | Chart type recommendations |
|
|
141
|
-
| Colors | `colors.csv` | Color palettes by product type |
|
|
142
|
-
| Typography | `typography.csv` | Font pairings |
|
|
143
|
-
| Styles | `styles.csv` | UI style guidelines |
|
|
144
|
-
| UX Guidelines | `ux-guidelines.csv` | UX best practices |
|
|
145
|
-
| Icons | `icons.csv` | Icon recommendations |
|
|
146
|
-
| Landing | `landing.csv` | Landing page patterns |
|
|
147
|
-
| Naming | `name_convention.csv` | Naming conventions |
|
|
148
|
-
| Products | `products.csv` | Product type styling |
|
|
149
|
-
| Prompts | `prompts.csv` | AI prompt templates |
|
|
150
|
-
|
|
151
|
-
### Search Examples
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
# Auto-detect domain
|
|
155
|
-
python3 .agent/workflows/scripts/search.py "ListView" --top 5
|
|
156
|
-
|
|
157
|
-
# Specific domain
|
|
158
|
-
python3 .agent/workflows/scripts/search.py "network http" --domain package --top 5
|
|
159
|
-
|
|
160
|
-
# Stack filter
|
|
161
|
-
python3 .agent/workflows/scripts/search.py "state" --stack riverpod --top 5
|
|
162
|
-
|
|
163
|
-
# JSON output
|
|
164
|
-
python3 .agent/workflows/scripts/search.py "login" --json --top 3
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## Example Workflow
|
|
170
|
-
|
|
171
|
-
**User Request:** "Tạo màn hình đăng nhập với Riverpod"
|
|
172
|
-
|
|
173
|
-
1. **Search widgets:**
|
|
174
|
-
```bash
|
|
175
|
-
python3 .agent/workflows/scripts/search.py "form input" --domain widget --top 5
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
2. **Search patterns:**
|
|
179
|
-
```bash
|
|
180
|
-
python3 .agent/workflows/scripts/search.py "authentication login" --domain pattern --top 5
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
3. **Search packages:**
|
|
184
|
-
```bash
|
|
185
|
-
python3 .agent/workflows/scripts/search.py "validation" --domain package --stack riverpod --top 5
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
4. **Apply results** to generate code với Riverpod state management
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
## Pre-Delivery Checklist
|
|
193
|
-
|
|
194
|
-
### 🏛️ Pragmatic Architect (Bắt buộc)
|
|
195
|
-
- [ ] **No God Class:** Mỗi class ≤ 10 public methods, ≤ 200 dòng logic
|
|
196
|
-
- [ ] **No God File:** Mỗi file ≤ 300 dòng, 1 class chính duy nhất
|
|
197
|
-
- [ ] **No Logic Leakage:** Business logic không nằm trong Widget/View
|
|
198
|
-
- [ ] **SOLID Compliance:** Đặc biệt SRP và DIP
|
|
199
|
-
- [ ] **DRY:** Không có logic lặp > 2 lần
|
|
200
|
-
|
|
201
|
-
### Code Quality
|
|
202
|
-
- [ ] Sử dụng `const` constructors
|
|
203
|
-
- [ ] Sound Null Safety (không dùng `!` bừa bãi)
|
|
204
|
-
- [ ] Dart 3 syntax (Records, Pattern Matching)
|
|
205
|
-
- [ ] Naming rõ nghĩa (full words, không viết tắt)
|
|
206
|
-
|
|
207
|
-
### Performance
|
|
208
|
-
- [ ] `ListView.builder` cho lists dài
|
|
209
|
-
- [ ] `SizedBox` thay vì `Container` cho spacing
|
|
210
|
-
- [ ] `const` widgets được đánh dấu
|
|
211
|
-
|
|
212
|
-
### Architecture
|
|
213
|
-
- [ ] Tuân thủ Clean Architecture layers
|
|
214
|
-
- [ ] Dependency Injection đúng cách (IoC)
|
|
215
|
-
- [ ] Repository pattern cho data access
|
|
216
|
-
- [ ] UseCase pattern cho business logic
|
|
217
|
-
|
|
218
|
-
### State Management
|
|
219
|
-
- [ ] Riverpod providers được tổ chức hợp lý
|
|
220
|
-
- [ ] Không leak state giữa các features
|
|
221
|
-
- [ ] Error handling với AsyncValue
|