autoworkflow 3.1.4 → 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 +174 -11
  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,426 @@
1
+ # tRPC Skill
2
+
3
+ ## Project Setup
4
+ \`\`\`typescript
5
+ // server/trpc.ts
6
+ import { initTRPC, TRPCError } from '@trpc/server';
7
+ import { type Context } from './context';
8
+ import superjson from 'superjson';
9
+ import { ZodError } from 'zod';
10
+
11
+ const t = initTRPC.context<Context>().create({
12
+ transformer: superjson,
13
+ errorFormatter({ shape, error }) {
14
+ return {
15
+ ...shape,
16
+ data: {
17
+ ...shape.data,
18
+ zodError:
19
+ error.cause instanceof ZodError ? error.cause.flatten() : null,
20
+ },
21
+ };
22
+ },
23
+ });
24
+
25
+ export const router = t.router;
26
+ export const publicProcedure = t.procedure;
27
+ export const middleware = t.middleware;
28
+ export const mergeRouters = t.mergeRouters;
29
+ \`\`\`
30
+
31
+ ## Context
32
+ \`\`\`typescript
33
+ // server/context.ts
34
+ import { type inferAsyncReturnType } from '@trpc/server';
35
+ import { type CreateNextContextOptions } from '@trpc/server/adapters/next';
36
+ import { getServerSession } from 'next-auth';
37
+ import { prisma } from './db';
38
+ import { authOptions } from './auth';
39
+
40
+ export async function createContext(opts: CreateNextContextOptions) {
41
+ const session = await getServerSession(opts.req, opts.res, authOptions);
42
+
43
+ return {
44
+ prisma,
45
+ session,
46
+ user: session?.user,
47
+ };
48
+ }
49
+
50
+ export type Context = inferAsyncReturnType<typeof createContext>;
51
+ \`\`\`
52
+
53
+ ## Middleware
54
+ \`\`\`typescript
55
+ // server/middleware.ts
56
+ import { TRPCError } from '@trpc/server';
57
+ import { middleware, publicProcedure } from './trpc';
58
+
59
+ // Logging middleware
60
+ const loggerMiddleware = middleware(async ({ path, type, next }) => {
61
+ const start = Date.now();
62
+ const result = await next();
63
+ const duration = Date.now() - start;
64
+ console.log(\`[\${type}] \${path} - \${duration}ms\`);
65
+ return result;
66
+ });
67
+
68
+ // Auth middleware
69
+ const isAuthed = middleware(async ({ ctx, next }) => {
70
+ if (!ctx.session || !ctx.user) {
71
+ throw new TRPCError({
72
+ code: 'UNAUTHORIZED',
73
+ message: 'Not authenticated',
74
+ });
75
+ }
76
+ return next({
77
+ ctx: {
78
+ ...ctx,
79
+ user: ctx.user, // user is now non-nullable
80
+ },
81
+ });
82
+ });
83
+
84
+ // Role middleware
85
+ const hasRole = (role: string) =>
86
+ middleware(async ({ ctx, next }) => {
87
+ if (ctx.user?.role !== role) {
88
+ throw new TRPCError({
89
+ code: 'FORBIDDEN',
90
+ message: 'Insufficient permissions',
91
+ });
92
+ }
93
+ return next();
94
+ });
95
+
96
+ // Procedures with middleware
97
+ export const protectedProcedure = publicProcedure
98
+ .use(loggerMiddleware)
99
+ .use(isAuthed);
100
+
101
+ export const adminProcedure = protectedProcedure.use(hasRole('admin'));
102
+ \`\`\`
103
+
104
+ ## Router Definition
105
+ \`\`\`typescript
106
+ // server/routers/user.ts
107
+ import { z } from 'zod';
108
+ import { router, publicProcedure, protectedProcedure } from '../trpc';
109
+ import { TRPCError } from '@trpc/server';
110
+
111
+ export const userRouter = router({
112
+ // Public query
113
+ getById: publicProcedure
114
+ .input(z.object({ id: z.string().uuid() }))
115
+ .query(async ({ ctx, input }) => {
116
+ const user = await ctx.prisma.user.findUnique({
117
+ where: { id: input.id },
118
+ select: {
119
+ id: true,
120
+ name: true,
121
+ image: true,
122
+ // Don't expose email publicly
123
+ },
124
+ });
125
+
126
+ if (!user) {
127
+ throw new TRPCError({
128
+ code: 'NOT_FOUND',
129
+ message: 'User not found',
130
+ });
131
+ }
132
+
133
+ return user;
134
+ }),
135
+
136
+ // Protected query
137
+ me: protectedProcedure.query(async ({ ctx }) => {
138
+ return ctx.prisma.user.findUnique({
139
+ where: { id: ctx.user.id },
140
+ include: { profile: true },
141
+ });
142
+ }),
143
+
144
+ // Mutation with input validation
145
+ updateProfile: protectedProcedure
146
+ .input(
147
+ z.object({
148
+ name: z.string().min(2).max(100).optional(),
149
+ bio: z.string().max(500).optional(),
150
+ website: z.string().url().optional().or(z.literal('')),
151
+ })
152
+ )
153
+ .mutation(async ({ ctx, input }) => {
154
+ return ctx.prisma.user.update({
155
+ where: { id: ctx.user.id },
156
+ data: input,
157
+ });
158
+ }),
159
+
160
+ // List with pagination
161
+ list: publicProcedure
162
+ .input(
163
+ z.object({
164
+ limit: z.number().min(1).max(100).default(10),
165
+ cursor: z.string().uuid().optional(),
166
+ })
167
+ )
168
+ .query(async ({ ctx, input }) => {
169
+ const { limit, cursor } = input;
170
+
171
+ const users = await ctx.prisma.user.findMany({
172
+ take: limit + 1,
173
+ ...(cursor && {
174
+ cursor: { id: cursor },
175
+ skip: 1,
176
+ }),
177
+ orderBy: { createdAt: 'desc' },
178
+ });
179
+
180
+ let nextCursor: string | undefined;
181
+ if (users.length > limit) {
182
+ const nextItem = users.pop();
183
+ nextCursor = nextItem?.id;
184
+ }
185
+
186
+ return { users, nextCursor };
187
+ }),
188
+ });
189
+
190
+ // server/routers/post.ts
191
+ export const postRouter = router({
192
+ create: protectedProcedure
193
+ .input(
194
+ z.object({
195
+ title: z.string().min(1).max(200),
196
+ content: z.string().min(1),
197
+ published: z.boolean().default(false),
198
+ })
199
+ )
200
+ .mutation(async ({ ctx, input }) => {
201
+ return ctx.prisma.post.create({
202
+ data: {
203
+ ...input,
204
+ authorId: ctx.user.id,
205
+ },
206
+ });
207
+ }),
208
+
209
+ delete: protectedProcedure
210
+ .input(z.object({ id: z.string().uuid() }))
211
+ .mutation(async ({ ctx, input }) => {
212
+ const post = await ctx.prisma.post.findUnique({
213
+ where: { id: input.id },
214
+ });
215
+
216
+ if (!post) {
217
+ throw new TRPCError({ code: 'NOT_FOUND' });
218
+ }
219
+
220
+ if (post.authorId !== ctx.user.id) {
221
+ throw new TRPCError({ code: 'FORBIDDEN' });
222
+ }
223
+
224
+ return ctx.prisma.post.delete({ where: { id: input.id } });
225
+ }),
226
+ });
227
+ \`\`\`
228
+
229
+ ## App Router
230
+ \`\`\`typescript
231
+ // server/routers/_app.ts
232
+ import { router } from '../trpc';
233
+ import { userRouter } from './user';
234
+ import { postRouter } from './post';
235
+
236
+ export const appRouter = router({
237
+ user: userRouter,
238
+ post: postRouter,
239
+ });
240
+
241
+ export type AppRouter = typeof appRouter;
242
+ \`\`\`
243
+
244
+ ## Next.js API Handler
245
+ \`\`\`typescript
246
+ // app/api/trpc/[trpc]/route.ts (App Router)
247
+ import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
248
+ import { appRouter } from '@/server/routers/_app';
249
+ import { createContext } from '@/server/context';
250
+
251
+ const handler = (req: Request) =>
252
+ fetchRequestHandler({
253
+ endpoint: '/api/trpc',
254
+ req,
255
+ router: appRouter,
256
+ createContext: () => createContext({ req }),
257
+ });
258
+
259
+ export { handler as GET, handler as POST };
260
+ \`\`\`
261
+
262
+ ## Client Setup
263
+ \`\`\`typescript
264
+ // utils/trpc.ts
265
+ import { createTRPCReact } from '@trpc/react-query';
266
+ import { type AppRouter } from '@/server/routers/_app';
267
+
268
+ export const trpc = createTRPCReact<AppRouter>();
269
+
270
+ // app/providers.tsx
271
+ 'use client';
272
+
273
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
274
+ import { httpBatchLink } from '@trpc/client';
275
+ import { useState } from 'react';
276
+ import { trpc } from '@/utils/trpc';
277
+ import superjson from 'superjson';
278
+
279
+ export function TRPCProvider({ children }: { children: React.ReactNode }) {
280
+ const [queryClient] = useState(() => new QueryClient());
281
+ const [trpcClient] = useState(() =>
282
+ trpc.createClient({
283
+ links: [
284
+ httpBatchLink({
285
+ url: '/api/trpc',
286
+ transformer: superjson,
287
+ }),
288
+ ],
289
+ })
290
+ );
291
+
292
+ return (
293
+ <trpc.Provider client={trpcClient} queryClient={queryClient}>
294
+ <QueryClientProvider client={queryClient}>
295
+ {children}
296
+ </QueryClientProvider>
297
+ </trpc.Provider>
298
+ );
299
+ }
300
+ \`\`\`
301
+
302
+ ## Client Usage
303
+ \`\`\`typescript
304
+ // components/UserProfile.tsx
305
+ 'use client';
306
+
307
+ import { trpc } from '@/utils/trpc';
308
+
309
+ export function UserProfile({ userId }: { userId: string }) {
310
+ // Query
311
+ const { data: user, isLoading, error } = trpc.user.getById.useQuery(
312
+ { id: userId },
313
+ { enabled: !!userId }
314
+ );
315
+
316
+ // Mutation
317
+ const utils = trpc.useUtils();
318
+ const updateProfile = trpc.user.updateProfile.useMutation({
319
+ onSuccess: () => {
320
+ // Invalidate and refetch
321
+ utils.user.me.invalidate();
322
+ },
323
+ onError: (error) => {
324
+ console.error('Update failed:', error.message);
325
+ },
326
+ });
327
+
328
+ const handleUpdate = (data: { name: string }) => {
329
+ updateProfile.mutate(data);
330
+ };
331
+
332
+ if (isLoading) return <div>Loading...</div>;
333
+ if (error) return <div>Error: {error.message}</div>;
334
+
335
+ return <div>{user?.name}</div>;
336
+ }
337
+
338
+ // Infinite query
339
+ export function PostList() {
340
+ const {
341
+ data,
342
+ fetchNextPage,
343
+ hasNextPage,
344
+ isFetchingNextPage,
345
+ } = trpc.post.list.useInfiniteQuery(
346
+ { limit: 10 },
347
+ {
348
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
349
+ }
350
+ );
351
+
352
+ return (
353
+ <div>
354
+ {data?.pages.map((page) =>
355
+ page.posts.map((post) => <PostCard key={post.id} post={post} />)
356
+ )}
357
+ {hasNextPage && (
358
+ <button
359
+ onClick={() => fetchNextPage()}
360
+ disabled={isFetchingNextPage}
361
+ >
362
+ {isFetchingNextPage ? 'Loading...' : 'Load More'}
363
+ </button>
364
+ )}
365
+ </div>
366
+ );
367
+ }
368
+ \`\`\`
369
+
370
+ ## Server-Side Calls (RSC)
371
+ \`\`\`typescript
372
+ // Server component usage
373
+ import { createCaller } from '@/server/routers/_app';
374
+ import { createContext } from '@/server/context';
375
+
376
+ export default async function Page() {
377
+ const ctx = await createContext();
378
+ const caller = createCaller(ctx);
379
+
380
+ const user = await caller.user.me();
381
+
382
+ return <div>{user.name}</div>;
383
+ }
384
+ \`\`\`
385
+
386
+ ## Error Handling
387
+ \`\`\`typescript
388
+ // Custom error with data
389
+ throw new TRPCError({
390
+ code: 'BAD_REQUEST',
391
+ message: 'Validation failed',
392
+ cause: new Error('Original error'),
393
+ });
394
+
395
+ // Error codes
396
+ type TRPCErrorCode =
397
+ | 'PARSE_ERROR'
398
+ | 'BAD_REQUEST'
399
+ | 'UNAUTHORIZED'
400
+ | 'FORBIDDEN'
401
+ | 'NOT_FOUND'
402
+ | 'METHOD_NOT_SUPPORTED'
403
+ | 'TIMEOUT'
404
+ | 'CONFLICT'
405
+ | 'PRECONDITION_FAILED'
406
+ | 'PAYLOAD_TOO_LARGE'
407
+ | 'TOO_MANY_REQUESTS'
408
+ | 'CLIENT_CLOSED_REQUEST'
409
+ | 'INTERNAL_SERVER_ERROR';
410
+ \`\`\`
411
+
412
+ ## ❌ DON'T
413
+ - Skip input validation with Zod
414
+ - Expose sensitive data in public procedures
415
+ - Forget to handle errors in mutations
416
+ - Use any types for inputs/outputs
417
+ - Skip middleware for auth checks
418
+
419
+ ## ✅ DO
420
+ - Use superjson for Date/Map/Set support
421
+ - Create reusable middleware
422
+ - Use proper error codes
423
+ - Invalidate queries after mutations
424
+ - Use infinite queries for pagination
425
+ - Type your context properly
426
+ - Use procedure builders for common patterns