autoworkflow 3.1.5 → 3.6.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.
- package/.claude/commands/analyze.md +19 -0
- package/.claude/commands/audit.md +26 -0
- package/.claude/commands/build.md +39 -0
- package/.claude/commands/commit.md +25 -0
- package/.claude/commands/fix.md +23 -0
- package/.claude/commands/plan.md +18 -0
- package/.claude/commands/suggest.md +23 -0
- package/.claude/commands/verify.md +18 -0
- package/.claude/hooks/post-bash-router.sh +20 -0
- package/.claude/hooks/post-commit.sh +140 -0
- package/.claude/hooks/post-edit.sh +190 -17
- package/.claude/hooks/pre-edit.sh +221 -0
- package/.claude/hooks/session-check.sh +90 -0
- package/.claude/settings.json +56 -6
- package/.claude/settings.local.json +5 -1
- package/.claude/skills/actix.md +337 -0
- package/.claude/skills/alembic.md +504 -0
- package/.claude/skills/angular.md +237 -0
- package/.claude/skills/api-design.md +187 -0
- package/.claude/skills/aspnet-core.md +377 -0
- package/.claude/skills/astro.md +245 -0
- package/.claude/skills/auth-clerk.md +327 -0
- package/.claude/skills/auth-firebase.md +367 -0
- package/.claude/skills/auth-nextauth.md +359 -0
- package/.claude/skills/auth-supabase.md +368 -0
- package/.claude/skills/axum.md +386 -0
- package/.claude/skills/blazor.md +456 -0
- package/.claude/skills/chi.md +348 -0
- package/.claude/skills/code-review.md +133 -0
- package/.claude/skills/csharp.md +296 -0
- package/.claude/skills/css-modules.md +325 -0
- package/.claude/skills/cypress.md +343 -0
- package/.claude/skills/debugging.md +133 -0
- package/.claude/skills/diesel.md +392 -0
- package/.claude/skills/django.md +301 -0
- package/.claude/skills/docker.md +319 -0
- package/.claude/skills/doctrine.md +473 -0
- package/.claude/skills/documentation.md +182 -0
- package/.claude/skills/dotnet.md +409 -0
- package/.claude/skills/drizzle.md +293 -0
- package/.claude/skills/echo.md +321 -0
- package/.claude/skills/eloquent.md +256 -0
- package/.claude/skills/emotion.md +426 -0
- package/.claude/skills/entity-framework.md +370 -0
- package/.claude/skills/express.md +316 -0
- package/.claude/skills/fastapi.md +329 -0
- package/.claude/skills/fastify.md +299 -0
- package/.claude/skills/fiber.md +315 -0
- package/.claude/skills/flask.md +322 -0
- package/.claude/skills/gin.md +342 -0
- package/.claude/skills/git.md +116 -0
- package/.claude/skills/github-actions.md +353 -0
- package/.claude/skills/go.md +377 -0
- package/.claude/skills/gorm.md +409 -0
- package/.claude/skills/graphql.md +478 -0
- package/.claude/skills/hibernate.md +379 -0
- package/.claude/skills/hono.md +306 -0
- package/.claude/skills/java.md +400 -0
- package/.claude/skills/jest.md +313 -0
- package/.claude/skills/jpa.md +282 -0
- package/.claude/skills/kotlin.md +347 -0
- package/.claude/skills/kubernetes.md +363 -0
- package/.claude/skills/laravel.md +414 -0
- package/.claude/skills/mcp-browser.md +320 -0
- package/.claude/skills/mcp-database.md +219 -0
- package/.claude/skills/mcp-fetch.md +241 -0
- package/.claude/skills/mcp-filesystem.md +204 -0
- package/.claude/skills/mcp-github.md +217 -0
- package/.claude/skills/mcp-memory.md +240 -0
- package/.claude/skills/mcp-search.md +218 -0
- package/.claude/skills/mcp-slack.md +262 -0
- package/.claude/skills/micronaut.md +388 -0
- package/.claude/skills/mongodb.md +319 -0
- package/.claude/skills/mongoose.md +355 -0
- package/.claude/skills/mysql.md +281 -0
- package/.claude/skills/nestjs.md +335 -0
- package/.claude/skills/nextjs-app-router.md +260 -0
- package/.claude/skills/nextjs-pages.md +172 -0
- package/.claude/skills/nuxt.md +202 -0
- package/.claude/skills/openapi.md +489 -0
- package/.claude/skills/performance.md +199 -0
- package/.claude/skills/php.md +398 -0
- package/.claude/skills/playwright.md +371 -0
- package/.claude/skills/postgresql.md +257 -0
- package/.claude/skills/prisma.md +293 -0
- package/.claude/skills/pydantic.md +304 -0
- package/.claude/skills/pytest.md +313 -0
- package/.claude/skills/python.md +272 -0
- package/.claude/skills/quarkus.md +377 -0
- package/.claude/skills/react.md +230 -0
- package/.claude/skills/redis.md +391 -0
- package/.claude/skills/refactoring.md +143 -0
- package/.claude/skills/remix.md +246 -0
- package/.claude/skills/rest-api.md +490 -0
- package/.claude/skills/rocket.md +366 -0
- package/.claude/skills/rust.md +341 -0
- package/.claude/skills/sass.md +380 -0
- package/.claude/skills/sea-orm.md +382 -0
- package/.claude/skills/security.md +167 -0
- package/.claude/skills/sequelize.md +395 -0
- package/.claude/skills/spring-boot.md +416 -0
- package/.claude/skills/sqlalchemy.md +269 -0
- package/.claude/skills/sqlx-rust.md +408 -0
- package/.claude/skills/state-jotai.md +346 -0
- package/.claude/skills/state-mobx.md +353 -0
- package/.claude/skills/state-pinia.md +431 -0
- package/.claude/skills/state-redux.md +337 -0
- package/.claude/skills/state-tanstack-query.md +434 -0
- package/.claude/skills/state-zustand.md +340 -0
- package/.claude/skills/styled-components.md +403 -0
- package/.claude/skills/svelte.md +238 -0
- package/.claude/skills/sveltekit.md +207 -0
- package/.claude/skills/symfony.md +437 -0
- package/.claude/skills/tailwind.md +279 -0
- package/.claude/skills/terraform.md +394 -0
- package/.claude/skills/testing-library.md +371 -0
- package/.claude/skills/trpc.md +426 -0
- package/.claude/skills/typeorm.md +368 -0
- package/.claude/skills/vitest.md +330 -0
- package/.claude/skills/vue.md +202 -0
- package/.claude/skills/warp.md +365 -0
- package/README.md +163 -52
- package/package.json +1 -1
- package/system/triggers.md +256 -17
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Remix Skill
|
|
2
|
+
|
|
3
|
+
## Route Conventions
|
|
4
|
+
\`\`\`
|
|
5
|
+
app/
|
|
6
|
+
├── root.tsx # Root layout
|
|
7
|
+
├── routes/
|
|
8
|
+
│ ├── _index.tsx # / (index route)
|
|
9
|
+
│ ├── users.tsx # /users (layout)
|
|
10
|
+
│ ├── users._index.tsx # /users (index)
|
|
11
|
+
│ ├── users.$id.tsx # /users/:id
|
|
12
|
+
│ ├── users.$id_.edit.tsx # /users/:id/edit (escapes layout)
|
|
13
|
+
│ └── api.users.ts # /api/users (resource route)
|
|
14
|
+
\`\`\`
|
|
15
|
+
|
|
16
|
+
## Loader (Data Fetching)
|
|
17
|
+
\`\`\`typescript
|
|
18
|
+
import type { LoaderFunctionArgs } from '@remix-run/node';
|
|
19
|
+
import { json } from '@remix-run/node';
|
|
20
|
+
import { useLoaderData } from '@remix-run/react';
|
|
21
|
+
|
|
22
|
+
export async function loader({ params, request }: LoaderFunctionArgs) {
|
|
23
|
+
// Access URL search params
|
|
24
|
+
const url = new URL(request.url);
|
|
25
|
+
const page = url.searchParams.get('page') ?? '1';
|
|
26
|
+
|
|
27
|
+
// Auth check
|
|
28
|
+
const user = await requireUser(request);
|
|
29
|
+
|
|
30
|
+
const post = await db.post.findUnique({ where: { id: params.id } });
|
|
31
|
+
|
|
32
|
+
if (!post) {
|
|
33
|
+
throw new Response('Not Found', { status: 404 });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return json({ post, user });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default function PostPage() {
|
|
40
|
+
const { post, user } = useLoaderData<typeof loader>();
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<article>
|
|
44
|
+
<h1>{post.title}</h1>
|
|
45
|
+
<p>By {user.name}</p>
|
|
46
|
+
</article>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
\`\`\`
|
|
50
|
+
|
|
51
|
+
## Action (Mutations)
|
|
52
|
+
\`\`\`typescript
|
|
53
|
+
import type { ActionFunctionArgs } from '@remix-run/node';
|
|
54
|
+
import { redirect, json } from '@remix-run/node';
|
|
55
|
+
import { useActionData, Form } from '@remix-run/react';
|
|
56
|
+
|
|
57
|
+
export async function action({ request }: ActionFunctionArgs) {
|
|
58
|
+
const formData = await request.formData();
|
|
59
|
+
const intent = formData.get('intent');
|
|
60
|
+
|
|
61
|
+
if (intent === 'delete') {
|
|
62
|
+
await db.post.delete({ where: { id: formData.get('id') } });
|
|
63
|
+
return redirect('/posts');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Validation
|
|
67
|
+
const title = formData.get('title');
|
|
68
|
+
const content = formData.get('content');
|
|
69
|
+
|
|
70
|
+
const errors: Record<string, string> = {};
|
|
71
|
+
if (!title) errors.title = 'Title is required';
|
|
72
|
+
if (!content) errors.content = 'Content is required';
|
|
73
|
+
|
|
74
|
+
if (Object.keys(errors).length) {
|
|
75
|
+
return json({ errors, values: { title, content } }, { status: 400 });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await db.post.create({ data: { title, content } });
|
|
79
|
+
return redirect('/posts');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default function NewPost() {
|
|
83
|
+
const actionData = useActionData<typeof action>();
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Form method="post">
|
|
87
|
+
<input
|
|
88
|
+
name="title"
|
|
89
|
+
defaultValue={actionData?.values?.title}
|
|
90
|
+
/>
|
|
91
|
+
{actionData?.errors?.title && (
|
|
92
|
+
<span className="error">{actionData.errors.title}</span>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
<textarea
|
|
96
|
+
name="content"
|
|
97
|
+
defaultValue={actionData?.values?.content}
|
|
98
|
+
/>
|
|
99
|
+
|
|
100
|
+
<button type="submit">Create Post</button>
|
|
101
|
+
</Form>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
\`\`\`
|
|
105
|
+
|
|
106
|
+
## Error Handling
|
|
107
|
+
\`\`\`typescript
|
|
108
|
+
import { isRouteErrorResponse, useRouteError } from '@remix-run/react';
|
|
109
|
+
|
|
110
|
+
// Error boundary for this route
|
|
111
|
+
export function ErrorBoundary() {
|
|
112
|
+
const error = useRouteError();
|
|
113
|
+
|
|
114
|
+
if (isRouteErrorResponse(error)) {
|
|
115
|
+
return (
|
|
116
|
+
<div>
|
|
117
|
+
<h1>{error.status} {error.statusText}</h1>
|
|
118
|
+
<p>{error.data}</p>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div>
|
|
125
|
+
<h1>Unexpected Error</h1>
|
|
126
|
+
<p>{error instanceof Error ? error.message : 'Unknown error'}</p>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Throwing errors in loaders/actions
|
|
132
|
+
export async function loader({ params }: LoaderFunctionArgs) {
|
|
133
|
+
const user = await db.user.findUnique({ where: { id: params.id } });
|
|
134
|
+
|
|
135
|
+
if (!user) {
|
|
136
|
+
throw new Response('User not found', { status: 404 });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return json({ user });
|
|
140
|
+
}
|
|
141
|
+
\`\`\`
|
|
142
|
+
|
|
143
|
+
## Deferred Data (Streaming)
|
|
144
|
+
\`\`\`typescript
|
|
145
|
+
import { defer } from '@remix-run/node';
|
|
146
|
+
import { Await, useLoaderData } from '@remix-run/react';
|
|
147
|
+
import { Suspense } from 'react';
|
|
148
|
+
|
|
149
|
+
export async function loader() {
|
|
150
|
+
// Fast data - awaited
|
|
151
|
+
const user = await getUser();
|
|
152
|
+
|
|
153
|
+
// Slow data - deferred
|
|
154
|
+
const recommendationsPromise = getRecommendations();
|
|
155
|
+
|
|
156
|
+
return defer({
|
|
157
|
+
user,
|
|
158
|
+
recommendations: recommendationsPromise
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export default function Dashboard() {
|
|
163
|
+
const { user, recommendations } = useLoaderData<typeof loader>();
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<div>
|
|
167
|
+
<h1>Welcome, {user.name}</h1>
|
|
168
|
+
|
|
169
|
+
<Suspense fallback={<p>Loading recommendations...</p>}>
|
|
170
|
+
<Await resolve={recommendations}>
|
|
171
|
+
{(data) => <RecommendationsList items={data} />}
|
|
172
|
+
</Await>
|
|
173
|
+
</Suspense>
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
\`\`\`
|
|
178
|
+
|
|
179
|
+
## Session Management
|
|
180
|
+
\`\`\`typescript
|
|
181
|
+
// app/sessions.server.ts
|
|
182
|
+
import { createCookieSessionStorage } from '@remix-run/node';
|
|
183
|
+
|
|
184
|
+
export const sessionStorage = createCookieSessionStorage({
|
|
185
|
+
cookie: {
|
|
186
|
+
name: '__session',
|
|
187
|
+
httpOnly: true,
|
|
188
|
+
maxAge: 60 * 60 * 24 * 7, // 1 week
|
|
189
|
+
path: '/',
|
|
190
|
+
sameSite: 'lax',
|
|
191
|
+
secrets: [process.env.SESSION_SECRET!],
|
|
192
|
+
secure: process.env.NODE_ENV === 'production',
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
export async function getSession(request: Request) {
|
|
197
|
+
return sessionStorage.getSession(request.headers.get('Cookie'));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export async function requireUser(request: Request) {
|
|
201
|
+
const session = await getSession(request);
|
|
202
|
+
const userId = session.get('userId');
|
|
203
|
+
|
|
204
|
+
if (!userId) {
|
|
205
|
+
throw redirect('/login');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return db.user.findUnique({ where: { id: userId } });
|
|
209
|
+
}
|
|
210
|
+
\`\`\`
|
|
211
|
+
|
|
212
|
+
## Resource Routes (API)
|
|
213
|
+
\`\`\`typescript
|
|
214
|
+
// app/routes/api.users.ts
|
|
215
|
+
import { json } from '@remix-run/node';
|
|
216
|
+
import type { LoaderFunctionArgs, ActionFunctionArgs } from '@remix-run/node';
|
|
217
|
+
|
|
218
|
+
export async function loader({ request }: LoaderFunctionArgs) {
|
|
219
|
+
const users = await db.user.findMany();
|
|
220
|
+
return json(users);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export async function action({ request }: ActionFunctionArgs) {
|
|
224
|
+
if (request.method === 'POST') {
|
|
225
|
+
const data = await request.json();
|
|
226
|
+
const user = await db.user.create({ data });
|
|
227
|
+
return json(user, { status: 201 });
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return json({ error: 'Method not allowed' }, { status: 405 });
|
|
231
|
+
}
|
|
232
|
+
\`\`\`
|
|
233
|
+
|
|
234
|
+
## ❌ DON'T
|
|
235
|
+
- Use useEffect for data fetching (use loaders)
|
|
236
|
+
- Forget error boundaries
|
|
237
|
+
- Skip validation in actions
|
|
238
|
+
- Put secrets in client code
|
|
239
|
+
|
|
240
|
+
## ✅ DO
|
|
241
|
+
- Use loaders for data fetching
|
|
242
|
+
- Use actions for mutations
|
|
243
|
+
- Use Form for progressive enhancement
|
|
244
|
+
- Use defer for slow data
|
|
245
|
+
- Handle errors with ErrorBoundary
|
|
246
|
+
- Use sessions for auth state
|