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,434 @@
1
+ # TanStack Query Skill
2
+
3
+ ## Setup
4
+ \`\`\`typescript
5
+ // app/providers.tsx
6
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
7
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
8
+
9
+ const queryClient = new QueryClient({
10
+ defaultOptions: {
11
+ queries: {
12
+ staleTime: 60 * 1000, // 1 minute
13
+ gcTime: 5 * 60 * 1000, // 5 minutes (formerly cacheTime)
14
+ retry: 3,
15
+ refetchOnWindowFocus: true,
16
+ refetchOnReconnect: true,
17
+ },
18
+ mutations: {
19
+ retry: 1,
20
+ },
21
+ },
22
+ });
23
+
24
+ export function Providers({ children }: { children: React.ReactNode }) {
25
+ return (
26
+ <QueryClientProvider client={queryClient}>
27
+ {children}
28
+ <ReactQueryDevtools initialIsOpen={false} />
29
+ </QueryClientProvider>
30
+ );
31
+ }
32
+ \`\`\`
33
+
34
+ ## Basic Queries
35
+ \`\`\`typescript
36
+ import { useQuery, useQueryClient } from '@tanstack/react-query';
37
+
38
+ // Basic query
39
+ function useUsers() {
40
+ return useQuery({
41
+ queryKey: ['users'],
42
+ queryFn: async () => {
43
+ const response = await fetch('/api/users');
44
+ if (!response.ok) throw new Error('Failed to fetch users');
45
+ return response.json() as Promise<User[]>;
46
+ },
47
+ });
48
+ }
49
+
50
+ // Query with parameters
51
+ function useUser(userId: string) {
52
+ return useQuery({
53
+ queryKey: ['user', userId],
54
+ queryFn: async () => {
55
+ const response = await fetch(\`/api/users/\${userId}\`);
56
+ if (!response.ok) throw new Error('User not found');
57
+ return response.json() as Promise<User>;
58
+ },
59
+ enabled: !!userId, // Only run if userId exists
60
+ });
61
+ }
62
+
63
+ // Usage in component
64
+ function UserProfile({ userId }: { userId: string }) {
65
+ const { data: user, isLoading, isError, error, refetch } = useUser(userId);
66
+
67
+ if (isLoading) return <div>Loading...</div>;
68
+ if (isError) return <div>Error: {error.message}</div>;
69
+
70
+ return (
71
+ <div>
72
+ <h1>{user.name}</h1>
73
+ <button onClick={() => refetch()}>Refresh</button>
74
+ </div>
75
+ );
76
+ }
77
+ \`\`\`
78
+
79
+ ## Query Options
80
+ \`\`\`typescript
81
+ function usePosts(category: string) {
82
+ return useQuery({
83
+ queryKey: ['posts', { category }],
84
+ queryFn: () => fetchPosts(category),
85
+
86
+ // Timing
87
+ staleTime: 5 * 60 * 1000, // Data fresh for 5 minutes
88
+ gcTime: 10 * 60 * 1000, // Keep in cache for 10 minutes
89
+ refetchInterval: 30 * 1000, // Poll every 30 seconds
90
+ refetchIntervalInBackground: false, // Don't poll when tab hidden
91
+
92
+ // Behavior
93
+ enabled: !!category, // Conditional fetching
94
+ retry: 3, // Retry failed requests
95
+ retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
96
+
97
+ // Data transformation
98
+ select: (data) => data.filter((post) => post.published),
99
+
100
+ // Placeholder while loading
101
+ placeholderData: (previousData) => previousData,
102
+
103
+ // Initial data from cache or static
104
+ initialData: () => queryClient.getQueryData(['posts', { category: 'all' }]),
105
+ initialDataUpdatedAt: () =>
106
+ queryClient.getQueryState(['posts', { category: 'all' }])?.dataUpdatedAt,
107
+ });
108
+ }
109
+ \`\`\`
110
+
111
+ ## Mutations
112
+ \`\`\`typescript
113
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
114
+
115
+ function useCreateUser() {
116
+ const queryClient = useQueryClient();
117
+
118
+ return useMutation({
119
+ mutationFn: async (newUser: CreateUserData) => {
120
+ const response = await fetch('/api/users', {
121
+ method: 'POST',
122
+ headers: { 'Content-Type': 'application/json' },
123
+ body: JSON.stringify(newUser),
124
+ });
125
+ if (!response.ok) throw new Error('Failed to create user');
126
+ return response.json() as Promise<User>;
127
+ },
128
+
129
+ // Callbacks
130
+ onMutate: async (newUser) => {
131
+ // Optimistic update
132
+ await queryClient.cancelQueries({ queryKey: ['users'] });
133
+ const previousUsers = queryClient.getQueryData<User[]>(['users']);
134
+
135
+ queryClient.setQueryData<User[]>(['users'], (old) => [
136
+ ...(old ?? []),
137
+ { ...newUser, id: 'temp-id' } as User,
138
+ ]);
139
+
140
+ return { previousUsers };
141
+ },
142
+
143
+ onError: (err, newUser, context) => {
144
+ // Rollback on error
145
+ queryClient.setQueryData(['users'], context?.previousUsers);
146
+ },
147
+
148
+ onSuccess: (data) => {
149
+ // Invalidate and refetch
150
+ queryClient.invalidateQueries({ queryKey: ['users'] });
151
+ },
152
+
153
+ onSettled: () => {
154
+ // Always runs (success or error)
155
+ queryClient.invalidateQueries({ queryKey: ['users'] });
156
+ },
157
+ });
158
+ }
159
+
160
+ // Usage
161
+ function CreateUserForm() {
162
+ const createUser = useCreateUser();
163
+
164
+ const handleSubmit = async (data: CreateUserData) => {
165
+ try {
166
+ await createUser.mutateAsync(data);
167
+ toast.success('User created!');
168
+ } catch (error) {
169
+ toast.error('Failed to create user');
170
+ }
171
+ };
172
+
173
+ return (
174
+ <form onSubmit={handleSubmit}>
175
+ {/* form fields */}
176
+ <button type="submit" disabled={createUser.isPending}>
177
+ {createUser.isPending ? 'Creating...' : 'Create User'}
178
+ </button>
179
+ </form>
180
+ );
181
+ }
182
+ \`\`\`
183
+
184
+ ## Optimistic Updates
185
+ \`\`\`typescript
186
+ function useUpdateTodo() {
187
+ const queryClient = useQueryClient();
188
+
189
+ return useMutation({
190
+ mutationFn: async ({ id, data }: { id: string; data: Partial<Todo> }) => {
191
+ const response = await fetch(\`/api/todos/\${id}\`, {
192
+ method: 'PATCH',
193
+ body: JSON.stringify(data),
194
+ });
195
+ return response.json();
196
+ },
197
+
198
+ onMutate: async ({ id, data }) => {
199
+ await queryClient.cancelQueries({ queryKey: ['todos'] });
200
+
201
+ const previousTodos = queryClient.getQueryData<Todo[]>(['todos']);
202
+
203
+ queryClient.setQueryData<Todo[]>(['todos'], (old) =>
204
+ old?.map((todo) =>
205
+ todo.id === id ? { ...todo, ...data } : todo
206
+ )
207
+ );
208
+
209
+ return { previousTodos };
210
+ },
211
+
212
+ onError: (err, variables, context) => {
213
+ queryClient.setQueryData(['todos'], context?.previousTodos);
214
+ },
215
+
216
+ onSettled: () => {
217
+ queryClient.invalidateQueries({ queryKey: ['todos'] });
218
+ },
219
+ });
220
+ }
221
+
222
+ // Toggle todo optimistically
223
+ function TodoItem({ todo }: { todo: Todo }) {
224
+ const updateTodo = useUpdateTodo();
225
+
226
+ return (
227
+ <div>
228
+ <input
229
+ type="checkbox"
230
+ checked={todo.completed}
231
+ onChange={() =>
232
+ updateTodo.mutate({
233
+ id: todo.id,
234
+ data: { completed: !todo.completed },
235
+ })
236
+ }
237
+ />
238
+ <span>{todo.text}</span>
239
+ </div>
240
+ );
241
+ }
242
+ \`\`\`
243
+
244
+ ## Infinite Queries (Pagination)
245
+ \`\`\`typescript
246
+ import { useInfiniteQuery } from '@tanstack/react-query';
247
+
248
+ interface PostsResponse {
249
+ posts: Post[];
250
+ nextCursor: string | null;
251
+ }
252
+
253
+ function useInfinitePosts() {
254
+ return useInfiniteQuery({
255
+ queryKey: ['posts', 'infinite'],
256
+ queryFn: async ({ pageParam }) => {
257
+ const response = await fetch(\`/api/posts?cursor=\${pageParam ?? ''}\`);
258
+ return response.json() as Promise<PostsResponse>;
259
+ },
260
+ initialPageParam: null as string | null,
261
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
262
+ getPreviousPageParam: (firstPage) => firstPage.prevCursor,
263
+ });
264
+ }
265
+
266
+ function PostFeed() {
267
+ const {
268
+ data,
269
+ fetchNextPage,
270
+ hasNextPage,
271
+ isFetchingNextPage,
272
+ isLoading,
273
+ } = useInfinitePosts();
274
+
275
+ if (isLoading) return <div>Loading...</div>;
276
+
277
+ return (
278
+ <div>
279
+ {data?.pages.map((page, i) => (
280
+ <div key={i}>
281
+ {page.posts.map((post) => (
282
+ <PostCard key={post.id} post={post} />
283
+ ))}
284
+ </div>
285
+ ))}
286
+
287
+ <button
288
+ onClick={() => fetchNextPage()}
289
+ disabled={!hasNextPage || isFetchingNextPage}
290
+ >
291
+ {isFetchingNextPage
292
+ ? 'Loading more...'
293
+ : hasNextPage
294
+ ? 'Load More'
295
+ : 'No more posts'}
296
+ </button>
297
+ </div>
298
+ );
299
+ }
300
+ \`\`\`
301
+
302
+ ## Prefetching
303
+ \`\`\`typescript
304
+ // Prefetch on hover/focus
305
+ function UserLink({ userId }: { userId: string }) {
306
+ const queryClient = useQueryClient();
307
+
308
+ const prefetchUser = () => {
309
+ queryClient.prefetchQuery({
310
+ queryKey: ['user', userId],
311
+ queryFn: () => fetchUser(userId),
312
+ staleTime: 5 * 60 * 1000,
313
+ });
314
+ };
315
+
316
+ return (
317
+ <Link
318
+ to={\`/users/\${userId}\`}
319
+ onMouseEnter={prefetchUser}
320
+ onFocus={prefetchUser}
321
+ >
322
+ View User
323
+ </Link>
324
+ );
325
+ }
326
+
327
+ // Prefetch in loader (React Router)
328
+ export const loader = async ({ params }) => {
329
+ await queryClient.prefetchQuery({
330
+ queryKey: ['user', params.userId],
331
+ queryFn: () => fetchUser(params.userId),
332
+ });
333
+ return null;
334
+ };
335
+
336
+ // Prefetch related data after main query
337
+ function useUserWithPosts(userId: string) {
338
+ const queryClient = useQueryClient();
339
+
340
+ const userQuery = useQuery({
341
+ queryKey: ['user', userId],
342
+ queryFn: () => fetchUser(userId),
343
+ });
344
+
345
+ // Prefetch posts when user loads
346
+ useEffect(() => {
347
+ if (userQuery.data) {
348
+ queryClient.prefetchQuery({
349
+ queryKey: ['user', userId, 'posts'],
350
+ queryFn: () => fetchUserPosts(userId),
351
+ });
352
+ }
353
+ }, [userQuery.data, userId, queryClient]);
354
+
355
+ return userQuery;
356
+ }
357
+ \`\`\`
358
+
359
+ ## Parallel & Dependent Queries
360
+ \`\`\`typescript
361
+ import { useQueries } from '@tanstack/react-query';
362
+
363
+ // Parallel queries
364
+ function useMultipleUsers(userIds: string[]) {
365
+ return useQueries({
366
+ queries: userIds.map((id) => ({
367
+ queryKey: ['user', id],
368
+ queryFn: () => fetchUser(id),
369
+ })),
370
+ combine: (results) => ({
371
+ data: results.map((r) => r.data),
372
+ isLoading: results.some((r) => r.isLoading),
373
+ isError: results.some((r) => r.isError),
374
+ }),
375
+ });
376
+ }
377
+
378
+ // Dependent queries
379
+ function useUserAndPosts(userId: string) {
380
+ const userQuery = useQuery({
381
+ queryKey: ['user', userId],
382
+ queryFn: () => fetchUser(userId),
383
+ });
384
+
385
+ const postsQuery = useQuery({
386
+ queryKey: ['user', userId, 'posts'],
387
+ queryFn: () => fetchUserPosts(userId),
388
+ enabled: !!userQuery.data, // Only run after user loads
389
+ });
390
+
391
+ return { userQuery, postsQuery };
392
+ }
393
+ \`\`\`
394
+
395
+ ## Cache Manipulation
396
+ \`\`\`typescript
397
+ const queryClient = useQueryClient();
398
+
399
+ // Get cached data
400
+ const users = queryClient.getQueryData<User[]>(['users']);
401
+
402
+ // Set cached data
403
+ queryClient.setQueryData<User[]>(['users'], (old) => [...(old ?? []), newUser]);
404
+
405
+ // Invalidate (mark stale, refetch if active)
406
+ queryClient.invalidateQueries({ queryKey: ['users'] });
407
+ queryClient.invalidateQueries({ queryKey: ['user', userId] });
408
+ queryClient.invalidateQueries({ queryKey: ['user'] }); // All user queries
409
+
410
+ // Remove from cache
411
+ queryClient.removeQueries({ queryKey: ['user', userId] });
412
+
413
+ // Cancel ongoing queries
414
+ await queryClient.cancelQueries({ queryKey: ['users'] });
415
+
416
+ // Refetch
417
+ queryClient.refetchQueries({ queryKey: ['users'] });
418
+ \`\`\`
419
+
420
+ ## ❌ DON'T
421
+ - Use inline queryFn (extract to named function)
422
+ - Forget to handle loading/error states
423
+ - Use same query key for different data
424
+ - Call mutations in render (use callbacks)
425
+ - Forget enabled: false for conditional queries
426
+
427
+ ## ✅ DO
428
+ - Use structured query keys (['entity', id, 'relation'])
429
+ - Set appropriate staleTime for your data
430
+ - Use optimistic updates for better UX
431
+ - Prefetch data on hover/route change
432
+ - Use select to transform/filter data
433
+ - Invalidate related queries after mutations
434
+ - Use useQueries for parallel requests