ai-workflow-init 6.3.2 → 6.4.2

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.
@@ -0,0 +1,81 @@
1
+ # Tech Explainer Output Style
2
+
3
+ This output style is designed for explaining code, technical theories, and programming concepts.
4
+
5
+ ## Activation Behavior
6
+
7
+ **CRITICAL: On first activation of this style in a session, you MUST:**
8
+
9
+ 1. Use the `AskUserQuestion` tool to ask the user their experience level
10
+ 2. Store and remember the selection for the entire session
11
+ 3. Adapt all explanations to match the selected level
12
+
13
+ ## Experience Level Selection
14
+
15
+ Trigger this question immediately when the style is activated:
16
+
17
+ ```
18
+ Question: "What is your experience level?"
19
+ Header: "Level"
20
+ Options:
21
+ - Fresher: "Developer switching domains (e.g., Backend → Frontend). Familiar with programming but new to this specific area."
22
+ - Junior: "0-2 years experience. Still learning fundamentals and best practices."
23
+ - Middle: "2-5 years experience. Solid understanding, seeking deeper insights."
24
+ - Senior: "5+ years experience. Looking for advanced patterns and architectural considerations."
25
+ ```
26
+
27
+ ## Explanation Guidelines by Level
28
+
29
+ ### Fresher (Domain Switcher)
30
+ - **Assume:** Strong programming fundamentals, unfamiliar with domain-specific concepts
31
+ - **Focus on:** Domain terminology, ecosystem differences, transferable concepts
32
+ - **Include:** Comparisons to concepts they likely know from other domains
33
+ - **Avoid:** Explaining basic programming concepts they already understand
34
+ - **Example:** "In React, components are similar to classes in OOP - they encapsulate state and behavior. The key difference is..."
35
+
36
+ ### Junior
37
+ - **Assume:** Basic programming knowledge, limited practical experience
38
+ - **Focus on:** Step-by-step explanations, practical examples, common pitfalls
39
+ - **Include:** Code snippets with detailed comments, "why" behind decisions
40
+ - **Avoid:** Overwhelming with advanced patterns or edge cases
41
+ - **Example:** "Let me break this down step by step. First, we need to understand what a closure is..."
42
+
43
+ ### Middle
44
+ - **Assume:** Solid fundamentals, ready for deeper understanding
45
+ - **Focus on:** Trade-offs, design decisions, performance implications
46
+ - **Include:** Alternative approaches, when to use what, real-world considerations
47
+ - **Avoid:** Over-explaining basics, but clarify when introducing advanced concepts
48
+ - **Example:** "There are two common approaches here. The first uses X which is simpler but has O(n²) complexity..."
49
+
50
+ ### Senior
51
+ - **Assume:** Deep understanding, seeking nuanced insights
52
+ - **Focus on:** Architectural patterns, edge cases, scalability, advanced optimizations
53
+ - **Include:** Links to RFCs/specs, historical context, future considerations
54
+ - **Avoid:** Basic explanations unless specifically asked
55
+ - **Example:** "This pattern addresses the cache invalidation problem by using event sourcing. The trade-off is..."
56
+
57
+ ## Response Format
58
+
59
+ When explaining any technical concept:
60
+
61
+ 1. **Context First** - Why does this matter?
62
+ 2. **Core Concept** - What is it? (depth varies by level)
63
+ 3. **Practical Example** - Show it in action
64
+ 4. **Common Mistakes** - What to avoid (for Junior/Middle)
65
+ 5. **Advanced Considerations** - Deeper insights (for Middle/Senior)
66
+
67
+ ## Session Memory
68
+
69
+ Once the experience level is selected:
70
+ - Remember it for all subsequent explanations in the session
71
+ - Do not ask again unless the user requests to change it
72
+ - Prefix explanations with the current mode when relevant: `[Explaining for: Middle]`
73
+
74
+ ## Changing Experience Level
75
+
76
+ If the user wants to change their level mid-session, they can say:
77
+ - "Switch to Senior level"
78
+ - "Explain this for a Junior"
79
+ - "I'm actually a Fresher in this domain"
80
+
81
+ Update the stored preference and continue with the new level.
@@ -0,0 +1,242 @@
1
+ ---
2
+ name: UI Visualizer
3
+ description: Visualize UI layouts with ASCII wireframes, component trees, and detailed visual specs before implementation
4
+ keep-coding-instructions: true
5
+ ---
6
+
7
+ # UI Visualizer Mode
8
+
9
+ You help frontend developers visualize UI designs before implementation using text-based representations.
10
+
11
+ ## Core Visualization Techniques
12
+
13
+ ### 1. ASCII Wireframes (ALWAYS use for layouts)
14
+
15
+ Use box-drawing characters to represent UI structure:
16
+
17
+ ```
18
+ ┌─────────────────────────────────────────────────────┐
19
+ │ ┌─────────────────────────────────────────────┐ │
20
+ │ │ 🔍 Search... [🔔][👤]│ │ ← Header
21
+ │ └─────────────────────────────────────────────┘ │
22
+ ├────────────┬────────────────────────────────────────┤
23
+ │ │ │
24
+ │ 📁 Home │ ┌────────┐ ┌────────┐ ┌────────┐ │
25
+ │ 📊 Stats │ │ Card 1 │ │ Card 2 │ │ Card 3 │ │ ← Content
26
+ │ ⚙️ Config │ │ │ │ │ │ │ │
27
+ │ │ └────────┘ └────────┘ └────────┘ │
28
+ │ ← Sidebar │ │
29
+ └────────────┴────────────────────────────────────────┘
30
+ ```
31
+
32
+ ### 2. Component Hierarchy Tree
33
+
34
+ Always show structure:
35
+
36
+ ```
37
+ App
38
+ ├── Header (h-16, sticky)
39
+ │ ├── Logo
40
+ │ ├── SearchBar (flex-1)
41
+ │ └── UserMenu
42
+ ├── Sidebar (w-64, hidden@mobile)
43
+ │ └── NavItem[] (gap-2)
44
+ └── Main (flex-1, p-6)
45
+ └── CardGrid (grid, cols-3@lg)
46
+ └── Card[] (shadow-md, rounded-lg)
47
+ ```
48
+
49
+ ### 3. Visual Specs Table
50
+
51
+ For each major component, provide:
52
+
53
+ | Property | Value | Notes |
54
+ |----------|-------|-------|
55
+ | Width | 320px / 100% | Fixed on desktop, fluid on mobile |
56
+ | Height | auto (min 200px) | Content-driven |
57
+ | Padding | 24px (1.5rem) | Uses spacing scale |
58
+ | Border Radius | 12px | Consistent with design system |
59
+ | Shadow | 0 4px 6px rgba(0,0,0,0.1) | Subtle elevation |
60
+ | Background | #FFFFFF | --color-surface |
61
+
62
+ ### 4. State Variations
63
+
64
+ Show all interactive states:
65
+
66
+ ```
67
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
68
+ │ 🔘 Default │ │ 🔘 Hover │ │ 🔘 Active │
69
+ │ bg: gray-100 │ │ bg: gray-200 │ │ bg: blue-500 │
70
+ │ text: gray-700 │ │ text: gray-900 │ │ text: white │
71
+ │ border: none │ │ shadow: sm │ │ shadow: inner │
72
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
73
+
74
+ ┌─────────────────┐ ┌─────────────────┐
75
+ │ 🔘 Disabled │ │ 🔘 Loading │
76
+ │ bg: gray-50 │ │ bg: gray-100 │
77
+ │ text: gray-300 │ │ [◌ spinner] │
78
+ │ cursor: not-ok │ │ opacity: 0.7 │
79
+ └─────────────────┘ └─────────────────┘
80
+ ```
81
+
82
+ ### 5. Responsive Breakpoints
83
+
84
+ Show layout changes:
85
+
86
+ ```
87
+ 📱 Mobile (<640px) 📱 Tablet (640-1024px) 💻 Desktop (>1024px)
88
+ ┌──────────────────┐ ┌─────────────────────┐ ┌──────────────────────────┐
89
+ │ ☰ Logo [👤] │ │ Logo [Search] [👤]│ │ Logo [ Search ] [👤]│
90
+ ├──────────────────┤ ├──────┬──────────────┤ ├───────┬──────────────────┤
91
+ │ │ │ Nav │ │ │ Nav │ │
92
+ │ [ Card 1 ] │ │ │ [Card][Card] │ │ │ [Card][Card][Card]│
93
+ │ [ Card 2 ] │ │ │ [Card][Card] │ │ │ [Card][Card][Card]│
94
+ │ [ Card 3 ] │ │ │ │ │ │ │
95
+ └──────────────────┘ └──────┴──────────────┘ └───────┴──────────────────┘
96
+ (1 column) (2 columns) (3 columns)
97
+ ```
98
+
99
+ ### 6. Color & Typography Preview
100
+
101
+ ```
102
+ ┌─ Color Palette ─────────────────────────────────────┐
103
+ │ │
104
+ │ Primary: ████ #3B82F6 ████ #2563EB ████ #1D4ED8│
105
+ │ light base dark │
106
+ │ │
107
+ │ Neutral: ░░░░ #F9FAFB ▒▒▒▒ #6B7280 ████ #111827│
108
+ │ 50 500 900 │
109
+ │ │
110
+ │ Semantic: ████ #10B981 ████ #F59E0B ████ #EF4444│
111
+ │ success warning error │
112
+ └──────────────────────────────────────────────────────┘
113
+
114
+ ┌─ Typography Scale ──────────────────────────────────┐
115
+ │ xs (12px/1rem) Caption, helper text │
116
+ │ sm (14px/1.25rem) Body small, labels │
117
+ │ base (16px/1.5rem) Body text ← DEFAULT │
118
+ │ lg (18px/1.75rem) Lead paragraphs │
119
+ │ xl (20px/1.75rem) Card titles │
120
+ │ 2xl (24px/2rem) Section headers │
121
+ │ 3xl (30px/2.25rem) Page titles │
122
+ └──────────────────────────────────────────────────────┘
123
+ ```
124
+
125
+ ### 7. Animation & Interaction Notes
126
+
127
+ ```
128
+ ┌─ Interactions ──────────────────────────────────────┐
129
+ │ │
130
+ │ Hover Card: transform: translateY(-2px) │
131
+ │ transition: 150ms ease-out │
132
+ │ shadow: md → lg │
133
+ │ │
134
+ │ Button Click: scale: 1 → 0.98 → 1 │
135
+ │ duration: 100ms │
136
+ │ │
137
+ │ Modal Open: opacity: 0 → 1 │
138
+ │ transform: scale(0.95) → scale(1) │
139
+ │ backdrop: fade in 200ms │
140
+ └──────────────────────────────────────────────────────┘
141
+ ```
142
+
143
+ ## Before Writing Any UI Code
144
+
145
+ ALWAYS provide:
146
+
147
+ 1. **ASCII wireframe** of the layout
148
+ 2. **Component tree** with sizing hints
149
+ 3. **Visual specs table** for key components
150
+ 4. **Responsive behavior** diagram
151
+ 5. **State variations** for interactive elements
152
+
153
+ ## Communication Style
154
+
155
+ - Lead with visuals, explain after
156
+ - Use emoji icons (📱💻🔘✅❌) for quick scanning
157
+ - Include actual values (px, rem, hex codes)
158
+ - Show before/after for modifications
159
+ - Reference spacing scale (4, 8, 12, 16, 24, 32, 48...)
160
+
161
+ ## Example Response Format
162
+
163
+ When asked to create a component:
164
+
165
+ ```
166
+ ## 🎨 Login Card Visualization
167
+
168
+ ### Layout
169
+ ┌────────────────────────────────┐
170
+ │ Company Logo │ h: 48px
171
+ ├────────────────────────────────┤
172
+ │ │
173
+ │ ┌──────────────────────────┐ │
174
+ │ │ 📧 Email │ │ input, h: 44px
175
+ │ └──────────────────────────┘ │
176
+ │ │ gap: 16px
177
+ │ ┌──────────────────────────┐ │
178
+ │ │ 🔒 Password 👁 │ │ input + toggle
179
+ │ └──────────────────────────┘ │
180
+ │ │
181
+ │ ☑ Remember me Forgot? → │ gap: 24px
182
+ │ │
183
+ │ ┌──────────────────────────┐ │
184
+ │ │ Sign In │ │ button, primary
185
+ │ └──────────────────────────┘ │
186
+ │ │
187
+ │ ──────── or ──────── │ divider
188
+ │ │
189
+ │ ┌──────────────────────────┐ │
190
+ │ │ 🔷 Continue with Google │ │ button, outline
191
+ │ └──────────────────────────┘ │
192
+ │ │
193
+ └────────────────────────────────┘
194
+ w: 400px, p: 32px
195
+
196
+ ### Component Tree
197
+ LoginCard (w-[400px], p-8, rounded-xl, shadow-lg)
198
+ ├── Logo (h-12, mx-auto)
199
+ ├── Form (space-y-4)
200
+ │ ├── EmailInput
201
+ │ ├── PasswordInput (with visibility toggle)
202
+ │ ├── RememberRow (flex, justify-between)
203
+ │ └── SubmitButton (w-full, h-11)
204
+ ├── Divider (with "or" text)
205
+ └── SocialButtons
206
+ └── GoogleButton (outline variant)
207
+
208
+ ### Now implementing...
209
+ ```
210
+
211
+ ## Quick Preview Option
212
+
213
+ After presenting the UI visualization, **ALWAYS ask the user**:
214
+
215
+ > 🔍 **Quick Preview?** Would you like me to generate a temporary HTML file with Tailwind CSS CDN to preview this component in your browser?
216
+ >
217
+ > - **Yes** - I'll create a `/tmp/component-preview.html` file you can open
218
+ > - **No** - Continue with implementation
219
+
220
+ If user chooses **Yes**:
221
+ 1. Generate a standalone HTML file at `/tmp/component-preview.html`
222
+ 2. Include Tailwind CSS via CDN: `<script src="https://cdn.tailwindcss.com"></script>`
223
+ 3. Run the preview script: `.claude/scripts/preview-component.sh /tmp/component-preview.html`
224
+ 4. The file will auto-open in the default browser
225
+
226
+ Example preview HTML structure:
227
+ ```html
228
+ <!DOCTYPE html>
229
+ <html lang="en">
230
+ <head>
231
+ <meta charset="UTF-8">
232
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
233
+ <title>Component Preview</title>
234
+ <script src="https://cdn.tailwindcss.com"></script>
235
+ </head>
236
+ <body class="min-h-screen bg-gray-50 p-8">
237
+ <div class="max-w-4xl mx-auto">
238
+ <!-- Component code here -->
239
+ </div>
240
+ </body>
241
+ </html>
242
+ ```
@@ -0,0 +1,65 @@
1
+ #!/bin/bash
2
+ # Quick component preview - generates HTML and opens in browser
3
+ # Usage: ./preview-component.sh [filename.html]
4
+
5
+ FILE="${1:-/tmp/component-preview.html}"
6
+
7
+ # If no file provided, create from clipboard or stdin
8
+ if [ -z "$1" ]; then
9
+ echo "Creating preview at $FILE"
10
+ cat > "$FILE" << 'TEMPLATE'
11
+ <!DOCTYPE html>
12
+ <html lang="en">
13
+ <head>
14
+ <meta charset="UTF-8">
15
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
+ <title>Component Preview</title>
17
+ <script src="https://cdn.tailwindcss.com"></script>
18
+ <script>
19
+ tailwind.config = {
20
+ theme: {
21
+ extend: {
22
+ // Add your design tokens here
23
+ }
24
+ }
25
+ }
26
+ </script>
27
+ <style type="text/tailwindcss">
28
+ @layer utilities {
29
+ .debug * { outline: 1px solid red; }
30
+ }
31
+ </style>
32
+ </head>
33
+ <body class="min-h-screen bg-gray-50 p-8">
34
+ <div class="max-w-4xl mx-auto space-y-8">
35
+
36
+ <!-- PASTE YOUR COMPONENT HTML HERE -->
37
+ <div class="bg-white rounded-lg shadow-md p-6">
38
+ <h2 class="text-xl font-semibold">Preview Component</h2>
39
+ <p class="text-gray-600 mt-2">Replace this with your component code</p>
40
+ </div>
41
+
42
+ </div>
43
+
44
+ <!-- Debug toggle -->
45
+ <button
46
+ onclick="document.body.classList.toggle('debug')"
47
+ class="fixed bottom-4 right-4 bg-gray-800 text-white px-3 py-1 rounded text-sm"
48
+ >
49
+ Toggle Outlines
50
+ </button>
51
+ </body>
52
+ </html>
53
+ TEMPLATE
54
+ fi
55
+
56
+ # Open in browser (cross-platform)
57
+ if command -v xdg-open &> /dev/null; then
58
+ xdg-open "$FILE"
59
+ elif command -v open &> /dev/null; then
60
+ open "$FILE"
61
+ elif command -v start &> /dev/null; then
62
+ start "$FILE"
63
+ else
64
+ echo "Preview ready at: $FILE"
65
+ fi
@@ -0,0 +1,48 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "startup|resume|clear",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "echo REMINDER: Start EVERY response with: Skills: [list] or Skills: none"
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "PostToolUse": [
15
+ {
16
+ "matcher": "Edit",
17
+ "hooks": [
18
+ {
19
+ "type": "command",
20
+ "command": "echo %TOOL_INPUT% | findstr /C:\"docs/ai/planning/feature-\" >nul 2>&1 && echo [%DATE% %TIME%] Task updated in planning doc >> .claude/feature-progress.log || exit /b 0"
21
+ }
22
+ ]
23
+ }
24
+ ],
25
+ "Stop": [
26
+ {
27
+ "matcher": "",
28
+ "hooks": [
29
+ {
30
+ "type": "command",
31
+ "command": "powershell.exe -NoProfile -Command \"Add-Type -AssemblyName System.Windows.Forms; [void][System.Windows.Forms.MessageBox]::Show('Task completed', 'Claude Code', 0, 64)\" 2>nul || notify-send -i dialog-information 'Claude Code' 'Task completed' 2>/dev/null || osascript -e 'display notification \"Task completed\" with title \"Claude Code\"' 2>/dev/null || exit 0"
32
+ }
33
+ ]
34
+ }
35
+ ],
36
+ "Notification": [
37
+ {
38
+ "matcher": "permission_prompt",
39
+ "hooks": [
40
+ {
41
+ "type": "command",
42
+ "command": "powershell.exe -NoProfile -Command \"Add-Type -AssemblyName System.Windows.Forms; [void][System.Windows.Forms.MessageBox]::Show('Permission required - check terminal', 'Claude Code', 0, 48)\" 2>nul || notify-send -u critical -i dialog-warning 'Claude Code' 'Permission required' 2>/dev/null || exit 0"
43
+ }
44
+ ]
45
+ }
46
+ ]
47
+ }
48
+ }
@@ -12,50 +12,5 @@
12
12
  "deny": [],
13
13
  "ask": []
14
14
  },
15
- "hooks": {
16
- "SessionStart": [
17
- {
18
- "matcher": "startup|resume|clear",
19
- "hooks": [
20
- {
21
- "type": "command",
22
- "command": "echo '⚠️ REMINDER: Start EVERY response with: 📚 Skills: [list] or 📚 Skills: none'"
23
- }
24
- ]
25
- }
26
- ],
27
- "PostToolUse": [
28
- {
29
- "matcher": "Edit",
30
- "hooks": [
31
- {
32
- "type": "command",
33
- "command": "if echo \"$TOOL_INPUT\" | grep -q 'docs/ai/planning/feature-'; then echo \"[$(date '+%Y-%m-%d %H:%M:%S')] Task updated in planning doc\" >> .claude/feature-progress.log; fi"
34
- }
35
- ]
36
- }
37
- ],
38
- "Stop": [
39
- {
40
- "matcher": "",
41
- "hooks": [
42
- {
43
- "type": "command",
44
- "command": "if command -v notify-send &>/dev/null; then notify-send -i dialog-information 'Claude Code' '✅ Task completed' 2>/dev/null; elif command -v powershell.exe &>/dev/null; then powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Task completed', 'Claude Code', 'OK', 'Information')\" 2>/dev/null; elif command -v osascript &>/dev/null; then osascript -e 'display notification \"Task completed\" with title \"Claude Code\"' 2>/dev/null; fi; exit 0"
45
- }
46
- ]
47
- }
48
- ],
49
- "Notification": [
50
- {
51
- "matcher": "permission_prompt",
52
- "hooks": [
53
- {
54
- "type": "command",
55
- "command": "if command -v notify-send &>/dev/null; then notify-send -u critical -i dialog-warning 'Claude Code' '⚠️ Permission required - check terminal' 2>/dev/null; elif command -v powershell.exe &>/dev/null; then powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Permission required - check terminal', 'Claude Code', 'OK', 'Warning')\" 2>/dev/null; fi; exit 0"
56
- }
57
- ]
58
- }
59
- ]
60
- }
15
+ "outputStyle": "default"
61
16
  }
@@ -0,0 +1,519 @@
1
+ ---
2
+ name: react-best-practices
3
+ description: |
4
+ React and Next.js performance optimization guidelines from Vercel Engineering.
5
+ Contains 45 rules across 8 categories, prioritized by impact.
6
+
7
+ ALWAYS load when working with React/Next.js code:
8
+ - Writing new React components or Next.js pages
9
+ - Implementing data fetching (client or server-side)
10
+ - Reviewing code for performance issues
11
+ - Refactoring existing React/Next.js code
12
+ - Optimizing bundle size or load times
13
+ - Working with async operations and Promise handling
14
+ - Implementing Suspense boundaries or streaming
15
+
16
+ Keywords: React, Next.js, performance, optimization, bundle, async, Promise,
17
+ waterfall, rerender, memo, useMemo, useCallback, Suspense, RSC,
18
+ server components, client components, SWR, data fetching, cache
19
+
20
+ Do NOT load for:
21
+ - Non-React projects (Vue, Angular, Svelte, etc.)
22
+ - Backend-only code without React integration
23
+ - Pure CSS/styling work (use frontend-design-fundamentals)
24
+
25
+ Works with other skills:
26
+ - frontend-design-fundamentals: For UI/styling best practices
27
+ - quality-code-check: For linting and type checking
28
+ ---
29
+
30
+ # React Best Practices
31
+
32
+ Comprehensive performance optimization guide for React and Next.js applications.
33
+
34
+ ---
35
+
36
+ ## Rule Categories by Priority
37
+
38
+ | Priority | Category | Impact | Prefix |
39
+ |----------|----------|--------|--------|
40
+ | 1 | Eliminating Waterfalls | CRITICAL | `async-` |
41
+ | 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
42
+ | 3 | Server-Side Performance | HIGH | `server-` |
43
+ | 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
44
+ | 5 | Re-render Optimization | MEDIUM | `rerender-` |
45
+ | 6 | Rendering Performance | MEDIUM | `rendering-` |
46
+ | 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
47
+ | 8 | Advanced Patterns | LOW | `advanced-` |
48
+
49
+ ---
50
+
51
+ ## 1. Eliminating Waterfalls (CRITICAL)
52
+
53
+ Waterfalls are the #1 performance killer. Each sequential await adds full network latency.
54
+
55
+ ### Promise.all() for Independent Operations
56
+
57
+ **Impact:** 2-10× improvement
58
+
59
+ When async operations have no interdependencies, execute them concurrently.
60
+
61
+ **❌ Incorrect (sequential execution, 3 round trips):**
62
+
63
+ ```typescript
64
+ const user = await fetchUser()
65
+ const posts = await fetchPosts()
66
+ const comments = await fetchComments()
67
+ ```
68
+
69
+ **✅ Correct (parallel execution, 1 round trip):**
70
+
71
+ ```typescript
72
+ const [user, posts, comments] = await Promise.all([
73
+ fetchUser(),
74
+ fetchPosts(),
75
+ fetchComments()
76
+ ])
77
+ ```
78
+
79
+ ### Strategic Suspense Boundaries
80
+
81
+ **Impact:** Faster initial paint
82
+
83
+ Instead of awaiting data before returning JSX, use Suspense to show wrapper UI faster.
84
+
85
+ **❌ Incorrect (wrapper blocked by data fetching):**
86
+
87
+ ```tsx
88
+ async function Page() {
89
+ const data = await fetchData() // Blocks entire page
90
+
91
+ return (
92
+ <div>
93
+ <div>Sidebar</div>
94
+ <div>Header</div>
95
+ <div>
96
+ <DataDisplay data={data} />
97
+ </div>
98
+ <div>Footer</div>
99
+ </div>
100
+ )
101
+ }
102
+ ```
103
+
104
+ **✅ Correct (wrapper shows immediately, data streams in):**
105
+
106
+ ```tsx
107
+ function Page() {
108
+ return (
109
+ <div>
110
+ <div>Sidebar</div>
111
+ <div>Header</div>
112
+ <div>
113
+ <Suspense fallback={<Skeleton />}>
114
+ <DataDisplay />
115
+ </Suspense>
116
+ </div>
117
+ <div>Footer</div>
118
+ </div>
119
+ )
120
+ }
121
+
122
+ async function DataDisplay() {
123
+ const data = await fetchData() // Only blocks this component
124
+ return <div>{data.content}</div>
125
+ }
126
+ ```
127
+
128
+ **Alternative (share promise across components):**
129
+
130
+ ```tsx
131
+ function Page() {
132
+ const dataPromise = fetchData() // Start fetch immediately, don't await
133
+
134
+ return (
135
+ <div>
136
+ <div>Sidebar</div>
137
+ <Suspense fallback={<Skeleton />}>
138
+ <DataDisplay dataPromise={dataPromise} />
139
+ <DataSummary dataPromise={dataPromise} />
140
+ </Suspense>
141
+ </div>
142
+ )
143
+ }
144
+
145
+ function DataDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {
146
+ const data = use(dataPromise) // Unwraps the promise
147
+ return <div>{data.content}</div>
148
+ }
149
+ ```
150
+
151
+ ---
152
+
153
+ ## 2. Bundle Size Optimization (CRITICAL)
154
+
155
+ Reducing initial bundle size improves Time to Interactive and Largest Contentful Paint.
156
+
157
+ ### Avoid Barrel File Imports
158
+
159
+ **Impact:** 200-800ms import cost, slow builds
160
+
161
+ Import directly from source files instead of barrel files.
162
+
163
+ **❌ Incorrect (imports entire library):**
164
+
165
+ ```tsx
166
+ import { Check, X, Menu } from 'lucide-react'
167
+ // Loads 1,583 modules, takes ~2.8s extra in dev
168
+
169
+ import { Button, TextField } from '@mui/material'
170
+ // Loads 2,225 modules, takes ~4.2s extra in dev
171
+ ```
172
+
173
+ **✅ Correct (imports only what you need):**
174
+
175
+ ```tsx
176
+ import Check from 'lucide-react/dist/esm/icons/check'
177
+ import X from 'lucide-react/dist/esm/icons/x'
178
+ import Menu from 'lucide-react/dist/esm/icons/menu'
179
+
180
+ import Button from '@mui/material/Button'
181
+ import TextField from '@mui/material/TextField'
182
+ ```
183
+
184
+ **Alternative (Next.js 13.5+):**
185
+
186
+ ```js
187
+ // next.config.js
188
+ module.exports = {
189
+ experimental: {
190
+ optimizePackageImports: ['lucide-react', '@mui/material']
191
+ }
192
+ }
193
+ ```
194
+
195
+ **Commonly affected libraries:** `lucide-react`, `@mui/material`, `@mui/icons-material`, `@tabler/icons-react`, `react-icons`, `@headlessui/react`, `@radix-ui/react-*`, `lodash`, `date-fns`.
196
+
197
+ ### Dynamic Imports for Heavy Components
198
+
199
+ **Impact:** Directly affects TTI and LCP
200
+
201
+ Use `next/dynamic` to lazy-load large components not needed on initial render.
202
+
203
+ **❌ Incorrect (Monaco bundles with main chunk ~300KB):**
204
+
205
+ ```tsx
206
+ import { MonacoEditor } from './monaco-editor'
207
+
208
+ function CodePanel({ code }: { code: string }) {
209
+ return <MonacoEditor value={code} />
210
+ }
211
+ ```
212
+
213
+ **✅ Correct (Monaco loads on demand):**
214
+
215
+ ```tsx
216
+ import dynamic from 'next/dynamic'
217
+
218
+ const MonacoEditor = dynamic(
219
+ () => import('./monaco-editor').then(m => m.MonacoEditor),
220
+ { ssr: false }
221
+ )
222
+
223
+ function CodePanel({ code }: { code: string }) {
224
+ return <MonacoEditor value={code} />
225
+ }
226
+ ```
227
+
228
+ ---
229
+
230
+ ## 3. Server-Side Performance (HIGH)
231
+
232
+ Optimizing server-side rendering reduces response times.
233
+
234
+ ### Per-Request Deduplication with React.cache()
235
+
236
+ **Impact:** Deduplicates within request
237
+
238
+ Use `React.cache()` for server-side request deduplication.
239
+
240
+ ```typescript
241
+ import { cache } from 'react'
242
+
243
+ export const getCurrentUser = cache(async () => {
244
+ const session = await auth()
245
+ if (!session?.user?.id) return null
246
+ return await db.user.findUnique({
247
+ where: { id: session.user.id }
248
+ })
249
+ })
250
+ ```
251
+
252
+ **Avoid inline objects as arguments** - use primitives for cache hits:
253
+
254
+ ```typescript
255
+ // ❌ Always cache miss
256
+ const getUser = cache(async (params: { uid: number }) => {...})
257
+ getUser({ uid: 1 })
258
+ getUser({ uid: 1 }) // Cache miss, runs query again
259
+
260
+ // ✅ Cache hit
261
+ const getUser = cache(async (uid: number) => {...})
262
+ getUser(1)
263
+ getUser(1) // Cache hit, returns cached result
264
+ ```
265
+
266
+ **Note:** Next.js `fetch` has automatic memoization. Use `React.cache()` for:
267
+ - Database queries (Prisma, Drizzle, etc.)
268
+ - Heavy computations
269
+ - Authentication checks
270
+ - File system operations
271
+
272
+ ### Parallel Data Fetching with Component Composition
273
+
274
+ **Impact:** Eliminates server-side waterfalls
275
+
276
+ React Server Components execute sequentially within a tree. Restructure with composition to parallelize.
277
+
278
+ **❌ Incorrect (Sidebar waits for Page's fetch):**
279
+
280
+ ```tsx
281
+ export default async function Page() {
282
+ const header = await fetchHeader()
283
+ return (
284
+ <div>
285
+ <div>{header}</div>
286
+ <Sidebar />
287
+ </div>
288
+ )
289
+ }
290
+
291
+ async function Sidebar() {
292
+ const items = await fetchSidebarItems()
293
+ return <nav>{items.map(renderItem)}</nav>
294
+ }
295
+ ```
296
+
297
+ **✅ Correct (both fetch simultaneously):**
298
+
299
+ ```tsx
300
+ async function Header() {
301
+ const data = await fetchHeader()
302
+ return <div>{data}</div>
303
+ }
304
+
305
+ async function Sidebar() {
306
+ const items = await fetchSidebarItems()
307
+ return <nav>{items.map(renderItem)}</nav>
308
+ }
309
+
310
+ export default function Page() {
311
+ return (
312
+ <div>
313
+ <Header />
314
+ <Sidebar />
315
+ </div>
316
+ )
317
+ }
318
+ ```
319
+
320
+ ---
321
+
322
+ ## 4. Client-Side Data Fetching (MEDIUM-HIGH)
323
+
324
+ ### Use SWR for Automatic Deduplication
325
+
326
+ **Impact:** Automatic deduplication and caching
327
+
328
+ **❌ Incorrect (no deduplication, each instance fetches):**
329
+
330
+ ```tsx
331
+ function UserList() {
332
+ const [users, setUsers] = useState([])
333
+ useEffect(() => {
334
+ fetch('/api/users')
335
+ .then(r => r.json())
336
+ .then(setUsers)
337
+ }, [])
338
+ }
339
+ ```
340
+
341
+ **✅ Correct (multiple instances share one request):**
342
+
343
+ ```tsx
344
+ import useSWR from 'swr'
345
+
346
+ function UserList() {
347
+ const { data: users } = useSWR('/api/users', fetcher)
348
+ }
349
+ ```
350
+
351
+ ---
352
+
353
+ ## 5. Re-render Optimization (MEDIUM)
354
+
355
+ Reducing unnecessary re-renders minimizes wasted computation.
356
+
357
+ ### Extract to Memoized Components
358
+
359
+ **Impact:** Enables early returns
360
+
361
+ **❌ Incorrect (computes avatar even when loading):**
362
+
363
+ ```tsx
364
+ function Profile({ user, loading }: Props) {
365
+ const avatar = useMemo(() => {
366
+ const id = computeAvatarId(user)
367
+ return <Avatar id={id} />
368
+ }, [user])
369
+
370
+ if (loading) return <Skeleton />
371
+ return <div>{avatar}</div>
372
+ }
373
+ ```
374
+
375
+ **✅ Correct (skips computation when loading):**
376
+
377
+ ```tsx
378
+ const UserAvatar = memo(function UserAvatar({ user }: { user: User }) {
379
+ const id = useMemo(() => computeAvatarId(user), [user])
380
+ return <Avatar id={id} />
381
+ })
382
+
383
+ function Profile({ user, loading }: Props) {
384
+ if (loading) return <Skeleton />
385
+ return (
386
+ <div>
387
+ <UserAvatar user={user} />
388
+ </div>
389
+ )
390
+ }
391
+ ```
392
+
393
+ **Note:** If React Compiler is enabled, manual memoization is not necessary.
394
+
395
+ ### Subscribe to Derived State
396
+
397
+ **Impact:** Reduces re-render frequency
398
+
399
+ **❌ Incorrect (re-renders on every pixel change):**
400
+
401
+ ```tsx
402
+ function Sidebar() {
403
+ const width = useWindowWidth() // updates continuously
404
+ const isMobile = width < 768
405
+ return <nav className={isMobile ? 'mobile' : 'desktop'} />
406
+ }
407
+ ```
408
+
409
+ **✅ Correct (re-renders only when boolean changes):**
410
+
411
+ ```tsx
412
+ function Sidebar() {
413
+ const isMobile = useMediaQuery('(max-width: 767px)')
414
+ return <nav className={isMobile ? 'mobile' : 'desktop'} />
415
+ }
416
+ ```
417
+
418
+ ---
419
+
420
+ ## 6. Rendering Performance (MEDIUM)
421
+
422
+ ### Use Explicit Conditional Rendering
423
+
424
+ **Impact:** Prevents rendering 0 or NaN
425
+
426
+ **❌ Incorrect (renders "0" when count is 0):**
427
+
428
+ ```tsx
429
+ function Badge({ count }: { count: number }) {
430
+ return (
431
+ <div>
432
+ {count && <span className="badge">{count}</span>}
433
+ </div>
434
+ )
435
+ }
436
+ // When count = 0, renders: <div>0</div>
437
+ ```
438
+
439
+ **✅ Correct (renders nothing when count is 0):**
440
+
441
+ ```tsx
442
+ function Badge({ count }: { count: number }) {
443
+ return (
444
+ <div>
445
+ {count > 0 ? <span className="badge">{count}</span> : null}
446
+ </div>
447
+ )
448
+ }
449
+ ```
450
+
451
+ ---
452
+
453
+ ## 7. JavaScript Performance (LOW-MEDIUM)
454
+
455
+ Micro-optimizations for hot paths.
456
+
457
+ ### Build Index Maps for Repeated Lookups
458
+
459
+ **Impact:** 1M ops → 2K ops
460
+
461
+ **❌ Incorrect (O(n) per lookup):**
462
+
463
+ ```typescript
464
+ function processOrders(orders: Order[], users: User[]) {
465
+ return orders.map(order => ({
466
+ ...order,
467
+ user: users.find(u => u.id === order.userId)
468
+ }))
469
+ }
470
+ ```
471
+
472
+ **✅ Correct (O(1) per lookup):**
473
+
474
+ ```typescript
475
+ function processOrders(orders: Order[], users: User[]) {
476
+ const userById = new Map(users.map(u => [u.id, u]))
477
+
478
+ return orders.map(order => ({
479
+ ...order,
480
+ user: userById.get(order.userId)
481
+ }))
482
+ }
483
+ ```
484
+
485
+ ---
486
+
487
+ ## Quick Reference Checklist
488
+
489
+ ### CRITICAL Priority
490
+ - [ ] Use `Promise.all()` for independent async operations
491
+ - [ ] Avoid barrel file imports (or use `optimizePackageImports`)
492
+ - [ ] Use `next/dynamic` for heavy components
493
+ - [ ] Defer third-party scripts (analytics, logging)
494
+
495
+ ### HIGH Priority
496
+ - [ ] Use `React.cache()` for server-side deduplication
497
+ - [ ] Structure RSC for parallel data fetching
498
+ - [ ] Use Suspense boundaries strategically
499
+
500
+ ### MEDIUM Priority
501
+ - [ ] Use SWR for client-side data fetching
502
+ - [ ] Extract expensive work to memoized components
503
+ - [ ] Subscribe to derived booleans, not raw values
504
+ - [ ] Use explicit ternary for conditionals with numbers
505
+
506
+ ### LOW Priority
507
+ - [ ] Build Maps for repeated lookups
508
+ - [ ] Cache property access in loops
509
+ - [ ] Use Set/Map for O(1) lookups
510
+
511
+ ---
512
+
513
+ ## References
514
+
515
+ - [Vercel React Best Practices Repository](https://github.com/vercel-labs/agent-skills/tree/main/skills/react-best-practices)
516
+ - [React.cache documentation](https://react.dev/reference/react/cache)
517
+ - [SWR documentation](https://swr.vercel.app)
518
+ - [Next.js Package Imports Optimization](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js)
519
+ - [React Compiler](https://react.dev/learn/react-compiler)
package/cli.js CHANGED
@@ -212,7 +212,7 @@ const AI_TOOLS = [
212
212
  id: "claude",
213
213
  name: "Claude Code",
214
214
  description: "Anthropic's AI coding assistant",
215
- folders: [".claude/commands", ".claude/skills", ".claude/themes"],
215
+ folders: [".claude/commands", ".claude/skills", ".claude/themes", ".claude/output-styles", ".claude/agents"],
216
216
  },
217
217
  {
218
218
  id: "opencode",
@@ -399,62 +399,18 @@ function installClaudeCode() {
399
399
  run(`wget -qO ${claudeMdPath} ${RAW_BASE}/.claude/CLAUDE.md`);
400
400
  }
401
401
 
402
- // Create settings.json with hooks (project-level, shareable with team)
403
- step("🚚 Setting up Claude Code hooks (.claude/settings.json)...");
402
+ // Download settings.json from repo (project-level, shareable with team)
403
+ step("🚚 Downloading Claude Code hooks (.claude/settings.json)...");
404
404
  const claudeSettingsPath = ".claude/settings.json";
405
405
  if (existsSync(claudeSettingsPath)) {
406
406
  skip(`Skipping (already exists): ${claudeSettingsPath}`);
407
407
  } else {
408
- const claudeSettings = {
409
- hooks: {
410
- SessionStart: [
411
- {
412
- matcher: "startup|resume|clear",
413
- hooks: [
414
- {
415
- type: "command",
416
- command: "echo '⚠️ REMINDER: Start EVERY response with: 📚 Skills: [list] or 📚 Skills: none'"
417
- }
418
- ]
419
- }
420
- ],
421
- PostToolUse: [
422
- {
423
- matcher: "Edit",
424
- hooks: [
425
- {
426
- type: "command",
427
- command: "if echo \"$TOOL_INPUT\" | grep -q 'docs/ai/planning/feature-'; then echo \"[$(date '+%Y-%m-%d %H:%M:%S')] Task updated in planning doc\" >> .claude/feature-progress.log; fi"
428
- }
429
- ]
430
- }
431
- ],
432
- Stop: [
433
- {
434
- matcher: "",
435
- hooks: [
436
- {
437
- type: "command",
438
- command: "if command -v notify-send &>/dev/null; then notify-send -i dialog-information 'Claude Code' '✅ Task completed' 2>/dev/null; elif command -v powershell.exe &>/dev/null; then powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Task completed', 'Claude Code', 'OK', 'Information')\" 2>/dev/null; elif command -v osascript &>/dev/null; then osascript -e 'display notification \"Task completed\" with title \"Claude Code\"' 2>/dev/null; fi; exit 0"
439
- }
440
- ]
441
- }
442
- ],
443
- Notification: [
444
- {
445
- matcher: "permission_prompt",
446
- hooks: [
447
- {
448
- type: "command",
449
- command: "if command -v notify-send &>/dev/null; then notify-send -u critical -i dialog-warning 'Claude Code' '⚠️ Permission required - check terminal' 2>/dev/null; elif command -v powershell.exe &>/dev/null; then powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Permission required - check terminal', 'Claude Code', 'OK', 'Warning')\" 2>/dev/null; fi; exit 0"
450
- }
451
- ]
452
- }
453
- ]
454
- }
455
- };
456
- writeFileSync(claudeSettingsPath, JSON.stringify(claudeSettings, null, 2));
457
- success(`Created: ${claudeSettingsPath}`);
408
+ try {
409
+ run(`curl -fsSL ${RAW_BASE}/.claude/settings.json -o ${claudeSettingsPath}`);
410
+ } catch (_) {
411
+ run(`wget -qO ${claudeSettingsPath} ${RAW_BASE}/.claude/settings.json`);
412
+ }
413
+ success(`Downloaded: ${claudeSettingsPath}`);
458
414
  }
459
415
 
460
416
  // Download skills folder (always overwrite to get latest)
@@ -470,6 +426,20 @@ function installClaudeCode() {
470
426
  mkdirSync(".claude/themes", { recursive: true });
471
427
  }
472
428
  run(`npx degit ${REPO}/.claude/themes .claude/themes --force`);
429
+
430
+ // Download output-styles folder (always overwrite to get latest)
431
+ step("🚚 Downloading Claude Code output-styles (.claude/output-styles)...");
432
+ if (!existsSync(".claude/output-styles")) {
433
+ mkdirSync(".claude/output-styles", { recursive: true });
434
+ }
435
+ run(`npx degit ${REPO}/.claude/output-styles .claude/output-styles --force`);
436
+
437
+ // Download agents folder (always overwrite to get latest)
438
+ step("🚚 Downloading Claude Code agents (.claude/agents)...");
439
+ if (!existsSync(".claude/agents")) {
440
+ mkdirSync(".claude/agents", { recursive: true });
441
+ }
442
+ run(`npx degit ${REPO}/.claude/agents .claude/agents --force`);
473
443
  }
474
444
 
475
445
  // Install OpenCode
@@ -568,6 +538,66 @@ function installFactoryDroid() {
568
538
  }
569
539
  }
570
540
 
541
+ // Check and clone missing .factory subfolders (when .factory already exists)
542
+ function checkAndCloneFactory() {
543
+ if (!existsSync(".factory")) {
544
+ return; // .factory doesn't exist, skip
545
+ }
546
+
547
+ step("🔍 Checking for missing .factory subfolders...");
548
+
549
+ const factorySubfolders = [
550
+ { path: ".factory/commands", name: "commands" },
551
+ { path: ".factory/droids", name: "droids" },
552
+ { path: ".factory/skills", name: "skills" },
553
+ ];
554
+
555
+ for (const subfolder of factorySubfolders) {
556
+ if (!existsSync(subfolder.path)) {
557
+ step(`🚚 Cloning missing subfolder: ${subfolder.path}...`);
558
+ mkdirSync(subfolder.path, { recursive: true });
559
+ try {
560
+ run(`npx degit ${REPO}/${subfolder.path} ${subfolder.path} --force`);
561
+ success(`Cloned: ${subfolder.path}`);
562
+ } catch (e) {
563
+ console.log(`${colors.yellow}⚠️ ${subfolder.path} not found in repo${colors.reset}`);
564
+ }
565
+ } else {
566
+ skip(`Already exists: ${subfolder.path}`);
567
+ }
568
+ }
569
+ }
570
+
571
+ // Check and clone missing .opencode subfolders (when .opencode already exists)
572
+ function checkAndCloneOpenCode() {
573
+ if (!existsSync(".opencode")) {
574
+ return; // .opencode doesn't exist, skip
575
+ }
576
+
577
+ step("🔍 Checking for missing .opencode subfolders...");
578
+
579
+ const opencodeSubfolders = [
580
+ { path: ".opencode/agent", name: "agent" },
581
+ { path: ".opencode/command", name: "command" },
582
+ { path: ".opencode/skill", name: "skill" },
583
+ ];
584
+
585
+ for (const subfolder of opencodeSubfolders) {
586
+ if (!existsSync(subfolder.path)) {
587
+ step(`🚚 Cloning missing subfolder: ${subfolder.path}...`);
588
+ mkdirSync(subfolder.path, { recursive: true });
589
+ try {
590
+ run(`npx degit ${REPO}/${subfolder.path} ${subfolder.path} --force`);
591
+ success(`Cloned: ${subfolder.path}`);
592
+ } catch (e) {
593
+ console.log(`${colors.yellow}⚠️ ${subfolder.path} not found in repo${colors.reset}`);
594
+ }
595
+ } else {
596
+ skip(`Already exists: ${subfolder.path}`);
597
+ }
598
+ }
599
+ }
600
+
571
601
  async function main() {
572
602
  console.log(`
573
603
  ${colors.cyan}╔═══════════════════════════════════════════════════════════╗
@@ -640,6 +670,15 @@ ${colors.cyan}╔═════════════════════
640
670
  installFactoryDroid();
641
671
  }
642
672
 
673
+ // Check and clone missing subfolders for existing .factory and .opencode
674
+ // This runs regardless of tool selection, in case folders already exist
675
+ if (!toolIds.includes("factory")) {
676
+ checkAndCloneFactory();
677
+ }
678
+ if (!toolIds.includes("opencode")) {
679
+ checkAndCloneOpenCode();
680
+ }
681
+
643
682
  // Download AGENTS.md (luôn ghi đè)
644
683
  step("🚚 Downloading AGENTS.md...");
645
684
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-workflow-init",
3
- "version": "6.3.2",
3
+ "version": "6.4.2",
4
4
  "description": "Initialize AI workflow docs & commands into any repo with one command",
5
5
  "bin": {
6
6
  "ai-workflow-init": "./cli.js"