symfonia-ai-tools 1.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.
Files changed (74) hide show
  1. package/README.md +489 -0
  2. package/bin/cli.mjs +35 -0
  3. package/lib/installer.mjs +495 -0
  4. package/lib/questions.mjs +332 -0
  5. package/lib/ui.mjs +76 -0
  6. package/lib/utils.mjs +231 -0
  7. package/package.json +26 -0
  8. package/templates/base/CLAUDE.md +34 -0
  9. package/templates/base/_ai/_guidelines_header.md +70 -0
  10. package/templates/base/_ai/context/README.md +20 -0
  11. package/templates/base/_ai/prompts/codereview.prompt.md +324 -0
  12. package/templates/base/_ai/prompts/duplicate-code-analysis.prompt.md +128 -0
  13. package/templates/base/_ai/prompts/figma-analysis.prompt.md +155 -0
  14. package/templates/base/_ai/prompts/security-review.prompt.md +46 -0
  15. package/templates/base/_ai/skills/README.md +80 -0
  16. package/templates/base/_ai/skills/TEMPLATE.md +106 -0
  17. package/templates/base/_ai/skills/babysit-prs/SKILL.md +105 -0
  18. package/templates/base/_ai/skills/debug/SKILL.md +93 -0
  19. package/templates/base/_ai/skills/fill-worklogs/SKILL.md +158 -0
  20. package/templates/base/_ai/skills/hotfix/SKILL.md +52 -0
  21. package/templates/base/_ai/skills/jira-task/SKILL.md +170 -0
  22. package/templates/base/_ai/skills/my-prs/SKILL.md +78 -0
  23. package/templates/base/_ai/skills/pr-dashboard/SKILL.md +43 -0
  24. package/templates/base/_ai/skills/pr-prepare/SKILL.md +106 -0
  25. package/templates/base/_ai/skills/refactor/SKILL.md +87 -0
  26. package/templates/base/_ai/skills/write-tests/SKILL.md +109 -0
  27. package/templates/base/_claude/settings.local.json +37 -0
  28. package/templates/base/_cursor/rules/global.mdc +7 -0
  29. package/templates/base/_editorconfig +18 -0
  30. package/templates/base/_gemini/settings.json +3 -0
  31. package/templates/base/_github/copilot-instructions.md +1 -0
  32. package/templates/base/_github/pull_request_template.md +23 -0
  33. package/templates/base/_gitignore +22 -0
  34. package/templates/base/_junie/guidelines.md +1 -0
  35. package/templates/base/commit-instructions.md +92 -0
  36. package/templates/packs/docker/_ai/instructions/docker.instructions.md +193 -0
  37. package/templates/packs/docker/_guidelines.md +10 -0
  38. package/templates/packs/docker/pack.json +8 -0
  39. package/templates/packs/laravel/_ai/instructions/api-resource.instructions.md +251 -0
  40. package/templates/packs/laravel/_ai/instructions/module.instructions.md +133 -0
  41. package/templates/packs/laravel/_ai/instructions/service-repository.instructions.md +215 -0
  42. package/templates/packs/laravel/_ai/instructions/testing.instructions.md +278 -0
  43. package/templates/packs/laravel/_ai/skills/migration/SKILL.md +172 -0
  44. package/templates/packs/laravel/_ai/skills/new-endpoint/SKILL.md +165 -0
  45. package/templates/packs/laravel/_ai/skills/new-module/SKILL.md +208 -0
  46. package/templates/packs/laravel/_ai/skills/queued-job/SKILL.md +248 -0
  47. package/templates/packs/laravel/_ai/skills/testing-feature/SKILL.md +196 -0
  48. package/templates/packs/laravel/_ai/skills/testing-manual/SKILL.md +186 -0
  49. package/templates/packs/laravel/_ai/skills/testing-unit/SKILL.md +200 -0
  50. package/templates/packs/laravel/_guidelines.md +25 -0
  51. package/templates/packs/laravel/pack.json +6 -0
  52. package/templates/packs/playwright/_ai/instructions/playwright.instructions.md +219 -0
  53. package/templates/packs/playwright/_ai/skills/playwright/README.md +194 -0
  54. package/templates/packs/playwright/_ai/skills/playwright/SKILL.md +1245 -0
  55. package/templates/packs/playwright/_ai/skills/playwright-codereview/SKILL.md +642 -0
  56. package/templates/packs/playwright/_ai/skills/playwright-record/README.md +87 -0
  57. package/templates/packs/playwright/_ai/skills/playwright-record/SKILL.md +564 -0
  58. package/templates/packs/playwright/_guidelines.md +12 -0
  59. package/templates/packs/playwright/pack.json +9 -0
  60. package/templates/packs/storybook/_ai/instructions/storybook.instructions.md +181 -0
  61. package/templates/packs/storybook/pack.json +6 -0
  62. package/templates/packs/vitest/_ai/instructions/vitest.instructions.md +688 -0
  63. package/templates/packs/vitest/pack.json +6 -0
  64. package/templates/packs/vue3/_ai/instructions/api.instructions.md +163 -0
  65. package/templates/packs/vue3/_ai/instructions/coding-conventions.instructions.md +160 -0
  66. package/templates/packs/vue3/_ai/instructions/composables.instructions.md +218 -0
  67. package/templates/packs/vue3/_ai/instructions/forms.instructions.md +227 -0
  68. package/templates/packs/vue3/_ai/instructions/store.instructions.md +504 -0
  69. package/templates/packs/vue3/_ai/instructions/vue.instructions.md +339 -0
  70. package/templates/packs/vue3/_ai/skills/api-integration/SKILL.md +195 -0
  71. package/templates/packs/vue3/_ai/skills/new-component/SKILL.md +133 -0
  72. package/templates/packs/vue3/_ai/skills/new-module/SKILL.md +177 -0
  73. package/templates/packs/vue3/_guidelines.md +45 -0
  74. package/templates/packs/vue3/pack.json +11 -0
@@ -0,0 +1,504 @@
1
+ ---
2
+ applyTo: "**/*.store.ts"
3
+ ---
4
+
5
+ # Pinia Store Instructions
6
+
7
+ ## Core Pinia Store Principles
8
+
9
+ ### Architecture Rules
10
+ - **Stores handle state management ONLY** - no business logic
11
+ - **Use Composition API syntax** with `defineStore`
12
+ - **Business logic goes in composables**, not stores
13
+ - **Stores are reactive data containers** with actions for mutations
14
+ - **Follow strict TypeScript typing** - never use `any`
15
+
16
+ ### Store Structure Template
17
+ ```typescript
18
+ import { defineStore } from 'pinia'
19
+ import { ref, computed } from 'vue'
20
+ import type { IUser, IUserFilters, IUserState } from '@/types/user'
21
+
22
+ export const useUserStore = defineStore('user', () => {
23
+ // 1. State (reactive refs)
24
+ const users = ref<IUser[]>([])
25
+ const loading = ref(false)
26
+ const error = ref<string | null>(null)
27
+ const filters = ref<IUserFilters>({
28
+ search: '',
29
+ category: null,
30
+ isActive: true
31
+ })
32
+
33
+ // 2. Getters (computed properties)
34
+ const filteredUsers = computed((): IUser[] => {
35
+ return users.value.filter(user => {
36
+ const matchesSearch = !filters.value.search ||
37
+ user.name.toLowerCase().includes(filters.value.search.toLowerCase())
38
+ const matchesCategory = !filters.value.category ||
39
+ user.categoryId === filters.value.category
40
+ const matchesActive = user.isActive === filters.value.isActive
41
+
42
+ return matchesSearch && matchesCategory && matchesActive
43
+ })
44
+ })
45
+
46
+ const totalUsers = computed((): number => users.value.length)
47
+
48
+ const activeUsersCount = computed((): number =>
49
+ users.value.filter(user => user.isActive).length
50
+ )
51
+
52
+ // 3. Actions (state mutations only)
53
+ const setUsers = (newUsers: IUser[]): void => {
54
+ users.value = newUsers
55
+ }
56
+
57
+ const addUser = (user: IUser): void => {
58
+ users.value.push(user)
59
+ }
60
+
61
+ const updateUser = (userId: string, updatedUser: Partial<IUser>): void => {
62
+ const index = users.value.findIndex(user => user.id === userId)
63
+ if (index !== -1) {
64
+ users.value[index] = { ...users.value[index], ...updatedUser }
65
+ }
66
+ }
67
+
68
+ const removeUser = (userId: string): void => {
69
+ const index = users.value.findIndex(user => user.id === userId)
70
+ if (index !== -1) {
71
+ users.value.splice(index, 1)
72
+ }
73
+ }
74
+
75
+ const setLoading = (isLoading: boolean): void => {
76
+ loading.value = isLoading
77
+ }
78
+
79
+ const setError = (errorMessage: string | null): void => {
80
+ error.value = errorMessage
81
+ }
82
+
83
+ const updateFilters = (newFilters: Partial<IUserFilters>): void => {
84
+ filters.value = { ...filters.value, ...newFilters }
85
+ }
86
+
87
+ const resetFilters = (): void => {
88
+ filters.value = {
89
+ search: '',
90
+ category: null,
91
+ isActive: true
92
+ }
93
+ }
94
+
95
+ const clearError = (): void => {
96
+ error.value = null
97
+ }
98
+
99
+ const resetStore = (): void => {
100
+ users.value = []
101
+ loading.value = false
102
+ error.value = null
103
+ resetFilters()
104
+ }
105
+
106
+ // 4. Return everything that should be exposed
107
+ return {
108
+ // State
109
+ users,
110
+ loading,
111
+ error,
112
+ filters,
113
+
114
+ // Getters
115
+ filteredUsers,
116
+ totalUsers,
117
+ activeUsersCount,
118
+
119
+ // Actions
120
+ setUsers,
121
+ addUser,
122
+ updateUser,
123
+ removeUser,
124
+ setLoading,
125
+ setError,
126
+ updateFilters,
127
+ resetFilters,
128
+ clearError,
129
+ resetStore
130
+ }
131
+ })
132
+
133
+ // 5. Export type for store usage in composables
134
+ export type UserStore = ReturnType<typeof useUserStore>
135
+ ```
136
+
137
+ ## Mandatory Requirements
138
+
139
+ ### 1. TypeScript Interfaces
140
+ - **ALL state properties must be typed** with proper interfaces
141
+ - **Prefix interfaces with `I`** (e.g., `IUserState`, `IUserFilters`)
142
+ - **Export store type** for use in composables: `export type UserStore = ReturnType<typeof useUserStore>`
143
+ - **NEVER use `any` type** - strict typing required
144
+
145
+ ### 2. State Management Rules
146
+ - **Only reactive data storage** - no business logic in stores
147
+ - **Use `ref()` for state** and `computed()` for derived state
148
+ - **Actions only mutate state** - no API calls or complex logic
149
+ - **Clear separation**: state -> getters -> actions
150
+
151
+ ### 3. Naming Conventions
152
+ - **Store names**: `use[Entity]Store` (e.g., `useUserStore`, `useProductStore`)
153
+ - **File names**: `[entity].store.ts` (e.g., `user.store.ts`, `product.store.ts`)
154
+ - **State properties**: descriptive, camelCase
155
+ - **Actions**: verb-based (e.g., `setUsers`, `addUser`, `updateUser`)
156
+
157
+ ### 4. Store Organization
158
+ - **Module-specific stores**: `{{MODULE_PATH}}/stores/`
159
+ - **Global stores**: `/src/stores/`
160
+ - **One entity per store** - avoid mega-stores
161
+
162
+ ## Store Development Guidelines
163
+
164
+ ### State Definition Best Practices
165
+ ```typescript
166
+ // Good: Proper state typing and initialization
167
+ const users = ref<IUser[]>([])
168
+ const currentUser = ref<IUser | null>(null)
169
+ const loading = ref<boolean>(false)
170
+ const error = ref<string | null>(null)
171
+ const pagination = ref<IPagination>({
172
+ page: 1,
173
+ limit: 20,
174
+ total: 0
175
+ })
176
+
177
+ // Bad: No typing, unclear initialization
178
+ const data = ref()
179
+ const isLoading = ref()
180
+ const err = ref()
181
+ ```
182
+
183
+ ### Getters (Computed Properties)
184
+ ```typescript
185
+ // Good: Clear, typed computed properties
186
+ const filteredUsers = computed((): IUser[] => {
187
+ return users.value.filter(user =>
188
+ user.name.toLowerCase().includes(searchTerm.value.toLowerCase())
189
+ )
190
+ })
191
+
192
+ const hasUsers = computed((): boolean => users.value.length > 0)
193
+
194
+ const usersByCategory = computed((): Record<string, IUser[]> => {
195
+ return users.value.reduce((acc, user) => {
196
+ const category = user.category || 'unassigned'
197
+ if (!acc[category]) acc[category] = []
198
+ acc[category].push(user)
199
+ return acc
200
+ }, {} as Record<string, IUser[]>)
201
+ })
202
+ ```
203
+
204
+ ### Actions Best Practices
205
+ ```typescript
206
+ // Good: Simple state mutations
207
+ const setUsers = (newUsers: IUser[]): void => {
208
+ users.value = newUsers
209
+ }
210
+
211
+ const updateUserStatus = (userId: string, isActive: boolean): void => {
212
+ const user = users.value.find(u => u.id === userId)
213
+ if (user) {
214
+ user.isActive = isActive
215
+ }
216
+ }
217
+
218
+ // Good: Batch operations
219
+ const updateMultipleUsers = (updates: Array<{ id: string; data: Partial<IUser> }>): void => {
220
+ updates.forEach(({ id, data }) => {
221
+ const index = users.value.findIndex(user => user.id === id)
222
+ if (index !== -1) {
223
+ users.value[index] = { ...users.value[index], ...data }
224
+ }
225
+ })
226
+ }
227
+ ```
228
+
229
+ ### Error and Loading State Management
230
+ ```typescript
231
+ // Good: Consistent error/loading patterns
232
+ const setLoading = (isLoading: boolean): void => {
233
+ loading.value = isLoading
234
+ }
235
+
236
+ const setError = (errorMessage: string | null): void => {
237
+ error.value = errorMessage
238
+ if (errorMessage) {
239
+ loading.value = false
240
+ }
241
+ }
242
+
243
+ const clearError = (): void => {
244
+ error.value = null
245
+ }
246
+
247
+ // Good: Reset functionality
248
+ const resetStore = (): void => {
249
+ users.value = []
250
+ loading.value = false
251
+ error.value = null
252
+ currentUser.value = null
253
+ }
254
+ ```
255
+
256
+ ## What NOT to Do in Stores
257
+
258
+ ### Never Do This
259
+ ```typescript
260
+ // BAD: Business logic in stores
261
+ const fetchUsers = async (): Promise<void> => {
262
+ try {
263
+ loading.value = true
264
+ const response = await api.get('/users')
265
+ users.value = response.data
266
+ } catch (error) {
267
+ handleError(error)
268
+ } finally {
269
+ loading.value = false
270
+ }
271
+ }
272
+
273
+ // BAD: Complex business calculations
274
+ const calculateUserMetrics = (): void => {
275
+ // Complex business logic here
276
+ }
277
+
278
+ // BAD: Direct API calls
279
+ const saveUser = async (user: IUser): Promise<void> => {
280
+ const response = await userService.save(user)
281
+ // ...
282
+ }
283
+
284
+ // BAD: Using any type
285
+ const data = ref<any>([])
286
+
287
+ // BAD: Mega-store with multiple entities
288
+ const useAppStore = defineStore('app', () => {
289
+ const users = ref([])
290
+ const products = ref([])
291
+ const orders = ref([])
292
+ // Too many responsibilities
293
+ })
294
+ ```
295
+
296
+ ### Always Do This
297
+ ```typescript
298
+ // GOOD: Simple state mutations only
299
+ const setUsers = (newUsers: IUser[]): void => {
300
+ users.value = newUsers
301
+ }
302
+
303
+ const updateUser = (userId: string, userData: Partial<IUser>): void => {
304
+ const index = users.value.findIndex(user => user.id === userId)
305
+ if (index !== -1) {
306
+ users.value[index] = { ...users.value[index], ...userData }
307
+ }
308
+ }
309
+
310
+ // GOOD: Proper typing
311
+ const users = ref<IUser[]>([])
312
+ const loading = ref<boolean>(false)
313
+
314
+ // GOOD: Single responsibility
315
+ export const useUserStore = defineStore('user', () => {
316
+ // Only user-related state and mutations
317
+ })
318
+ ```
319
+
320
+ ## Store Integration Patterns
321
+
322
+ ### Using Stores in Composables
323
+ ```typescript
324
+ // {{MODULE_PATH}}/composables/useUserManagement.ts
325
+ import { useUserStore } from '{{MODULE_PATH}}/stores/user.store'
326
+ import { userService } from '{{MODULE_PATH}}/services/user.service'
327
+
328
+ export function useUserManagement() {
329
+ const userStore = useUserStore()
330
+
331
+ const fetchUsers = async (): Promise<void> => {
332
+ try {
333
+ userStore.setLoading(true)
334
+ userStore.clearError()
335
+
336
+ const users = await userService.getUsers()
337
+ userStore.setUsers(users)
338
+ } catch (error) {
339
+ userStore.setError('Failed to fetch users')
340
+ printError(error)
341
+ } finally {
342
+ userStore.setLoading(false)
343
+ }
344
+ }
345
+
346
+ return {
347
+ // Expose store state
348
+ users: userStore.users,
349
+ loading: userStore.loading,
350
+ error: userStore.error,
351
+
352
+ // Expose business logic
353
+ fetchUsers
354
+ }
355
+ }
356
+ ```
357
+
358
+ ### Store Communication Patterns
359
+ ```typescript
360
+ // Good: Store-to-store communication through composables
361
+ export function useUserCategorySync() {
362
+ const userStore = useUserStore()
363
+ const categoryStore = useCategoryStore()
364
+
365
+ const syncUserCategories = (): void => {
366
+ const categoryIds = userStore.users.map(user => user.categoryId)
367
+ const uniqueCategoryIds = [...new Set(categoryIds)]
368
+ categoryStore.setActiveCategories(uniqueCategoryIds)
369
+ }
370
+
371
+ return { syncUserCategories }
372
+ }
373
+ ```
374
+
375
+ ## Testing Store Requirements
376
+
377
+ ### Store Unit Testing with VITEST
378
+ ```typescript
379
+ // user.store.test.ts
380
+ import { describe, it, expect, beforeEach } from 'vitest'
381
+ import { setActivePinia, createPinia } from 'pinia'
382
+ import { useUserStore } from './user.store'
383
+
384
+ describe('User Store', () => {
385
+ beforeEach(() => {
386
+ setActivePinia(createPinia())
387
+ })
388
+
389
+ it('should initialize with empty state', () => {
390
+ const store = useUserStore()
391
+
392
+ expect(store.users).toEqual([])
393
+ expect(store.loading).toBe(false)
394
+ expect(store.error).toBe(null)
395
+ })
396
+
397
+ it('should set users correctly', () => {
398
+ const store = useUserStore()
399
+ const mockUsers = [
400
+ { id: '1', name: 'John Doe', isActive: true }
401
+ ]
402
+
403
+ store.setUsers(mockUsers)
404
+
405
+ expect(store.users).toEqual(mockUsers)
406
+ expect(store.totalUsers).toBe(1)
407
+ })
408
+
409
+ it('should filter users correctly', () => {
410
+ const store = useUserStore()
411
+ const mockUsers = [
412
+ { id: '1', name: 'John Doe', isActive: true },
413
+ { id: '2', name: 'Jane Smith', isActive: false }
414
+ ]
415
+
416
+ store.setUsers(mockUsers)
417
+ store.updateFilters({ isActive: true })
418
+
419
+ expect(store.filteredUsers).toHaveLength(1)
420
+ expect(store.filteredUsers[0].name).toBe('John Doe')
421
+ })
422
+ })
423
+ ```
424
+
425
+ ## Performance Considerations
426
+
427
+ ### Store Optimization
428
+ ```typescript
429
+ // Good: Efficient state updates
430
+ const updateUsersBatch = (updates: IUserUpdate[]): void => {
431
+ // Batch updates to minimize reactivity triggers
432
+ const updatedUsers = [...users.value]
433
+
434
+ updates.forEach(({ id, data }) => {
435
+ const index = updatedUsers.findIndex(user => user.id === id)
436
+ if (index !== -1) {
437
+ updatedUsers[index] = { ...updatedUsers[index], ...data }
438
+ }
439
+ })
440
+
441
+ users.value = updatedUsers
442
+ }
443
+
444
+ // Good: Memoized complex getters
445
+ const expensiveComputation = computed(() => {
446
+ // Use shallowRef for large datasets if needed
447
+ return users.value.reduce((acc, user) => {
448
+ // Complex calculation
449
+ return acc
450
+ }, {})
451
+ })
452
+ ```
453
+
454
+ ## File Organization Standards
455
+
456
+ ### Store File Structure
457
+ ```
458
+ src/
459
+ ├── stores/ # Global stores
460
+ │ ├── index.ts # Store exports
461
+ │ ├── auth.store.ts # Authentication store
462
+ │ └── app.store.ts # Application-wide state
463
+ └── modules/
464
+ └── user/
465
+ └── stores/ # Module-specific stores
466
+ └── user.store.ts
467
+ ```
468
+
469
+ ### Store Index File
470
+ ```typescript
471
+ // /src/stores/index.ts
472
+ export { useAuthStore } from './auth.store'
473
+ export { useAppStore } from './app.store'
474
+
475
+ // Module stores
476
+ export { useUserStore } from '{{MODULE_PATH}}/stores/user.store'
477
+ export { useProductStore } from '{{MODULE_PATH}}/stores/product.store'
478
+ ```
479
+
480
+ ## Store Persistence
481
+
482
+ ### Local Storage Integration
483
+ ```typescript
484
+ // Good: Persistence through composables, not stores
485
+ export function useUserStorePersistence() {
486
+ const userStore = useUserStore()
487
+
488
+ const saveToLocalStorage = (): void => {
489
+ localStorage.setItem('userFilters', JSON.stringify(userStore.filters))
490
+ }
491
+
492
+ const loadFromLocalStorage = (): void => {
493
+ const saved = localStorage.getItem('userFilters')
494
+ if (saved) {
495
+ const filters = JSON.parse(saved)
496
+ userStore.updateFilters(filters)
497
+ }
498
+ }
499
+
500
+ return { saveToLocalStorage, loadFromLocalStorage }
501
+ }
502
+ ```
503
+
504
+ Remember: Pinia stores are reactive data containers. Keep them simple, focused, and free of business logic. Use composables to orchestrate store operations and handle complex business requirements.