autoworkflow 3.1.5 → 3.5.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 (123) hide show
  1. package/.claude/commands/analyze.md +19 -0
  2. package/.claude/commands/audit.md +26 -0
  3. package/.claude/commands/build.md +39 -0
  4. package/.claude/commands/commit.md +25 -0
  5. package/.claude/commands/fix.md +23 -0
  6. package/.claude/commands/plan.md +18 -0
  7. package/.claude/commands/suggest.md +23 -0
  8. package/.claude/commands/verify.md +18 -0
  9. package/.claude/hooks/post-bash-router.sh +20 -0
  10. package/.claude/hooks/post-commit.sh +140 -0
  11. package/.claude/hooks/pre-edit.sh +129 -0
  12. package/.claude/hooks/session-check.sh +79 -0
  13. package/.claude/settings.json +40 -6
  14. package/.claude/settings.local.json +3 -1
  15. package/.claude/skills/actix.md +337 -0
  16. package/.claude/skills/alembic.md +504 -0
  17. package/.claude/skills/angular.md +237 -0
  18. package/.claude/skills/api-design.md +187 -0
  19. package/.claude/skills/aspnet-core.md +377 -0
  20. package/.claude/skills/astro.md +245 -0
  21. package/.claude/skills/auth-clerk.md +327 -0
  22. package/.claude/skills/auth-firebase.md +367 -0
  23. package/.claude/skills/auth-nextauth.md +359 -0
  24. package/.claude/skills/auth-supabase.md +368 -0
  25. package/.claude/skills/axum.md +386 -0
  26. package/.claude/skills/blazor.md +456 -0
  27. package/.claude/skills/chi.md +348 -0
  28. package/.claude/skills/code-review.md +133 -0
  29. package/.claude/skills/csharp.md +296 -0
  30. package/.claude/skills/css-modules.md +325 -0
  31. package/.claude/skills/cypress.md +343 -0
  32. package/.claude/skills/debugging.md +133 -0
  33. package/.claude/skills/diesel.md +392 -0
  34. package/.claude/skills/django.md +301 -0
  35. package/.claude/skills/docker.md +319 -0
  36. package/.claude/skills/doctrine.md +473 -0
  37. package/.claude/skills/documentation.md +182 -0
  38. package/.claude/skills/dotnet.md +409 -0
  39. package/.claude/skills/drizzle.md +293 -0
  40. package/.claude/skills/echo.md +321 -0
  41. package/.claude/skills/eloquent.md +256 -0
  42. package/.claude/skills/emotion.md +426 -0
  43. package/.claude/skills/entity-framework.md +370 -0
  44. package/.claude/skills/express.md +316 -0
  45. package/.claude/skills/fastapi.md +329 -0
  46. package/.claude/skills/fastify.md +299 -0
  47. package/.claude/skills/fiber.md +315 -0
  48. package/.claude/skills/flask.md +322 -0
  49. package/.claude/skills/gin.md +342 -0
  50. package/.claude/skills/git.md +116 -0
  51. package/.claude/skills/github-actions.md +353 -0
  52. package/.claude/skills/go.md +377 -0
  53. package/.claude/skills/gorm.md +409 -0
  54. package/.claude/skills/graphql.md +478 -0
  55. package/.claude/skills/hibernate.md +379 -0
  56. package/.claude/skills/hono.md +306 -0
  57. package/.claude/skills/java.md +400 -0
  58. package/.claude/skills/jest.md +313 -0
  59. package/.claude/skills/jpa.md +282 -0
  60. package/.claude/skills/kotlin.md +347 -0
  61. package/.claude/skills/kubernetes.md +363 -0
  62. package/.claude/skills/laravel.md +414 -0
  63. package/.claude/skills/mcp-browser.md +320 -0
  64. package/.claude/skills/mcp-database.md +219 -0
  65. package/.claude/skills/mcp-fetch.md +241 -0
  66. package/.claude/skills/mcp-filesystem.md +204 -0
  67. package/.claude/skills/mcp-github.md +217 -0
  68. package/.claude/skills/mcp-memory.md +240 -0
  69. package/.claude/skills/mcp-search.md +218 -0
  70. package/.claude/skills/mcp-slack.md +262 -0
  71. package/.claude/skills/micronaut.md +388 -0
  72. package/.claude/skills/mongodb.md +319 -0
  73. package/.claude/skills/mongoose.md +355 -0
  74. package/.claude/skills/mysql.md +281 -0
  75. package/.claude/skills/nestjs.md +335 -0
  76. package/.claude/skills/nextjs-app-router.md +260 -0
  77. package/.claude/skills/nextjs-pages.md +172 -0
  78. package/.claude/skills/nuxt.md +202 -0
  79. package/.claude/skills/openapi.md +489 -0
  80. package/.claude/skills/performance.md +199 -0
  81. package/.claude/skills/php.md +398 -0
  82. package/.claude/skills/playwright.md +371 -0
  83. package/.claude/skills/postgresql.md +257 -0
  84. package/.claude/skills/prisma.md +293 -0
  85. package/.claude/skills/pydantic.md +304 -0
  86. package/.claude/skills/pytest.md +313 -0
  87. package/.claude/skills/python.md +272 -0
  88. package/.claude/skills/quarkus.md +377 -0
  89. package/.claude/skills/react.md +230 -0
  90. package/.claude/skills/redis.md +391 -0
  91. package/.claude/skills/refactoring.md +143 -0
  92. package/.claude/skills/remix.md +246 -0
  93. package/.claude/skills/rest-api.md +490 -0
  94. package/.claude/skills/rocket.md +366 -0
  95. package/.claude/skills/rust.md +341 -0
  96. package/.claude/skills/sass.md +380 -0
  97. package/.claude/skills/sea-orm.md +382 -0
  98. package/.claude/skills/security.md +167 -0
  99. package/.claude/skills/sequelize.md +395 -0
  100. package/.claude/skills/spring-boot.md +416 -0
  101. package/.claude/skills/sqlalchemy.md +269 -0
  102. package/.claude/skills/sqlx-rust.md +408 -0
  103. package/.claude/skills/state-jotai.md +346 -0
  104. package/.claude/skills/state-mobx.md +353 -0
  105. package/.claude/skills/state-pinia.md +431 -0
  106. package/.claude/skills/state-redux.md +337 -0
  107. package/.claude/skills/state-tanstack-query.md +434 -0
  108. package/.claude/skills/state-zustand.md +340 -0
  109. package/.claude/skills/styled-components.md +403 -0
  110. package/.claude/skills/svelte.md +238 -0
  111. package/.claude/skills/sveltekit.md +207 -0
  112. package/.claude/skills/symfony.md +437 -0
  113. package/.claude/skills/tailwind.md +279 -0
  114. package/.claude/skills/terraform.md +394 -0
  115. package/.claude/skills/testing-library.md +371 -0
  116. package/.claude/skills/trpc.md +426 -0
  117. package/.claude/skills/typeorm.md +368 -0
  118. package/.claude/skills/vitest.md +330 -0
  119. package/.claude/skills/vue.md +202 -0
  120. package/.claude/skills/warp.md +365 -0
  121. package/README.md +135 -52
  122. package/package.json +1 -1
  123. package/system/triggers.md +152 -11
@@ -0,0 +1,431 @@
1
+ # Pinia Skill
2
+
3
+ ## Setup
4
+ \`\`\`typescript
5
+ // main.ts
6
+ import { createApp } from 'vue';
7
+ import { createPinia } from 'pinia';
8
+ import App from './App.vue';
9
+
10
+ const app = createApp(App);
11
+ const pinia = createPinia();
12
+
13
+ app.use(pinia);
14
+ app.mount('#app');
15
+ \`\`\`
16
+
17
+ ## Setup Stores (Composition API - Recommended)
18
+ \`\`\`typescript
19
+ // stores/user.ts
20
+ import { defineStore } from 'pinia';
21
+ import { ref, computed } from 'vue';
22
+
23
+ interface User {
24
+ id: string;
25
+ email: string;
26
+ name: string;
27
+ }
28
+
29
+ export const useUserStore = defineStore('user', () => {
30
+ // State (refs)
31
+ const user = ref<User | null>(null);
32
+ const loading = ref(false);
33
+ const error = ref<string | null>(null);
34
+
35
+ // Getters (computed)
36
+ const isLoggedIn = computed(() => !!user.value);
37
+ const userName = computed(() => user.value?.name ?? 'Guest');
38
+
39
+ // Actions (functions)
40
+ async function login(email: string, password: string) {
41
+ loading.value = true;
42
+ error.value = null;
43
+
44
+ try {
45
+ const response = await fetch('/api/auth/login', {
46
+ method: 'POST',
47
+ headers: { 'Content-Type': 'application/json' },
48
+ body: JSON.stringify({ email, password }),
49
+ });
50
+
51
+ if (!response.ok) throw new Error('Login failed');
52
+
53
+ user.value = await response.json();
54
+ } catch (e) {
55
+ error.value = (e as Error).message;
56
+ throw e;
57
+ } finally {
58
+ loading.value = false;
59
+ }
60
+ }
61
+
62
+ async function logout() {
63
+ await fetch('/api/auth/logout', { method: 'POST' });
64
+ user.value = null;
65
+ }
66
+
67
+ function updateProfile(data: Partial<User>) {
68
+ if (user.value) {
69
+ user.value = { ...user.value, ...data };
70
+ }
71
+ }
72
+
73
+ // Return everything that should be exposed
74
+ return {
75
+ // State
76
+ user,
77
+ loading,
78
+ error,
79
+ // Getters
80
+ isLoggedIn,
81
+ userName,
82
+ // Actions
83
+ login,
84
+ logout,
85
+ updateProfile,
86
+ };
87
+ });
88
+ \`\`\`
89
+
90
+ ## Options Stores (Options API)
91
+ \`\`\`typescript
92
+ // stores/cart.ts
93
+ import { defineStore } from 'pinia';
94
+
95
+ interface CartItem {
96
+ id: string;
97
+ name: string;
98
+ price: number;
99
+ quantity: number;
100
+ }
101
+
102
+ export const useCartStore = defineStore('cart', {
103
+ // State
104
+ state: () => ({
105
+ items: [] as CartItem[],
106
+ coupon: null as string | null,
107
+ }),
108
+
109
+ // Getters
110
+ getters: {
111
+ totalItems: (state) => state.items.reduce((sum, item) => sum + item.quantity, 0),
112
+
113
+ totalPrice: (state) =>
114
+ state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
115
+
116
+ // Getter using other getters
117
+ formattedTotal(): string {
118
+ return \`$\${this.totalPrice.toFixed(2)}\`;
119
+ },
120
+
121
+ // Getter with parameters
122
+ getItemById: (state) => (id: string) =>
123
+ state.items.find((item) => item.id === id),
124
+ },
125
+
126
+ // Actions
127
+ actions: {
128
+ addItem(item: Omit<CartItem, 'quantity'>) {
129
+ const existing = this.items.find((i) => i.id === item.id);
130
+ if (existing) {
131
+ existing.quantity++;
132
+ } else {
133
+ this.items.push({ ...item, quantity: 1 });
134
+ }
135
+ },
136
+
137
+ removeItem(id: string) {
138
+ const index = this.items.findIndex((item) => item.id === id);
139
+ if (index !== -1) {
140
+ this.items.splice(index, 1);
141
+ }
142
+ },
143
+
144
+ updateQuantity(id: string, quantity: number) {
145
+ const item = this.items.find((i) => i.id === id);
146
+ if (item) {
147
+ item.quantity = Math.max(0, quantity);
148
+ if (item.quantity === 0) {
149
+ this.removeItem(id);
150
+ }
151
+ }
152
+ },
153
+
154
+ clearCart() {
155
+ this.items = [];
156
+ this.coupon = null;
157
+ },
158
+
159
+ // Async action
160
+ async applyCoupon(code: string) {
161
+ const response = await fetch(\`/api/coupons/\${code}\`);
162
+ if (response.ok) {
163
+ this.coupon = code;
164
+ }
165
+ },
166
+ },
167
+ });
168
+ \`\`\`
169
+
170
+ ## Usage in Components
171
+ \`\`\`vue
172
+ <script setup lang="ts">
173
+ import { useUserStore } from '@/stores/user';
174
+ import { useCartStore } from '@/stores/cart';
175
+ import { storeToRefs } from 'pinia';
176
+
177
+ // Setup store usage
178
+ const userStore = useUserStore();
179
+ const cartStore = useCartStore();
180
+
181
+ // Destructure reactive state (use storeToRefs to keep reactivity)
182
+ const { user, loading, isLoggedIn } = storeToRefs(userStore);
183
+
184
+ // Actions can be destructured directly
185
+ const { login, logout } = userStore;
186
+
187
+ // Getters
188
+ const { totalItems, formattedTotal } = storeToRefs(cartStore);
189
+
190
+ // Direct access
191
+ const handleLogin = async () => {
192
+ await userStore.login(email.value, password.value);
193
+ };
194
+
195
+ // Watch store changes
196
+ watch(
197
+ () => userStore.user,
198
+ (newUser) => {
199
+ console.log('User changed:', newUser);
200
+ }
201
+ );
202
+ </script>
203
+
204
+ <template>
205
+ <div>
206
+ <div v-if="loading">Loading...</div>
207
+ <div v-else-if="isLoggedIn">
208
+ Welcome, {{ user?.name }}
209
+ <button @click="logout">Logout</button>
210
+ </div>
211
+ <div v-else>
212
+ <button @click="handleLogin">Login</button>
213
+ </div>
214
+
215
+ <div>Cart: {{ totalItems }} items ({{ formattedTotal }})</div>
216
+ </div>
217
+ </template>
218
+ \`\`\`
219
+
220
+ ## Store Composition (Using Other Stores)
221
+ \`\`\`typescript
222
+ // stores/checkout.ts
223
+ import { defineStore } from 'pinia';
224
+ import { useUserStore } from './user';
225
+ import { useCartStore } from './cart';
226
+
227
+ export const useCheckoutStore = defineStore('checkout', () => {
228
+ const userStore = useUserStore();
229
+ const cartStore = useCartStore();
230
+
231
+ const canCheckout = computed(() =>
232
+ userStore.isLoggedIn && cartStore.totalItems > 0
233
+ );
234
+
235
+ async function processCheckout() {
236
+ if (!canCheckout.value) {
237
+ throw new Error('Cannot checkout');
238
+ }
239
+
240
+ const order = {
241
+ userId: userStore.user!.id,
242
+ items: cartStore.items,
243
+ total: cartStore.totalPrice,
244
+ };
245
+
246
+ const response = await fetch('/api/orders', {
247
+ method: 'POST',
248
+ body: JSON.stringify(order),
249
+ });
250
+
251
+ if (response.ok) {
252
+ cartStore.clearCart();
253
+ return response.json();
254
+ }
255
+
256
+ throw new Error('Checkout failed');
257
+ }
258
+
259
+ return { canCheckout, processCheckout };
260
+ });
261
+ \`\`\`
262
+
263
+ ## Plugins
264
+
265
+ ### Persistence Plugin
266
+ \`\`\`typescript
267
+ // plugins/piniaPersistedState.ts
268
+ import { createPinia } from 'pinia';
269
+ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
270
+
271
+ const pinia = createPinia();
272
+ pinia.use(piniaPluginPersistedstate);
273
+
274
+ // In store
275
+ export const useUserStore = defineStore('user', () => {
276
+ const user = ref<User | null>(null);
277
+ // ...
278
+ return { user };
279
+ }, {
280
+ persist: true, // Persist entire store
281
+
282
+ // Or with options
283
+ persist: {
284
+ key: 'user-store',
285
+ storage: sessionStorage, // Default: localStorage
286
+ paths: ['user'], // Only persist specific paths
287
+ },
288
+ });
289
+ \`\`\`
290
+
291
+ ### Custom Plugin
292
+ \`\`\`typescript
293
+ // plugins/logger.ts
294
+ import { PiniaPluginContext } from 'pinia';
295
+
296
+ export function loggerPlugin({ store }: PiniaPluginContext) {
297
+ store.$subscribe((mutation, state) => {
298
+ console.log(\`[\${mutation.storeId}] \${mutation.type}\`, state);
299
+ });
300
+
301
+ store.$onAction(({ name, store, args, after, onError }) => {
302
+ console.log(\`Action "\${name}" started on \${store.$id}\`);
303
+
304
+ after((result) => {
305
+ console.log(\`Action "\${name}" finished. Result:\`, result);
306
+ });
307
+
308
+ onError((error) => {
309
+ console.error(\`Action "\${name}" failed:\`, error);
310
+ });
311
+ });
312
+ }
313
+
314
+ // Register plugin
315
+ pinia.use(loggerPlugin);
316
+ \`\`\`
317
+
318
+ ## Reset Store
319
+ \`\`\`typescript
320
+ // Setup store - manual reset
321
+ export const useUserStore = defineStore('user', () => {
322
+ const initialState = {
323
+ user: null as User | null,
324
+ loading: false,
325
+ error: null as string | null,
326
+ };
327
+
328
+ const user = ref(initialState.user);
329
+ const loading = ref(initialState.loading);
330
+ const error = ref(initialState.error);
331
+
332
+ function $reset() {
333
+ user.value = initialState.user;
334
+ loading.value = initialState.loading;
335
+ error.value = initialState.error;
336
+ }
337
+
338
+ return { user, loading, error, $reset };
339
+ });
340
+
341
+ // Options store - $reset is automatic
342
+ const cartStore = useCartStore();
343
+ cartStore.$reset(); // Resets to initial state
344
+ \`\`\`
345
+
346
+ ## Testing
347
+ \`\`\`typescript
348
+ import { setActivePinia, createPinia } from 'pinia';
349
+ import { useUserStore } from '@/stores/user';
350
+
351
+ describe('User Store', () => {
352
+ beforeEach(() => {
353
+ setActivePinia(createPinia());
354
+ });
355
+
356
+ it('should login user', async () => {
357
+ const store = useUserStore();
358
+
359
+ expect(store.isLoggedIn).toBe(false);
360
+
361
+ // Mock fetch
362
+ global.fetch = vi.fn().mockResolvedValue({
363
+ ok: true,
364
+ json: () => Promise.resolve({ id: '1', name: 'John', email: 'john@example.com' }),
365
+ });
366
+
367
+ await store.login('john@example.com', 'password');
368
+
369
+ expect(store.isLoggedIn).toBe(true);
370
+ expect(store.user?.name).toBe('John');
371
+ });
372
+
373
+ it('should handle login error', async () => {
374
+ const store = useUserStore();
375
+
376
+ global.fetch = vi.fn().mockResolvedValue({
377
+ ok: false,
378
+ });
379
+
380
+ await expect(store.login('test@example.com', 'wrong')).rejects.toThrow();
381
+ expect(store.error).toBe('Login failed');
382
+ });
383
+ });
384
+ \`\`\`
385
+
386
+ ## Outside Components
387
+ \`\`\`typescript
388
+ // router/guards.ts
389
+ import { useUserStore } from '@/stores/user';
390
+ import type { Router } from 'vue-router';
391
+
392
+ export function setupGuards(router: Router) {
393
+ router.beforeEach((to) => {
394
+ // Must be called after pinia is installed
395
+ const userStore = useUserStore();
396
+
397
+ if (to.meta.requiresAuth && !userStore.isLoggedIn) {
398
+ return { name: 'login', query: { redirect: to.fullPath } };
399
+ }
400
+ });
401
+ }
402
+
403
+ // api/client.ts
404
+ import { useUserStore } from '@/stores/user';
405
+
406
+ export async function apiClient(url: string, options?: RequestInit) {
407
+ const userStore = useUserStore();
408
+
409
+ return fetch(url, {
410
+ ...options,
411
+ headers: {
412
+ ...options?.headers,
413
+ Authorization: userStore.user ? \`Bearer \${userStore.token}\` : '',
414
+ },
415
+ });
416
+ }
417
+ \`\`\`
418
+
419
+ ## ❌ DON'T
420
+ - Destructure state directly (loses reactivity)
421
+ - Mutate state outside actions
422
+ - Create stores inside components
423
+ - Forget to use storeToRefs for reactive destructuring
424
+
425
+ ## ✅ DO
426
+ - Use Setup Stores for better TypeScript support
427
+ - Use storeToRefs when destructuring state/getters
428
+ - Use store composition for related stores
429
+ - Use persistence plugin for localStorage sync
430
+ - Reset stores in tests with setActivePinia
431
+ - Define $reset manually for Setup Stores