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,337 @@
1
+ # Redux Toolkit Skill
2
+
3
+ ## Store Setup
4
+ \`\`\`typescript
5
+ // store/index.ts
6
+ import { configureStore } from '@reduxjs/toolkit';
7
+ import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
8
+ import userReducer from './userSlice';
9
+ import postsReducer from './postsSlice';
10
+
11
+ export const store = configureStore({
12
+ reducer: {
13
+ user: userReducer,
14
+ posts: postsReducer,
15
+ },
16
+ middleware: (getDefaultMiddleware) =>
17
+ getDefaultMiddleware({
18
+ serializableCheck: {
19
+ // Ignore these paths in the state
20
+ ignoredPaths: ['user.lastLogin'],
21
+ },
22
+ }),
23
+ devTools: process.env.NODE_ENV !== 'production',
24
+ });
25
+
26
+ // Infer types from store
27
+ export type RootState = ReturnType<typeof store.getState>;
28
+ export type AppDispatch = typeof store.dispatch;
29
+
30
+ // Typed hooks
31
+ export const useAppDispatch: () => AppDispatch = useDispatch;
32
+ export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
33
+ \`\`\`
34
+
35
+ ## Slice Pattern
36
+ \`\`\`typescript
37
+ // store/userSlice.ts
38
+ import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
39
+ import type { RootState } from './index';
40
+
41
+ interface User {
42
+ id: string;
43
+ email: string;
44
+ name: string;
45
+ }
46
+
47
+ interface UserState {
48
+ user: User | null;
49
+ loading: boolean;
50
+ error: string | null;
51
+ }
52
+
53
+ const initialState: UserState = {
54
+ user: null,
55
+ loading: false,
56
+ error: null,
57
+ };
58
+
59
+ // Async thunk
60
+ export const fetchUser = createAsyncThunk(
61
+ 'user/fetchUser',
62
+ async (userId: string, { rejectWithValue }) => {
63
+ try {
64
+ const response = await fetch(\`/api/users/\${userId}\`);
65
+ if (!response.ok) throw new Error('User not found');
66
+ return response.json();
67
+ } catch (error) {
68
+ return rejectWithValue((error as Error).message);
69
+ }
70
+ }
71
+ );
72
+
73
+ export const updateUser = createAsyncThunk(
74
+ 'user/updateUser',
75
+ async ({ id, data }: { id: string; data: Partial<User> }, { rejectWithValue }) => {
76
+ try {
77
+ const response = await fetch(\`/api/users/\${id}\`, {
78
+ method: 'PATCH',
79
+ headers: { 'Content-Type': 'application/json' },
80
+ body: JSON.stringify(data),
81
+ });
82
+ return response.json();
83
+ } catch (error) {
84
+ return rejectWithValue((error as Error).message);
85
+ }
86
+ }
87
+ );
88
+
89
+ const userSlice = createSlice({
90
+ name: 'user',
91
+ initialState,
92
+ reducers: {
93
+ setUser: (state, action: PayloadAction<User>) => {
94
+ state.user = action.payload;
95
+ },
96
+ clearUser: (state) => {
97
+ state.user = null;
98
+ state.error = null;
99
+ },
100
+ updateUserField: (state, action: PayloadAction<{ field: keyof User; value: string }>) => {
101
+ if (state.user) {
102
+ state.user[action.payload.field] = action.payload.value;
103
+ }
104
+ },
105
+ },
106
+ extraReducers: (builder) => {
107
+ builder
108
+ // fetchUser
109
+ .addCase(fetchUser.pending, (state) => {
110
+ state.loading = true;
111
+ state.error = null;
112
+ })
113
+ .addCase(fetchUser.fulfilled, (state, action) => {
114
+ state.user = action.payload;
115
+ state.loading = false;
116
+ })
117
+ .addCase(fetchUser.rejected, (state, action) => {
118
+ state.loading = false;
119
+ state.error = action.payload as string;
120
+ })
121
+ // updateUser
122
+ .addCase(updateUser.fulfilled, (state, action) => {
123
+ state.user = action.payload;
124
+ });
125
+ },
126
+ });
127
+
128
+ export const { setUser, clearUser, updateUserField } = userSlice.actions;
129
+ export default userSlice.reducer;
130
+
131
+ // Selectors
132
+ export const selectUser = (state: RootState) => state.user.user;
133
+ export const selectUserLoading = (state: RootState) => state.user.loading;
134
+ export const selectUserError = (state: RootState) => state.user.error;
135
+ export const selectIsLoggedIn = (state: RootState) => !!state.user.user;
136
+ \`\`\`
137
+
138
+ ## Using in Components
139
+ \`\`\`tsx
140
+ import { useAppDispatch, useAppSelector } from '../store';
141
+ import { fetchUser, selectUser, selectUserLoading, clearUser } from '../store/userSlice';
142
+
143
+ function UserProfile({ userId }: { userId: string }) {
144
+ const dispatch = useAppDispatch();
145
+ const user = useAppSelector(selectUser);
146
+ const loading = useAppSelector(selectUserLoading);
147
+
148
+ useEffect(() => {
149
+ dispatch(fetchUser(userId));
150
+ }, [dispatch, userId]);
151
+
152
+ const handleLogout = () => {
153
+ dispatch(clearUser());
154
+ };
155
+
156
+ if (loading) return <div>Loading...</div>;
157
+ if (!user) return <div>No user</div>;
158
+
159
+ return (
160
+ <div>
161
+ <h1>{user.name}</h1>
162
+ <button onClick={handleLogout}>Logout</button>
163
+ </div>
164
+ );
165
+ }
166
+ \`\`\`
167
+
168
+ ## RTK Query (Data Fetching)
169
+ \`\`\`typescript
170
+ // store/api.ts
171
+ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
172
+
173
+ interface User {
174
+ id: string;
175
+ email: string;
176
+ name: string;
177
+ }
178
+
179
+ export const api = createApi({
180
+ reducerPath: 'api',
181
+ baseQuery: fetchBaseQuery({
182
+ baseUrl: '/api',
183
+ prepareHeaders: (headers, { getState }) => {
184
+ const token = (getState() as RootState).auth.token;
185
+ if (token) {
186
+ headers.set('Authorization', \`Bearer \${token}\`);
187
+ }
188
+ return headers;
189
+ },
190
+ }),
191
+ tagTypes: ['User', 'Post'],
192
+ endpoints: (builder) => ({
193
+ // Query endpoint
194
+ getUser: builder.query<User, string>({
195
+ query: (id) => \`/users/\${id}\`,
196
+ providesTags: (result, error, id) => [{ type: 'User', id }],
197
+ }),
198
+
199
+ getUsers: builder.query<User[], void>({
200
+ query: () => '/users',
201
+ providesTags: (result) =>
202
+ result
203
+ ? [...result.map(({ id }) => ({ type: 'User' as const, id })), 'User']
204
+ : ['User'],
205
+ }),
206
+
207
+ // Mutation endpoint
208
+ createUser: builder.mutation<User, Partial<User>>({
209
+ query: (body) => ({
210
+ url: '/users',
211
+ method: 'POST',
212
+ body,
213
+ }),
214
+ invalidatesTags: ['User'],
215
+ }),
216
+
217
+ updateUser: builder.mutation<User, { id: string; data: Partial<User> }>({
218
+ query: ({ id, data }) => ({
219
+ url: \`/users/\${id}\`,
220
+ method: 'PATCH',
221
+ body: data,
222
+ }),
223
+ invalidatesTags: (result, error, { id }) => [{ type: 'User', id }],
224
+ }),
225
+
226
+ deleteUser: builder.mutation<void, string>({
227
+ query: (id) => ({
228
+ url: \`/users/\${id}\`,
229
+ method: 'DELETE',
230
+ }),
231
+ invalidatesTags: (result, error, id) => [{ type: 'User', id }],
232
+ }),
233
+ }),
234
+ });
235
+
236
+ export const {
237
+ useGetUserQuery,
238
+ useGetUsersQuery,
239
+ useCreateUserMutation,
240
+ useUpdateUserMutation,
241
+ useDeleteUserMutation,
242
+ } = api;
243
+
244
+ // Add to store
245
+ export const store = configureStore({
246
+ reducer: {
247
+ [api.reducerPath]: api.reducer,
248
+ // ... other reducers
249
+ },
250
+ middleware: (getDefaultMiddleware) =>
251
+ getDefaultMiddleware().concat(api.middleware),
252
+ });
253
+ \`\`\`
254
+
255
+ ## RTK Query Usage
256
+ \`\`\`tsx
257
+ function UserList() {
258
+ const { data: users, isLoading, error, refetch } = useGetUsersQuery();
259
+ const [createUser, { isLoading: isCreating }] = useCreateUserMutation();
260
+
261
+ const handleCreate = async () => {
262
+ try {
263
+ await createUser({ email: 'new@example.com', name: 'New User' }).unwrap();
264
+ } catch (error) {
265
+ console.error('Failed to create user:', error);
266
+ }
267
+ };
268
+
269
+ if (isLoading) return <div>Loading...</div>;
270
+ if (error) return <div>Error loading users</div>;
271
+
272
+ return (
273
+ <div>
274
+ <button onClick={handleCreate} disabled={isCreating}>
275
+ Add User
276
+ </button>
277
+ <button onClick={refetch}>Refresh</button>
278
+ {users?.map((user) => (
279
+ <UserCard key={user.id} user={user} />
280
+ ))}
281
+ </div>
282
+ );
283
+ }
284
+
285
+ function UserCard({ user }: { user: User }) {
286
+ const [updateUser] = useUpdateUserMutation();
287
+ const [deleteUser] = useDeleteUserMutation();
288
+
289
+ return (
290
+ <div>
291
+ <span>{user.name}</span>
292
+ <button onClick={() => updateUser({ id: user.id, data: { name: 'Updated' } })}>
293
+ Edit
294
+ </button>
295
+ <button onClick={() => deleteUser(user.id)}>Delete</button>
296
+ </div>
297
+ );
298
+ }
299
+ \`\`\`
300
+
301
+ ## Selectors with Reselect
302
+ \`\`\`typescript
303
+ import { createSelector } from '@reduxjs/toolkit';
304
+
305
+ // Memoized selector
306
+ export const selectUserPosts = createSelector(
307
+ [selectUser, (state: RootState) => state.posts.items],
308
+ (user, posts) => posts.filter((post) => post.authorId === user?.id)
309
+ );
310
+
311
+ // Parameterized selector
312
+ export const makeSelectPostsByCategory = () =>
313
+ createSelector(
314
+ [(state: RootState) => state.posts.items, (_, category: string) => category],
315
+ (posts, category) => posts.filter((post) => post.category === category)
316
+ );
317
+
318
+ // Usage
319
+ const userPosts = useAppSelector(selectUserPosts);
320
+ const selectPostsByCategory = useMemo(makeSelectPostsByCategory, []);
321
+ const techPosts = useAppSelector((state) => selectPostsByCategory(state, 'tech'));
322
+ \`\`\`
323
+
324
+ ## ❌ DON'T
325
+ - Mutate state outside of reducers
326
+ - Put non-serializable values in state (functions, class instances)
327
+ - Use createAsyncThunk for simple fetches (use RTK Query)
328
+ - Create selectors inside components (causes re-renders)
329
+ - Dispatch in reducers
330
+
331
+ ## ✅ DO
332
+ - Use RTK Query for data fetching
333
+ - Create typed hooks (useAppDispatch, useAppSelector)
334
+ - Use createSelector for derived data
335
+ - Keep state normalized (by ID)
336
+ - Use PayloadAction for typed action payloads
337
+ - Handle all async states (pending, fulfilled, rejected)