@strayl/agent 0.1.3 → 0.1.4
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/package.json +5 -1
- package/skills/api-creation/SKILL.md +631 -0
- package/skills/authentication/SKILL.md +294 -0
- package/skills/frontend-design/SKILL.md +108 -0
- package/skills/landing-creation/SKILL.md +125 -0
- package/skills/reference/SKILL.md +149 -0
- package/skills/web-application-creation/SKILL.md +231 -0
- package/src/agent.ts +0 -465
- package/src/checkpoints/manager.ts +0 -112
- package/src/context/manager.ts +0 -185
- package/src/context/summarizer.ts +0 -104
- package/src/context/trim.ts +0 -55
- package/src/emitter.ts +0 -14
- package/src/hitl/manager.ts +0 -77
- package/src/hitl/transport.ts +0 -13
- package/src/index.ts +0 -116
- package/src/llm/client.ts +0 -276
- package/src/llm/gemini-native.ts +0 -307
- package/src/llm/models.ts +0 -64
- package/src/middleware/compose.ts +0 -24
- package/src/middleware/credential-scrubbing.ts +0 -31
- package/src/middleware/forbidden-packages.ts +0 -107
- package/src/middleware/plan-mode.ts +0 -143
- package/src/middleware/prompt-caching.ts +0 -21
- package/src/middleware/tool-compression.ts +0 -25
- package/src/middleware/tool-filter.ts +0 -13
- package/src/prompts/implementation-mode.md +0 -16
- package/src/prompts/plan-mode.md +0 -51
- package/src/prompts/system.ts +0 -173
- package/src/skills/loader.ts +0 -53
- package/src/stdin-listener.ts +0 -61
- package/src/subagents/definitions.ts +0 -72
- package/src/subagents/manager.ts +0 -161
- package/src/todos/manager.ts +0 -61
- package/src/tools/builtin/delete.ts +0 -29
- package/src/tools/builtin/edit.ts +0 -74
- package/src/tools/builtin/exec.ts +0 -216
- package/src/tools/builtin/glob.ts +0 -104
- package/src/tools/builtin/grep.ts +0 -115
- package/src/tools/builtin/ls.ts +0 -54
- package/src/tools/builtin/move.ts +0 -31
- package/src/tools/builtin/read.ts +0 -69
- package/src/tools/builtin/write.ts +0 -42
- package/src/tools/executor.ts +0 -51
- package/src/tools/external/database.ts +0 -285
- package/src/tools/external/enter-plan-mode.ts +0 -34
- package/src/tools/external/generate-image.ts +0 -110
- package/src/tools/external/hitl-tools.ts +0 -118
- package/src/tools/external/preview.ts +0 -28
- package/src/tools/external/proxy-fetch.ts +0 -51
- package/src/tools/external/task.ts +0 -38
- package/src/tools/external/wait.ts +0 -20
- package/src/tools/external/web-fetch.ts +0 -57
- package/src/tools/external/web-search.ts +0 -61
- package/src/tools/registry.ts +0 -36
- package/src/tools/zod-to-json-schema.ts +0 -86
- package/src/types.ts +0 -151
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: authentication
|
|
3
|
+
description: Add authentication to a TanStack Start app using Neon Auth (managed Better Auth). Handles sign-in, sign-up, OAuth, email verification, password reset, session management, route protection, and pre-built auth UI. Use when the user needs user accounts, login, or protected routes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Authentication (Neon Auth)
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- User asks to add authentication, login, sign-up, or user accounts
|
|
11
|
+
- User wants to protect routes (dashboard, settings, profile, etc.)
|
|
12
|
+
- User mentions "auth", "login", "register", "sign up", "sign in", "logout", "session", "password", "OAuth", "Google sign-in"
|
|
13
|
+
- User needs user management or access control in their app
|
|
14
|
+
- User wants OAuth (Google, GitHub) login
|
|
15
|
+
|
|
16
|
+
## When NOT to Use
|
|
17
|
+
|
|
18
|
+
- User only needs a public site with no user accounts
|
|
19
|
+
- User wants API key authentication (not session-based)
|
|
20
|
+
- User explicitly wants to build auth from scratch without Neon Auth
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
- A TanStack Start project (scaffolded with `web-application-creation` skill or existing)
|
|
25
|
+
- A database created with `database-management` skill (or will be created in this workflow)
|
|
26
|
+
- `AUTH_BASE_URL` and `VITE_AUTH_BASE_URL` env vars are automatically available after database creation (both set by `create_database`)
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
|
|
30
|
+
Neon Auth is a **managed authentication service** built on Better Auth. It runs as a REST API deployed in the same region as the Neon database.
|
|
31
|
+
|
|
32
|
+
| Concern | Solution |
|
|
33
|
+
|---------|----------|
|
|
34
|
+
| Auth service | Neon Auth (managed Better Auth) |
|
|
35
|
+
| User storage | `neon_auth` schema in Neon DB (automatic) |
|
|
36
|
+
| UI components | `@neondatabase/neon-js/auth/react/ui` (pre-built) |
|
|
37
|
+
| Session | HTTP-only cookie (`__Secure-neonauth.session_token`), managed by SDK |
|
|
38
|
+
| OAuth | Google works out of the box; GitHub/Vercel need custom credentials |
|
|
39
|
+
|
|
40
|
+
**No custom user table needed.** Users, sessions, and accounts are stored automatically in the `neon_auth` schema.
|
|
41
|
+
|
|
42
|
+
## Workflow
|
|
43
|
+
|
|
44
|
+
### Step 1: Ensure Database Exists
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
universal({ tool: "list_databases", params: {} })
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If no databases exist, create one first:
|
|
51
|
+
```
|
|
52
|
+
universal({ tool: "create_database", params: { name: "main" } })
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Auth is automatically provisioned when the database is created. The `AUTH_BASE_URL`, `VITE_AUTH_BASE_URL`, and `AUTH_COOKIE_SECRET` env vars are already set in the sandbox and `.env`.
|
|
56
|
+
|
|
57
|
+
### Step 2: Install Neon Auth SDK
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
exec({ command: "cd {app-name} && npm install @neondatabase/neon-js", background: true })
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Step 3: Add Auth Styles
|
|
64
|
+
|
|
65
|
+
**Edit** `src/styles.css` — add the Neon UI import right after the Tailwind import:
|
|
66
|
+
|
|
67
|
+
```css
|
|
68
|
+
@import 'tailwindcss';
|
|
69
|
+
@import '@neondatabase/neon-js/ui/tailwind';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If the project does NOT use Tailwind, import the pre-built CSS bundle instead. Add to the root layout or entry point:
|
|
73
|
+
```typescript
|
|
74
|
+
import '@neondatabase/neon-js/ui/css';
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Step 4: Create Auth Client
|
|
78
|
+
|
|
79
|
+
Create `src/auth.ts`. Uses `VITE_AUTH_BASE_URL` which is auto-set by `create_database` — no manual env var setup needed.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { createAuthClient } from '@neondatabase/neon-js/auth';
|
|
83
|
+
import { BetterAuthReactAdapter } from '@neondatabase/neon-js/auth/react';
|
|
84
|
+
|
|
85
|
+
export const authClient = createAuthClient(
|
|
86
|
+
import.meta.env.VITE_AUTH_BASE_URL,
|
|
87
|
+
{ adapter: BetterAuthReactAdapter() }
|
|
88
|
+
);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Step 5: Add Auth Provider to Root Route
|
|
92
|
+
|
|
93
|
+
**Edit** `src/routes/__root.tsx` — wrap the app with `NeonAuthUIProvider`:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { NeonAuthUIProvider } from '@neondatabase/neon-js/auth/react';
|
|
97
|
+
import { authClient } from '../auth';
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Wrap the existing `<Outlet />` (or app content) with the provider:
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
<NeonAuthUIProvider authClient={authClient}>
|
|
104
|
+
<Outlet />
|
|
105
|
+
</NeonAuthUIProvider>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Optional props** for `NeonAuthUIProvider`:
|
|
109
|
+
- `social={{ providers: ['google'] }}` — show OAuth buttons (Google works out of the box)
|
|
110
|
+
- `emailOTP` — enable Email OTP sign-in
|
|
111
|
+
- `credentials={{ forgotPassword: true }}` — enable forgot password flow
|
|
112
|
+
- `navigate={navigate}` — for React Router integration
|
|
113
|
+
|
|
114
|
+
**Do NOT replace** the existing root route — just add the import and wrap the content with the provider.
|
|
115
|
+
|
|
116
|
+
### Step 6: Create Auth Page Route
|
|
117
|
+
|
|
118
|
+
Create `src/routes/auth.$pathname.tsx`:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
122
|
+
import { AuthView } from '@neondatabase/neon-js/auth/react/ui';
|
|
123
|
+
|
|
124
|
+
export const Route = createFileRoute('/auth/$pathname')({
|
|
125
|
+
component: Auth,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
function Auth() {
|
|
129
|
+
const { pathname } = Route.useParams();
|
|
130
|
+
return (
|
|
131
|
+
<div className="flex min-h-screen items-center justify-center">
|
|
132
|
+
<AuthView pathname={pathname} />
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This single route handles `/auth/sign-in`, `/auth/sign-up`, `/auth/forgot-password`, etc.
|
|
139
|
+
|
|
140
|
+
### Step 7: Create Account Page Route
|
|
141
|
+
|
|
142
|
+
Create `src/routes/account.$pathname.tsx`:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
146
|
+
import { AccountView } from '@neondatabase/neon-js/auth/react/ui';
|
|
147
|
+
|
|
148
|
+
export const Route = createFileRoute('/account/$pathname')({
|
|
149
|
+
component: Account,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
function Account() {
|
|
153
|
+
const { pathname } = Route.useParams();
|
|
154
|
+
return (
|
|
155
|
+
<div className="flex min-h-screen items-center justify-center">
|
|
156
|
+
<AccountView pathname={pathname} />
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
This handles `/account/settings`, `/account/profile`, etc.
|
|
163
|
+
|
|
164
|
+
### Step 8: Protect Routes
|
|
165
|
+
|
|
166
|
+
**Edit** the main page (e.g., `src/routes/index.tsx`) to require authentication:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { createFileRoute } from '@tanstack/react-router';
|
|
170
|
+
import { SignedIn, UserButton, RedirectToSignIn } from '@neondatabase/neon-js/auth/react/ui';
|
|
171
|
+
import { authClient } from '../auth';
|
|
172
|
+
|
|
173
|
+
export const Route = createFileRoute('/')({
|
|
174
|
+
component: Home,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
function Home() {
|
|
178
|
+
const { data } = authClient.useSession();
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<>
|
|
182
|
+
<SignedIn>
|
|
183
|
+
<div className="container mx-auto p-6">
|
|
184
|
+
<div className="flex items-center justify-between">
|
|
185
|
+
<h1 className="text-2xl font-bold">Welcome, {data?.user?.name}!</h1>
|
|
186
|
+
<UserButton />
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</SignedIn>
|
|
190
|
+
<RedirectToSignIn />
|
|
191
|
+
</>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Key components:**
|
|
197
|
+
- `<SignedIn>` — renders children only when authenticated
|
|
198
|
+
- `<SignedOut>` — renders children only when NOT authenticated
|
|
199
|
+
- `<RedirectToSignIn>` — redirects to `/auth/sign-in` if not authenticated
|
|
200
|
+
- `<UserButton />` — user avatar/menu dropdown with sign-out
|
|
201
|
+
|
|
202
|
+
### Step 9: Restart and Preview
|
|
203
|
+
|
|
204
|
+
Restart the dev server to pick up new routes and env vars, then `showPreview`. Tell the user to test `/auth/sign-in` and `/auth/sign-up`.
|
|
205
|
+
|
|
206
|
+
## File Structure (after completion)
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
src/
|
|
210
|
+
├── auth.ts # Auth client configuration (NEW)
|
|
211
|
+
├── styles.css # EDITED: added neon-js/ui/tailwind import
|
|
212
|
+
└── routes/
|
|
213
|
+
├── __root.tsx # EDITED: wrapped with NeonAuthUIProvider
|
|
214
|
+
├── auth.$pathname.tsx # NEW: handles sign-in, sign-up, forgot-password
|
|
215
|
+
├── account.$pathname.tsx # NEW: handles account settings, profile
|
|
216
|
+
└── index.tsx # EDITED: added route protection
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Available UI Components
|
|
220
|
+
|
|
221
|
+
| Component | Import | Purpose |
|
|
222
|
+
|-----------|--------|---------|
|
|
223
|
+
| `<AuthView>` | `@neondatabase/neon-js/auth/react/ui` | Full auth page (sign-in/sign-up/reset) |
|
|
224
|
+
| `<AccountView>` | `@neondatabase/neon-js/auth/react/ui` | Account management page |
|
|
225
|
+
| `<SignedIn>` | `@neondatabase/neon-js/auth/react/ui` | Render children only when authenticated |
|
|
226
|
+
| `<SignedOut>` | `@neondatabase/neon-js/auth/react/ui` | Render children only when NOT authenticated |
|
|
227
|
+
| `<RedirectToSignIn>` | `@neondatabase/neon-js/auth/react/ui` | Redirect to sign-in if not authenticated |
|
|
228
|
+
| `<RedirectToSignUp>` | `@neondatabase/neon-js/auth/react/ui` | Redirect to sign-up if not authenticated |
|
|
229
|
+
| `<UserButton>` | `@neondatabase/neon-js/auth/react/ui` | User avatar dropdown with sign-out |
|
|
230
|
+
| `<UserAvatar>` | `@neondatabase/neon-js/auth/react/ui` | User profile picture |
|
|
231
|
+
| `<SignInForm>` | `@neondatabase/neon-js/auth/react/ui` | Standalone sign-in form |
|
|
232
|
+
| `<SignUpForm>` | `@neondatabase/neon-js/auth/react/ui` | Standalone sign-up form |
|
|
233
|
+
| `<ForgotPasswordForm>` | `@neondatabase/neon-js/auth/react/ui` | Password recovery form |
|
|
234
|
+
|
|
235
|
+
## Hooks
|
|
236
|
+
|
|
237
|
+
| Hook | Import | Returns |
|
|
238
|
+
|------|--------|---------|
|
|
239
|
+
| `authClient.useSession()` | from auth client | `{ data: { session, user }, isPending }` |
|
|
240
|
+
|
|
241
|
+
## Important Notes
|
|
242
|
+
|
|
243
|
+
- **No custom user table.** Users are stored automatically in the `neon_auth` schema. Query with `SELECT * FROM neon_auth.user;`
|
|
244
|
+
- **No password hashing.** Neon Auth handles all credential management.
|
|
245
|
+
- **No session management.** Sessions are managed by the SDK via HTTP-only cookies.
|
|
246
|
+
- **Google OAuth works immediately** with shared credentials for development. GitHub/Vercel require custom OAuth app setup.
|
|
247
|
+
- **AUTH_BASE_URL is branch-specific.** Each Neon branch has its own auth environment — dev and prod are isolated.
|
|
248
|
+
- Do NOT import both `@neondatabase/neon-js/ui/css` AND `@neondatabase/neon-js/ui/tailwind` — pick one based on whether the project uses Tailwind.
|
|
249
|
+
- Do NOT install `bcryptjs`, `better-auth`, or other auth libraries — Neon Auth replaces them.
|
|
250
|
+
|
|
251
|
+
## SDK Methods Reference
|
|
252
|
+
|
|
253
|
+
For programmatic auth (building custom UI instead of pre-built components):
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import { authClient } from './auth';
|
|
257
|
+
|
|
258
|
+
// Sign up
|
|
259
|
+
await authClient.signUp.email({ email, password, name });
|
|
260
|
+
|
|
261
|
+
// Sign in with email/password
|
|
262
|
+
await authClient.signIn.email({ email, password });
|
|
263
|
+
|
|
264
|
+
// Sign in with OAuth
|
|
265
|
+
await authClient.signIn.social({ provider: 'google', callbackURL: '/' });
|
|
266
|
+
|
|
267
|
+
// Sign out
|
|
268
|
+
await authClient.signOut();
|
|
269
|
+
|
|
270
|
+
// Get current session
|
|
271
|
+
const { data } = await authClient.getSession();
|
|
272
|
+
// data.session, data.user
|
|
273
|
+
|
|
274
|
+
// React hook for session
|
|
275
|
+
const { data } = authClient.useSession();
|
|
276
|
+
|
|
277
|
+
// Update user profile
|
|
278
|
+
await authClient.updateUser({ name: 'New Name' });
|
|
279
|
+
|
|
280
|
+
// Change password
|
|
281
|
+
await authClient.changePassword({ currentPassword, newPassword });
|
|
282
|
+
|
|
283
|
+
// Email OTP verification
|
|
284
|
+
await authClient.emailOtp.verifyEmail({ email, otp: code });
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Extending
|
|
288
|
+
|
|
289
|
+
- **OAuth providers** — add `social={{ providers: ['google', 'github', 'vercel'] }}` to `NeonAuthUIProvider`
|
|
290
|
+
- **Forgot password** — add `credentials={{ forgotPassword: true }}` to `NeonAuthUIProvider`, or use `<ForgotPasswordForm>` and `<ResetPasswordForm>` components
|
|
291
|
+
- **Email verification** — enable in Neon Console (Settings > Auth). Use verification codes (works out of the box) or verification links (requires custom SMTP)
|
|
292
|
+
- **Custom sign-up fields** — use `additionalFields` and `signUp` props on `NeonAuthUIProvider`
|
|
293
|
+
- **Custom localization** — use `localization` prop to change labels (e.g., `{ SIGN_IN: 'Welcome Back' }`)
|
|
294
|
+
- **Protected route layout** — create `src/routes/_authed.tsx` with `<SignedIn>` check for route groups
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-design
|
|
3
|
+
description: Design and implement distinctive frontend UI for landing pages and web applications. Use when users ask for visual direction, layout, styling, component composition, or UX polish.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Frontend Design
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- After scaffolding with `landing-creation` or `web-application-creation`
|
|
11
|
+
- User asks to design, style, polish, or redesign UI
|
|
12
|
+
- User wants new screens/sections (hero, pricing, dashboard, settings, auth pages, etc.)
|
|
13
|
+
- User asks for a specific aesthetic direction (minimal, bold, editorial, brutalist, retro, corporate)
|
|
14
|
+
|
|
15
|
+
## Workflow
|
|
16
|
+
|
|
17
|
+
1. **Clarify intent quickly**
|
|
18
|
+
- Product/site goal and audience
|
|
19
|
+
- Required screens/sections
|
|
20
|
+
- Preferred visual direction and color constraints
|
|
21
|
+
|
|
22
|
+
2. **Define the visual system first**
|
|
23
|
+
- Typography pair (display + body) — see **Font Guidelines** below
|
|
24
|
+
- Color tokens via CSS variables
|
|
25
|
+
- Spacing, radius, shadow, and motion rules
|
|
26
|
+
|
|
27
|
+
3. **Compose the layout**
|
|
28
|
+
- For landing pages: nav, hero, proof, features, CTA, footer
|
|
29
|
+
- For apps: app shell, primary user flow, settings/forms, data states
|
|
30
|
+
- Add meaningful empty/loading/error states where relevant
|
|
31
|
+
|
|
32
|
+
4. **Implement pragmatically**
|
|
33
|
+
- Reuse existing project components before adding new dependencies
|
|
34
|
+
- Add new UI components only when the current set cannot cover the requirement
|
|
35
|
+
- Run install commands in background mode and confirm via logs
|
|
36
|
+
|
|
37
|
+
5. **Validate before handoff**
|
|
38
|
+
- Check mobile/tablet/desktop behavior
|
|
39
|
+
- Verify contrast and focus states
|
|
40
|
+
- Show preview, gather feedback, iterate
|
|
41
|
+
|
|
42
|
+
## Core Principles
|
|
43
|
+
|
|
44
|
+
### 1. Universal Frontend Scope
|
|
45
|
+
This skill is not only for landing pages. Apply it to marketing sites, product pages, dashboards, and full web app screens.
|
|
46
|
+
|
|
47
|
+
### 2. Distinct Visual Direction
|
|
48
|
+
Avoid generic template outputs. Make deliberate choices in typography, spacing rhythm, and layout structure.
|
|
49
|
+
|
|
50
|
+
### 3. No Forced Component Catalog
|
|
51
|
+
Do not rely on a single external component catalog as a default workflow. Use the project's own design language first.
|
|
52
|
+
|
|
53
|
+
### 4. Reuse Before Reinventing
|
|
54
|
+
Prefer existing components and tokens; extend them only where needed to keep UI consistent.
|
|
55
|
+
|
|
56
|
+
### 5. Responsive by Default
|
|
57
|
+
Design for small screens first, then scale up without breaking hierarchy and readability.
|
|
58
|
+
|
|
59
|
+
## Font Guidelines
|
|
60
|
+
|
|
61
|
+
**NEVER use the Bitcount font** — it is a Strayl branding font and must not be used in user projects.
|
|
62
|
+
|
|
63
|
+
**Avoid generic defaults** — Do NOT default to System UI, Inter, Arial, Helvetica, or other overused fonts. Every project deserves a distinctive typographic identity.
|
|
64
|
+
|
|
65
|
+
**Be creative and intentional** — Pick fonts that match the project's personality and aesthetic direction. Experiment with interesting pairings. Examples of strong choices:
|
|
66
|
+
- **Editorial / luxury**: Playfair Display, Cormorant, Fraunces, Libre Baskerville
|
|
67
|
+
- **Modern / clean**: Space Grotesk, General Sans, Outfit, Plus Jakarta Sans, Sora
|
|
68
|
+
- **Bold / statement**: Clash Display, Cabinet Grotesk, Unbounded, Familjen Grotesk
|
|
69
|
+
- **Geometric**: DM Sans, Manrope, Satoshi, Urbanist
|
|
70
|
+
- **Playful / warm**: Bricolage Grotesque, Instrument Sans, Lora, Crimson Pro
|
|
71
|
+
- **Monospace accent**: JetBrains Mono, Fira Code, IBM Plex Mono, Space Mono
|
|
72
|
+
|
|
73
|
+
Use Google Fonts CDN or fontsource for font loading. Always pick a display + body pair that complement each other.
|
|
74
|
+
|
|
75
|
+
## Technical Guidelines
|
|
76
|
+
|
|
77
|
+
- For simple sites, start with `src/routes/index.tsx`.
|
|
78
|
+
- For app features, edit the route/component relevant to the request.
|
|
79
|
+
- Extract reusable UI into `src/components/`.
|
|
80
|
+
- Keep style tokens centralized in `src/styles.css` and route shell files.
|
|
81
|
+
|
|
82
|
+
## Image Generation
|
|
83
|
+
|
|
84
|
+
**Proactively generate images** when the design calls for visual content (hero images, backgrounds, illustrations, icons, product shots). Do NOT use placeholder boxes or Lorem-style image URLs — generate real images instead.
|
|
85
|
+
|
|
86
|
+
**When to generate:**
|
|
87
|
+
- The user asks to build a page/section that naturally needs imagery (hero, about, features, gallery) and has NOT provided their own images or URLs
|
|
88
|
+
- The design would look incomplete or broken without visual content
|
|
89
|
+
- The user explicitly asks for images or illustrations
|
|
90
|
+
|
|
91
|
+
**When NOT to generate:**
|
|
92
|
+
- The user provided their own images, URLs, or assets
|
|
93
|
+
- The section works well with icons, gradients, or pure typography (no image needed)
|
|
94
|
+
- The user explicitly said to skip images or use placeholders
|
|
95
|
+
|
|
96
|
+
**How:**
|
|
97
|
+
- Use `generate_image` — up to 10 images per call, with descriptive prompts and appropriate aspect ratios
|
|
98
|
+
- Write detailed prompts: describe style, mood, colors, subject — not just "hero image"
|
|
99
|
+
- Match aspect ratios to layout: `16:9` for hero banners, `1:1` for cards/avatars, `3:4` for portraits
|
|
100
|
+
- Use `analyze_image` to understand user-provided mockups or screenshots before designing
|
|
101
|
+
|
|
102
|
+
## Workflow Checklist
|
|
103
|
+
|
|
104
|
+
- [ ] Confirmed goal, screens, and visual direction
|
|
105
|
+
- [ ] Defined typography and color/token system
|
|
106
|
+
- [ ] Implemented responsive layout and key states
|
|
107
|
+
- [ ] Reused existing components where possible
|
|
108
|
+
- [ ] Previewed and iterated with user feedback
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: landing-creation
|
|
3
|
+
description: Initialize a new landing page from the Strayl landing template using npx create-strayl-landing. Use when the user wants a single-page site, landing page, or marketing page — NOT a full web application with multiple routes and complex state.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Landing Page Creation
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- User asks to create a landing page, marketing page, or single-page site
|
|
11
|
+
- User says something like "create a site", "make me a landing page", "build a website", "create a homepage"
|
|
12
|
+
- User wants a simple promotional or presentation page (not a multi-page app with forms, auth, dashboards)
|
|
13
|
+
- The workspace repository is empty and the user's request implies a simple site rather than a full application
|
|
14
|
+
|
|
15
|
+
## When NOT to Use (use `web-application-creation` instead)
|
|
16
|
+
|
|
17
|
+
- User explicitly asks for a "web app", "application", "dashboard", "admin panel"
|
|
18
|
+
- User needs multiple routes, forms, data handling, state management, i18n
|
|
19
|
+
- User describes features like authentication, CRUD, API integration, database
|
|
20
|
+
- User wants 50+ UI components out of the box
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
1. **Ask the user for the site name** before running any commands. The name will be used as the project directory name.
|
|
25
|
+
2. **Run the scaffolding command** in the repository root:
|
|
26
|
+
```
|
|
27
|
+
npx -y create-strayl-landing@latest --name {site-name}
|
|
28
|
+
```
|
|
29
|
+
3. **Install dependencies:**
|
|
30
|
+
```
|
|
31
|
+
cd {site-name} && npm install
|
|
32
|
+
```
|
|
33
|
+
4. **Start the dev server** in background mode:
|
|
34
|
+
```
|
|
35
|
+
cd {site-name} && npm run dev
|
|
36
|
+
```
|
|
37
|
+
5. **Check logs** to confirm the server started successfully (look for "ready" or "listening on port").
|
|
38
|
+
6. **Show preview** to the user with `showPreview`.
|
|
39
|
+
|
|
40
|
+
7. **🔴 REQUIRED: Read and follow the design skill** — After showing preview, you MUST immediately:
|
|
41
|
+
```
|
|
42
|
+
read_file("/skills/frontend-design/SKILL.md")
|
|
43
|
+
```
|
|
44
|
+
Then follow the design skill's workflow to build out the landing page content. Do NOT stop after showing the preview — the scaffolding is just the starting point.
|
|
45
|
+
|
|
46
|
+
## After Scaffolding
|
|
47
|
+
|
|
48
|
+
**IMPORTANT:** Scaffolding creates an empty template. Your job is not done after `showPreview`. You MUST continue to the `frontend-design` skill to actually build the landing page content (hero, features, sections, etc.) based on the user's request.
|
|
49
|
+
|
|
50
|
+
## Template Stack
|
|
51
|
+
|
|
52
|
+
| Layer | Technology |
|
|
53
|
+
|-------|------------|
|
|
54
|
+
| Framework | React 19.2 + TanStack Start |
|
|
55
|
+
| Bundler | Vite 7.1 |
|
|
56
|
+
| Language | TypeScript 5.7 (strict mode) |
|
|
57
|
+
| Routing | TanStack Router (file-based) |
|
|
58
|
+
| Styling | Tailwind CSS 4.0 + CSS custom properties |
|
|
59
|
+
| UI Components | shadcn/ui (install as needed) |
|
|
60
|
+
| Icons | Lucide React |
|
|
61
|
+
| Theming | next-themes (light/dark + system default) |
|
|
62
|
+
| Fonts | Geist, Geist Mono (Google CDN) |
|
|
63
|
+
| Server | Nitro |
|
|
64
|
+
|
|
65
|
+
## Project Structure
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
{site-name}/
|
|
69
|
+
├── public/
|
|
70
|
+
│ ├── favicon.ico
|
|
71
|
+
│ ├── logo-dark.webp
|
|
72
|
+
│ └── logo-light.webp
|
|
73
|
+
├── src/
|
|
74
|
+
│ ├── components/
|
|
75
|
+
│ │ ├── ui/
|
|
76
|
+
│ │ │ └── button.tsx # Button component (7 variants, 6 sizes)
|
|
77
|
+
│ │ ├── theme-provider.tsx # Theme provider (light/dark/system)
|
|
78
|
+
│ │ └── themed-logo.tsx # Theme-aware logo
|
|
79
|
+
│ ├── lib/
|
|
80
|
+
│ │ └── utils.ts # cn() — class merging utility
|
|
81
|
+
│ ├── routes/
|
|
82
|
+
│ │ ├── __root.tsx # Root layout (fonts, meta, ThemeProvider)
|
|
83
|
+
│ │ ├── index.tsx # Home page (single landing page)
|
|
84
|
+
│ │ └── routeTree.gen.ts # Auto-generated route tree
|
|
85
|
+
│ ├── router.tsx # Router configuration
|
|
86
|
+
│ └── styles.css # Global styles + CSS custom properties
|
|
87
|
+
├── package.json
|
|
88
|
+
├── tsconfig.json
|
|
89
|
+
├── vite.config.ts
|
|
90
|
+
└── components.json # shadcn/ui configuration
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Key Features
|
|
94
|
+
|
|
95
|
+
- **Theming** — Light/dark mode via CSS custom properties. Semantic tokens: `primary`, `secondary`, `accent`, `destructive`, `muted`, `info`, `success`, `warning`. Light background `#f5f5f5`, dark background `#171717`.
|
|
96
|
+
- **Button component** — Simple button with CVA variants (`default`, `destructive`, `outline`, `ghost`, `secondary`, `link`) and sizes (`sm`, `default`, `lg`, `icon`).
|
|
97
|
+
- **Hydration safety** — Components check `mounted` state before rendering theme-dependent UI, preventing SSR mismatches.
|
|
98
|
+
- **Minimal footprint** — Only 3 components (Button, ThemeProvider, ThemedLogo) and a single page. No bloat.
|
|
99
|
+
- **Extensible** — Add new components via `npx shadcn@latest add <component>`. Add pages by creating files in `src/routes/`.
|
|
100
|
+
|
|
101
|
+
## Default Page Content
|
|
102
|
+
|
|
103
|
+
The template ships with a single page (`/`) containing:
|
|
104
|
+
- "STRAYL" heading (responsive sizing)
|
|
105
|
+
- "Landing page template" subheading
|
|
106
|
+
- "Get Started" CTA button with themed logo
|
|
107
|
+
- Full-height centered layout
|
|
108
|
+
|
|
109
|
+
## Architecture
|
|
110
|
+
|
|
111
|
+
- **Root layout** (`__root.tsx`) — Uses `shellComponent` for HTML shell. Geist fonts via Google Fonts CDN, ThemeProvider wrapper. Same pattern as `web-application-creation` template.
|
|
112
|
+
- **Routing** — File-based via TanStack Router. Files in `src/routes/` become routes automatically.
|
|
113
|
+
- **SSR** — Supported via TanStack React Start + Nitro.
|
|
114
|
+
- **Path alias** — `@/*` maps to `./src/*`.
|
|
115
|
+
- **`cn()`** — Utility combining clsx + tailwind-merge for conflict-free class merging.
|
|
116
|
+
- **Button** — Standard React button component. For link buttons, wrap with an anchor or use Tailwind classes directly.
|
|
117
|
+
|
|
118
|
+
## Best Practices
|
|
119
|
+
|
|
120
|
+
- **Do NOT** use `npm create`, `npx create-vite`, or other scaffolding tools. Always use `npx -y create-strayl-landing@latest`.
|
|
121
|
+
- Always use the `--name` flag to specify the site name.
|
|
122
|
+
- After creation, work inside the `{site-name}/` directory for all file edits.
|
|
123
|
+
- Start editing from `src/routes/index.tsx` (the landing page).
|
|
124
|
+
- Add new UI components via `npx shadcn@latest add <component>` rather than installing separate UI libraries.
|
|
125
|
+
- This is a landing page template — keep it simple. For complex multi-page apps, use the `web-application-creation` skill instead.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reference
|
|
3
|
+
description: Essential reference for stack versions, APIs, common errors, and patterns. Read this BEFORE writing any code in a TanStack Start project to avoid wrong imports, deprecated APIs, and build errors.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Reference — Stack Versions & Patterns
|
|
7
|
+
|
|
8
|
+
## When to Read This Skill
|
|
9
|
+
|
|
10
|
+
- **ALWAYS** before writing code that uses TanStack Start, Tailwind CSS, or shadcn/ui
|
|
11
|
+
- Before debugging build or runtime errors
|
|
12
|
+
- Before setting up a dev server
|
|
13
|
+
- When unsure about correct import paths or API syntax
|
|
14
|
+
|
|
15
|
+
## Stack Versions
|
|
16
|
+
|
|
17
|
+
| Package | Version | Key Changes |
|
|
18
|
+
|---------|---------|-------------|
|
|
19
|
+
| React | 19.x | `use()`, `useActionState()`, `useOptimistic()`, ref as prop (no forwardRef) |
|
|
20
|
+
| TanStack Start | 1.x | `createServerFn()` with fluent API, Nitro server, config in `vite.config.ts` |
|
|
21
|
+
| TanStack Router | 1.x | `createFileRoute()`, `Link`, `useNavigate()`, `useParams()`, `useSearch()` |
|
|
22
|
+
| Vite | 7.x | `@tailwindcss/vite` plugin, `@tanstack/react-start/plugin/vite` |
|
|
23
|
+
| Tailwind CSS | 4.x | CSS-based config via `@theme {}` — **NO `tailwind.config.js`** |
|
|
24
|
+
| shadcn/ui | latest | OKLCH colors, `tw-animate-css` (NOT `tailwindcss-animate`), `@custom-variant dark` |
|
|
25
|
+
| TypeScript | 5.7+ | strict mode |
|
|
26
|
+
|
|
27
|
+
## Tailwind CSS 4 — Critical Differences from v3
|
|
28
|
+
|
|
29
|
+
- Config lives in `src/styles.css` using `@import "tailwindcss"` and `@theme {}` blocks
|
|
30
|
+
- **NO `tailwind.config.js`** — delete it if it exists
|
|
31
|
+
- Colors use OKLCH format, not HSL
|
|
32
|
+
- Custom properties: `--color-primary`, `--color-background`, etc. inside `@theme inline {}`
|
|
33
|
+
- Plugins loaded via CSS: `@plugin "..."` — NOT via JS config
|
|
34
|
+
- No `content` array needed — auto-detection
|
|
35
|
+
- Animation: use `tw-animate-css`, NOT `tailwindcss-animate`
|
|
36
|
+
|
|
37
|
+
## TanStack Start API
|
|
38
|
+
|
|
39
|
+
### Config
|
|
40
|
+
Config is in `vite.config.ts` with `tanstackStart()` plugin. **NOT** old `app.config.ts` with `defineConfig`.
|
|
41
|
+
|
|
42
|
+
### Server Functions
|
|
43
|
+
```typescript
|
|
44
|
+
import { createServerFn } from '@tanstack/react-start'
|
|
45
|
+
import { z } from 'zod'
|
|
46
|
+
|
|
47
|
+
const mySchema = z.object({ id: z.string() })
|
|
48
|
+
|
|
49
|
+
export const getData = createServerFn({ method: 'GET' })
|
|
50
|
+
.inputValidator((d: unknown) => mySchema.parse(d))
|
|
51
|
+
.handler(async ({ data }) => {
|
|
52
|
+
// data is typed as { id: string }
|
|
53
|
+
return { result: data.id }
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**IMPORTANT:** `.inputValidator()` takes a **FUNCTION**, not a schema directly. Always wrap zod: `.inputValidator((d: unknown) => mySchema.parse(d))`
|
|
58
|
+
|
|
59
|
+
### File-Based Routing
|
|
60
|
+
- `$param` for dynamic segments
|
|
61
|
+
- `_layout` prefix for pathless layouts
|
|
62
|
+
- `__root.tsx` for root layout
|
|
63
|
+
- Loaders: defined on route via `loader` option in `createFileRoute()`
|
|
64
|
+
|
|
65
|
+
## Common Errors & Recovery
|
|
66
|
+
|
|
67
|
+
### Build / Compile Errors
|
|
68
|
+
| Error | Fix |
|
|
69
|
+
|-------|-----|
|
|
70
|
+
| `Cannot find module 'X'` | Run `npm install` first, then retry |
|
|
71
|
+
| `Type error: ...` | Read the file, fix the type, rebuild |
|
|
72
|
+
| `ENOENT: no such file or directory` | Check the path — likely wrong relative path |
|
|
73
|
+
|
|
74
|
+
### Dev Server Errors
|
|
75
|
+
| Error | Fix |
|
|
76
|
+
|-------|-----|
|
|
77
|
+
| Port already in use | Kill the background process, restart on a different port |
|
|
78
|
+
| `MODULE_NOT_FOUND` after install | `rm -rf node_modules && npm install` |
|
|
79
|
+
|
|
80
|
+
### Package Install Errors
|
|
81
|
+
| Error | Fix |
|
|
82
|
+
|-------|-----|
|
|
83
|
+
| `ERESOLVE: peer dependency conflict` | Use `npm install --legacy-peer-deps` |
|
|
84
|
+
| `ETARGET: no matching version` | Check the actual package name/version with `web_search` |
|
|
85
|
+
|
|
86
|
+
### Recovery Pattern
|
|
87
|
+
1. Read the **FULL** error message (don't guess from partial output)
|
|
88
|
+
2. Check `getLogs` if it was a background command
|
|
89
|
+
3. Fix the root cause (don't retry the same failing command)
|
|
90
|
+
4. **NEVER repeat the same edit or command twice** — if your fix didn't work, try a DIFFERENT approach
|
|
91
|
+
5. If stuck after 2 attempts, use `web_search` to find the solution
|
|
92
|
+
6. If still stuck, use `askUser` to explain the problem and ask for guidance
|
|
93
|
+
|
|
94
|
+
### Do NOT Loop
|
|
95
|
+
If you edited a file and it still errors:
|
|
96
|
+
- Read the error message carefully — it may be a different issue
|
|
97
|
+
- Use `web_search` or `task(web-researcher)` to understand the correct API
|
|
98
|
+
- Try a fundamentally different approach, not a variation of the same one
|
|
99
|
+
|
|
100
|
+
## Dev Server
|
|
101
|
+
|
|
102
|
+
When starting a dev server:
|
|
103
|
+
1. Run `exec({ command: "npm install", cwd: "web-application" })` if `node_modules` is missing
|
|
104
|
+
2. Use `exec({ command: "npm run dev", cwd: "web-application", background: true })` to start in background
|
|
105
|
+
3. Use `getLogs({ sessionId, commandId })` to check output and wait for ready
|
|
106
|
+
4. Extract the actual port from logs (e.g., "localhost:5173", "127.0.0.1:3001")
|
|
107
|
+
5. Use that detected port in `showPreview({ port: DETECTED_PORT, title: "Dev Server" })`
|
|
108
|
+
6. Only if no port found in logs, fallback to `showPreview({ port: 3000, title: "Dev Server" })`
|
|
109
|
+
|
|
110
|
+
## Database — Neon PostgreSQL
|
|
111
|
+
|
|
112
|
+
- **ALWAYS use `@neondatabase/serverless`** — it uses HTTP/WebSocket, compatible with Workers
|
|
113
|
+
- API: `import { neon } from '@neondatabase/serverless'`
|
|
114
|
+
- For simple queries: `const sql = neon(process.env.DATABASE_URL); const rows = await sql`SELECT * FROM users`;`
|
|
115
|
+
- For ORM: use `drizzle-orm` + `drizzle-orm/neon-http`
|
|
116
|
+
|
|
117
|
+
### Database Provisioning
|
|
118
|
+
1. First check if `DATABASE_URL` already exists via `list_env_vars`
|
|
119
|
+
2. If not — use `create_database` tool to provision a Neon DB (it auto-sets `DATABASE_URL`)
|
|
120
|
+
3. **NEVER ask the user to provide DATABASE_URL** — the platform provisions databases automatically
|
|
121
|
+
4. Only use `requestEnvVar` for DATABASE_URL if the user explicitly wants their own external database
|
|
122
|
+
|
|
123
|
+
### Critical: Lazy Initialization
|
|
124
|
+
`neon()` must **NEVER** be called at module top level. In Cloudflare Workers, `process.env` is only populated inside the `fetch()` handler. Module-level `neon(process.env.DATABASE_URL)` will crash with `undefined`. Always use a lazy singleton — see the `db()` pattern in `api-creation` and `authentication` skills.
|
|
125
|
+
|
|
126
|
+
## Packages Compatible with Workers
|
|
127
|
+
|
|
128
|
+
| Package | Purpose |
|
|
129
|
+
|---------|---------|
|
|
130
|
+
| `@neondatabase/serverless` | PostgreSQL via HTTP (Neon) |
|
|
131
|
+
| `drizzle-orm` + `drizzle-orm/neon-http` | ORM for Neon (~7kb) |
|
|
132
|
+
| `kysely` | Lightweight query builder (pure TS) |
|
|
133
|
+
| `@planetscale/database` | MySQL via HTTP |
|
|
134
|
+
| `@upstash/redis` | Redis via HTTP |
|
|
135
|
+
| `@libsql/client/web` | Turso/libSQL via HTTP |
|
|
136
|
+
| `jose` | JWT/JWE/JWS (WebCrypto native) |
|
|
137
|
+
| `bcryptjs` | Password hashing (pure JS) |
|
|
138
|
+
| `zod` | Schema validation |
|
|
139
|
+
| `fetch` | Built-in, no import needed |
|
|
140
|
+
|
|
141
|
+
## Background Commands
|
|
142
|
+
|
|
143
|
+
Use `background: true` for long-running commands:
|
|
144
|
+
- `npx -y shadcn@latest add ...` → wait 20-40 seconds
|
|
145
|
+
- `npm install` with many deps → wait 20-30 seconds
|
|
146
|
+
- `npm run build` → wait 15-45 seconds
|
|
147
|
+
- `npm run dev` (server startup) → wait 5-10 seconds
|
|
148
|
+
|
|
149
|
+
After starting in background, call `wait({ seconds: N })`, then `getLogs` to check. If still running, wait again (5-10s) and re-check. Do NOT call `getLogs` repeatedly without waiting.
|