ai-forge-cli 0.2.3 → 0.3.2
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/dist/{add-feature-JBVJHKHX.js → add-feature-MU65GMUK.js} +2 -2
- package/dist/index.js +2 -2
- package/dist/{init-UBPMMJ4L.js → init-OYJP5QCZ.js} +56 -23
- package/dist/templates/init/biome.json.hbs +8 -4
- package/dist/templates/init/claude.md.hbs +31 -73
- package/package.json +1 -1
- package/templates/init/biome.json.hbs +8 -4
- package/templates/init/claude.md.hbs +31 -73
- package/dist/templates/init/postcss.config.js.hbs +0 -6
- package/dist/templates/init/tailwind.config.ts.hbs +0 -12
- package/templates/init/postcss.config.js.hbs +0 -6
- package/templates/init/tailwind.config.ts.hbs +0 -12
|
@@ -76,11 +76,11 @@ var add_feature_default = defineCommand({
|
|
|
76
76
|
// Route files
|
|
77
77
|
{
|
|
78
78
|
templatePath: "feature/routes/index.tsx.hbs",
|
|
79
|
-
destPath: join(cwd, "
|
|
79
|
+
destPath: join(cwd, "src/routes", name, "index.tsx")
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
templatePath: "feature/routes/$id.tsx.hbs",
|
|
83
|
-
destPath: join(cwd, "
|
|
83
|
+
destPath: join(cwd, "src/routes", name, "$id.tsx")
|
|
84
84
|
}
|
|
85
85
|
];
|
|
86
86
|
for (const file of files) {
|
package/dist/index.js
CHANGED
|
@@ -19,8 +19,8 @@ var main = defineCommand({
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
subCommands: {
|
|
22
|
-
init: () => import("./init-
|
|
23
|
-
"add:feature": () => import("./add-feature-
|
|
22
|
+
init: () => import("./init-OYJP5QCZ.js").then((m) => m.default),
|
|
23
|
+
"add:feature": () => import("./add-feature-MU65GMUK.js").then((m) => m.default),
|
|
24
24
|
check: () => import("./check-B4VHLFHH.js").then((m) => m.default),
|
|
25
25
|
version: () => import("./version-VO3LHLDO.js").then((m) => m.default)
|
|
26
26
|
},
|
|
@@ -59,16 +59,24 @@ var init_default = defineCommand({
|
|
|
59
59
|
logger.blank();
|
|
60
60
|
logger.log(` ${pc.bold("Forge CLI")} - Creating project "${name}"`);
|
|
61
61
|
logger.blank();
|
|
62
|
-
logger.log(` ${pc.
|
|
62
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
63
|
+
logger.log(` ${pc.cyan("Step 1/5:")} TanStack Start`);
|
|
64
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
63
65
|
logger.blank();
|
|
64
66
|
try {
|
|
65
67
|
await runInteractive("pnpm", ["create", "@tanstack/start@latest", name]);
|
|
68
|
+
logger.blank();
|
|
69
|
+
logger.success("TanStack Start scaffolding complete");
|
|
66
70
|
} catch {
|
|
67
71
|
logger.error("TanStack Start scaffolding failed");
|
|
68
72
|
process.exit(1);
|
|
69
73
|
}
|
|
70
74
|
logger.blank();
|
|
71
|
-
|
|
75
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
76
|
+
logger.log(` ${pc.cyan("Step 2/5:")} Forge Customizations`);
|
|
77
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
78
|
+
logger.blank();
|
|
79
|
+
const step2 = logger.step("Adding customizations...");
|
|
72
80
|
try {
|
|
73
81
|
const pkgPath = join(projectDir, "package.json");
|
|
74
82
|
const pkg = JSON.parse(await readFile(pkgPath));
|
|
@@ -80,10 +88,9 @@ var init_default = defineCommand({
|
|
|
80
88
|
};
|
|
81
89
|
pkg.devDependencies = {
|
|
82
90
|
...pkg.devDependencies,
|
|
83
|
-
"@biomejs/biome": "^
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
tailwindcss: "^3.4.17"
|
|
91
|
+
"@biomejs/biome": "^2.3.11",
|
|
92
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
93
|
+
tailwindcss: "^4.1.18"
|
|
87
94
|
};
|
|
88
95
|
pkg.scripts = {
|
|
89
96
|
...pkg.scripts,
|
|
@@ -107,8 +114,6 @@ var init_default = defineCommand({
|
|
|
107
114
|
const templateData = { name };
|
|
108
115
|
const forgeFiles = [
|
|
109
116
|
{ templatePath: "init/biome.json.hbs", destPath: join(projectDir, "biome.json") },
|
|
110
|
-
{ templatePath: "init/tailwind.config.ts.hbs", destPath: join(projectDir, "tailwind.config.ts") },
|
|
111
|
-
{ templatePath: "init/postcss.config.js.hbs", destPath: join(projectDir, "postcss.config.js") },
|
|
112
117
|
{ templatePath: "init/convex/schema.ts.hbs", destPath: join(projectDir, "convex/schema.ts") },
|
|
113
118
|
{ templatePath: "init/src/lib/cn.ts.hbs", destPath: join(projectDir, "src/lib/cn.ts") },
|
|
114
119
|
{ templatePath: "init/src/providers/index.tsx.hbs", destPath: join(projectDir, "src/providers/index.tsx") },
|
|
@@ -143,13 +148,24 @@ ${rootContent}`;
|
|
|
143
148
|
}
|
|
144
149
|
const stylesPath = join(projectDir, "src/styles.css");
|
|
145
150
|
const existingStyles = await fileExists(stylesPath) ? await readFile(stylesPath) : "";
|
|
146
|
-
if (!existingStyles.includes("@tailwind")) {
|
|
147
|
-
const
|
|
148
|
-
@tailwind components;
|
|
149
|
-
@tailwind utilities;
|
|
151
|
+
if (!existingStyles.includes("@import") && !existingStyles.includes("@tailwind")) {
|
|
152
|
+
const tailwindImport = `@import "tailwindcss";
|
|
150
153
|
|
|
151
154
|
`;
|
|
152
|
-
await writeFile(stylesPath,
|
|
155
|
+
await writeFile(stylesPath, tailwindImport + existingStyles);
|
|
156
|
+
}
|
|
157
|
+
const viteConfigPath = join(projectDir, "vite.config.ts");
|
|
158
|
+
if (await fileExists(viteConfigPath)) {
|
|
159
|
+
let viteConfig = await readFile(viteConfigPath);
|
|
160
|
+
if (!viteConfig.includes("@tailwindcss/vite")) {
|
|
161
|
+
viteConfig = `import tailwindcss from "@tailwindcss/vite";
|
|
162
|
+
${viteConfig}`;
|
|
163
|
+
viteConfig = viteConfig.replace(
|
|
164
|
+
/plugins:\s*\[/,
|
|
165
|
+
"plugins: [tailwindcss(), "
|
|
166
|
+
);
|
|
167
|
+
await writeFile(viteConfigPath, viteConfig);
|
|
168
|
+
}
|
|
153
169
|
}
|
|
154
170
|
const gitignorePath = join(projectDir, ".gitignore");
|
|
155
171
|
let gitignore = await fileExists(gitignorePath) ? await readFile(gitignorePath) : "";
|
|
@@ -162,43 +178,60 @@ ${item}`;
|
|
|
162
178
|
}
|
|
163
179
|
await writeFile(gitignorePath, gitignore.trim() + "\n");
|
|
164
180
|
await writeFile(join(projectDir, ".env.example"), "VITE_CONVEX_URL=\n");
|
|
165
|
-
step2.succeed(
|
|
181
|
+
step2.succeed("Forge customizations added");
|
|
166
182
|
} catch (err) {
|
|
167
|
-
step2.fail(
|
|
183
|
+
step2.fail("Failed to add customizations");
|
|
168
184
|
throw err;
|
|
169
185
|
}
|
|
170
186
|
logger.blank();
|
|
171
|
-
logger.log(` ${pc.
|
|
187
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
188
|
+
logger.log(` ${pc.cyan("Step 3/5:")} Dependencies`);
|
|
189
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
172
190
|
logger.blank();
|
|
173
191
|
try {
|
|
174
192
|
await runInteractive("pnpm", ["install"], projectDir);
|
|
193
|
+
logger.blank();
|
|
194
|
+
logger.success("Dependencies installed");
|
|
175
195
|
} catch {
|
|
176
196
|
logger.error("Failed to install dependencies");
|
|
177
197
|
process.exit(1);
|
|
178
198
|
}
|
|
179
199
|
logger.blank();
|
|
180
|
-
logger.log(` ${pc.
|
|
200
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
201
|
+
logger.log(` ${pc.cyan("Step 4/5:")} Convex`);
|
|
202
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
181
203
|
logger.blank();
|
|
182
204
|
try {
|
|
183
205
|
await runInteractive("npx", ["convex", "dev", "--once", "--configure=new"], projectDir);
|
|
206
|
+
logger.blank();
|
|
207
|
+
logger.success("Convex configured");
|
|
184
208
|
} catch {
|
|
185
|
-
logger.
|
|
209
|
+
logger.blank();
|
|
210
|
+
logger.warn("Convex setup skipped - run 'npx convex dev' later");
|
|
186
211
|
}
|
|
187
212
|
logger.blank();
|
|
188
|
-
logger.log(` ${pc.
|
|
213
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
214
|
+
logger.log(` ${pc.cyan("Step 5/5:")} shadcn/ui`);
|
|
215
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
189
216
|
logger.blank();
|
|
190
217
|
try {
|
|
191
218
|
await runInteractive("pnpm", ["dlx", "shadcn@latest", "init"], projectDir);
|
|
219
|
+
logger.blank();
|
|
220
|
+
logger.success("shadcn/ui configured");
|
|
192
221
|
} catch {
|
|
193
|
-
logger.
|
|
222
|
+
logger.blank();
|
|
223
|
+
logger.warn("shadcn setup skipped - run 'pnpm dlx shadcn init' later");
|
|
194
224
|
}
|
|
195
225
|
logger.blank();
|
|
226
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
196
227
|
logger.log(` ${pc.green("\u2713")} ${pc.bold("Project created successfully!")}`);
|
|
228
|
+
logger.log(` ${pc.dim("\u2500".repeat(50))}`);
|
|
197
229
|
logger.blank();
|
|
198
|
-
logger.log(` ${pc.
|
|
199
|
-
logger.log(` ${pc.cyan("
|
|
230
|
+
logger.log(` ${pc.dim("Next steps:")}`);
|
|
231
|
+
logger.log(` ${pc.cyan("$")} cd ${name}`);
|
|
232
|
+
logger.log(` ${pc.cyan("$")} pnpm dev`);
|
|
200
233
|
logger.blank();
|
|
201
|
-
logger.log(` ${pc.dim("CLAUDE.md
|
|
234
|
+
logger.log(` ${pc.dim("CLAUDE.md configured for Claude Code.")}`);
|
|
202
235
|
logger.blank();
|
|
203
236
|
}
|
|
204
237
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://biomejs.dev/schemas/
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
|
|
3
3
|
"vcs": {
|
|
4
4
|
"enabled": true,
|
|
5
5
|
"clientKind": "git",
|
|
@@ -7,15 +7,19 @@
|
|
|
7
7
|
},
|
|
8
8
|
"files": {
|
|
9
9
|
"ignoreUnknown": false,
|
|
10
|
-
"
|
|
10
|
+
"includes": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.json"]
|
|
11
11
|
},
|
|
12
12
|
"formatter": {
|
|
13
13
|
"enabled": true,
|
|
14
14
|
"indentStyle": "space",
|
|
15
15
|
"indentWidth": 2
|
|
16
16
|
},
|
|
17
|
-
"
|
|
18
|
-
"
|
|
17
|
+
"assist": {
|
|
18
|
+
"actions": {
|
|
19
|
+
"source": {
|
|
20
|
+
"organizeImports": "on"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
19
23
|
},
|
|
20
24
|
"linter": {
|
|
21
25
|
"enabled": true,
|
|
@@ -1,93 +1,51 @@
|
|
|
1
1
|
# CLAUDE.md
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Stack
|
|
4
|
+
TanStack Start + Convex + Tailwind v4 + shadcn/ui + Biome
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
## IMPORTANT: Use Forge CLI for Features
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Trigger Words → Action
|
|
12
|
-
|
|
13
|
-
| User says | You run |
|
|
14
|
-
|-----------|---------|
|
|
15
|
-
| "add feature", "create feature", "build feature" | `forge add:feature <name>` |
|
|
16
|
-
| "add X with Y" (any domain entity) | `forge add:feature <name>` |
|
|
17
|
-
| "new page for X" | `forge add:feature <name>` |
|
|
18
|
-
| "build X functionality" | `forge add:feature <name>` |
|
|
19
|
-
|
|
20
|
-
## File Creation Rules
|
|
21
|
-
|
|
22
|
-
DO NOT create these files manually:
|
|
23
|
-
- `src/features/**/*` (forge creates the structure)
|
|
24
|
-
- `convex/features/**/*` (forge creates the structure)
|
|
25
|
-
- `app/routes/<feature>/**/*` (forge creates the structure)
|
|
26
|
-
|
|
27
|
-
ONLY the forge CLI creates these. You fill them in after.
|
|
28
|
-
|
|
29
|
-
## What You CAN Create Manually
|
|
30
|
-
|
|
31
|
-
- Files inside existing feature component folders (after forge created them)
|
|
32
|
-
- `src/components/*` (shared UI)
|
|
33
|
-
- `src/lib/*` (utilities)
|
|
34
|
-
- `src/hooks/*` (global hooks)
|
|
8
|
+
BEFORE building any feature, YOU MUST run:
|
|
9
|
+
```bash
|
|
10
|
+
forge add:feature <name>
|
|
11
|
+
```
|
|
35
12
|
|
|
36
|
-
|
|
13
|
+
This scaffolds the complete vertical slice:
|
|
14
|
+
- `src/features/<name>/` (components, hooks)
|
|
15
|
+
- `convex/features/<name>/` (schema, queries, mutations)
|
|
16
|
+
- `src/routes/<name>/` (route pages)
|
|
37
17
|
|
|
38
|
-
|
|
18
|
+
NEVER create these paths manually. Edit the scaffolded files instead.
|
|
39
19
|
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
Run: forge add:feature comments
|
|
43
|
-
Edit: convex/features/comments/schema.ts (add fields for comments + replies)
|
|
44
|
-
Edit: convex/features/comments/queries.ts (add queries)
|
|
45
|
-
Edit: convex/features/comments/mutations.ts (add mutations)
|
|
46
|
-
Edit: src/features/comments/hooks.ts (add/modify hooks)
|
|
47
|
-
Create: src/features/comments/components/CommentCard.tsx
|
|
48
|
-
Create: src/features/comments/components/CommentList.tsx
|
|
49
|
-
Create: src/features/comments/components/ReplyForm.tsx
|
|
50
|
-
Update: src/features/comments/components/index.ts (add exports)
|
|
51
|
-
Edit: app/routes/comments/index.tsx (wire up components)
|
|
52
|
-
```
|
|
20
|
+
The ONLY route you may create directly is `src/routes/index.tsx` (homepage).
|
|
53
21
|
|
|
54
|
-
##
|
|
22
|
+
## Commands
|
|
55
23
|
|
|
56
|
-
Before finishing ANY task, run:
|
|
57
24
|
```bash
|
|
58
|
-
|
|
25
|
+
pnpm dev # Start dev server
|
|
26
|
+
npx convex dev # Start Convex backend
|
|
27
|
+
pnpm lint # Check with Biome
|
|
28
|
+
forge check # Validate architecture (run before finishing)
|
|
59
29
|
```
|
|
60
|
-
If it fails, fix ALL issues before responding to the user.
|
|
61
30
|
|
|
62
|
-
##
|
|
31
|
+
## Architecture
|
|
63
32
|
|
|
64
33
|
```
|
|
65
|
-
|
|
66
|
-
src/features/ →
|
|
67
|
-
src/components/ → Shared UI only
|
|
68
|
-
src/lib/ →
|
|
69
|
-
convex/features/ → Backend mirrors
|
|
34
|
+
src/routes/ → Thin route files (import from features, no logic)
|
|
35
|
+
src/features/ → Feature code (components/, hooks.ts)
|
|
36
|
+
src/components/ → Shared UI only
|
|
37
|
+
src/lib/ → Utilities
|
|
38
|
+
convex/features/ → Backend (mirrors src/features/)
|
|
70
39
|
```
|
|
71
40
|
|
|
72
41
|
## Rules
|
|
73
42
|
|
|
74
|
-
1.
|
|
75
|
-
2.
|
|
76
|
-
3.
|
|
77
|
-
4. **Components in components/**: All feature components in `src/features/<name>/components/`
|
|
78
|
-
5. **Mirror structure**: Every `src/features/X` has `convex/features/X`
|
|
79
|
-
|
|
80
|
-
## Stack Quick Reference
|
|
81
|
-
|
|
82
|
-
- **Data fetching**: Use hooks from `src/features/<name>/hooks.ts` (they wrap Convex)
|
|
83
|
-
- **Mutations**: Use mutation hooks from `src/features/<name>/hooks.ts`
|
|
84
|
-
- **UI primitives**: Import from `~/components/ui/*` (shadcn)
|
|
85
|
-
- **Styling**: Tailwind classes only, no CSS files
|
|
86
|
-
- **Forms**: react-hook-form + zod for validation
|
|
43
|
+
1. Routes are thin wrappers - no business logic, just imports and renders
|
|
44
|
+
2. No cross-feature imports (`src/features/X` cannot import from `src/features/Y`)
|
|
45
|
+
3. Each `src/features/X` has matching `convex/features/X`
|
|
87
46
|
|
|
88
|
-
##
|
|
47
|
+
## Quick Reference
|
|
89
48
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
| `forge check` | BEFORE completing any task |
|
|
49
|
+
- **Data/Mutations**: Use hooks from `src/features/<name>/hooks.ts`
|
|
50
|
+
- **UI Components**: Import from `~/components/ui/*` (shadcn)
|
|
51
|
+
- **Styling**: Tailwind classes only
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://biomejs.dev/schemas/
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
|
|
3
3
|
"vcs": {
|
|
4
4
|
"enabled": true,
|
|
5
5
|
"clientKind": "git",
|
|
@@ -7,15 +7,19 @@
|
|
|
7
7
|
},
|
|
8
8
|
"files": {
|
|
9
9
|
"ignoreUnknown": false,
|
|
10
|
-
"
|
|
10
|
+
"includes": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.json"]
|
|
11
11
|
},
|
|
12
12
|
"formatter": {
|
|
13
13
|
"enabled": true,
|
|
14
14
|
"indentStyle": "space",
|
|
15
15
|
"indentWidth": 2
|
|
16
16
|
},
|
|
17
|
-
"
|
|
18
|
-
"
|
|
17
|
+
"assist": {
|
|
18
|
+
"actions": {
|
|
19
|
+
"source": {
|
|
20
|
+
"organizeImports": "on"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
19
23
|
},
|
|
20
24
|
"linter": {
|
|
21
25
|
"enabled": true,
|
|
@@ -1,93 +1,51 @@
|
|
|
1
1
|
# CLAUDE.md
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Stack
|
|
4
|
+
TanStack Start + Convex + Tailwind v4 + shadcn/ui + Biome
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
## IMPORTANT: Use Forge CLI for Features
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Trigger Words → Action
|
|
12
|
-
|
|
13
|
-
| User says | You run |
|
|
14
|
-
|-----------|---------|
|
|
15
|
-
| "add feature", "create feature", "build feature" | `forge add:feature <name>` |
|
|
16
|
-
| "add X with Y" (any domain entity) | `forge add:feature <name>` |
|
|
17
|
-
| "new page for X" | `forge add:feature <name>` |
|
|
18
|
-
| "build X functionality" | `forge add:feature <name>` |
|
|
19
|
-
|
|
20
|
-
## File Creation Rules
|
|
21
|
-
|
|
22
|
-
DO NOT create these files manually:
|
|
23
|
-
- `src/features/**/*` (forge creates the structure)
|
|
24
|
-
- `convex/features/**/*` (forge creates the structure)
|
|
25
|
-
- `app/routes/<feature>/**/*` (forge creates the structure)
|
|
26
|
-
|
|
27
|
-
ONLY the forge CLI creates these. You fill them in after.
|
|
28
|
-
|
|
29
|
-
## What You CAN Create Manually
|
|
30
|
-
|
|
31
|
-
- Files inside existing feature component folders (after forge created them)
|
|
32
|
-
- `src/components/*` (shared UI)
|
|
33
|
-
- `src/lib/*` (utilities)
|
|
34
|
-
- `src/hooks/*` (global hooks)
|
|
8
|
+
BEFORE building any feature, YOU MUST run:
|
|
9
|
+
```bash
|
|
10
|
+
forge add:feature <name>
|
|
11
|
+
```
|
|
35
12
|
|
|
36
|
-
|
|
13
|
+
This scaffolds the complete vertical slice:
|
|
14
|
+
- `src/features/<name>/` (components, hooks)
|
|
15
|
+
- `convex/features/<name>/` (schema, queries, mutations)
|
|
16
|
+
- `src/routes/<name>/` (route pages)
|
|
37
17
|
|
|
38
|
-
|
|
18
|
+
NEVER create these paths manually. Edit the scaffolded files instead.
|
|
39
19
|
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
Run: forge add:feature comments
|
|
43
|
-
Edit: convex/features/comments/schema.ts (add fields for comments + replies)
|
|
44
|
-
Edit: convex/features/comments/queries.ts (add queries)
|
|
45
|
-
Edit: convex/features/comments/mutations.ts (add mutations)
|
|
46
|
-
Edit: src/features/comments/hooks.ts (add/modify hooks)
|
|
47
|
-
Create: src/features/comments/components/CommentCard.tsx
|
|
48
|
-
Create: src/features/comments/components/CommentList.tsx
|
|
49
|
-
Create: src/features/comments/components/ReplyForm.tsx
|
|
50
|
-
Update: src/features/comments/components/index.ts (add exports)
|
|
51
|
-
Edit: app/routes/comments/index.tsx (wire up components)
|
|
52
|
-
```
|
|
20
|
+
The ONLY route you may create directly is `src/routes/index.tsx` (homepage).
|
|
53
21
|
|
|
54
|
-
##
|
|
22
|
+
## Commands
|
|
55
23
|
|
|
56
|
-
Before finishing ANY task, run:
|
|
57
24
|
```bash
|
|
58
|
-
|
|
25
|
+
pnpm dev # Start dev server
|
|
26
|
+
npx convex dev # Start Convex backend
|
|
27
|
+
pnpm lint # Check with Biome
|
|
28
|
+
forge check # Validate architecture (run before finishing)
|
|
59
29
|
```
|
|
60
|
-
If it fails, fix ALL issues before responding to the user.
|
|
61
30
|
|
|
62
|
-
##
|
|
31
|
+
## Architecture
|
|
63
32
|
|
|
64
33
|
```
|
|
65
|
-
|
|
66
|
-
src/features/ →
|
|
67
|
-
src/components/ → Shared UI only
|
|
68
|
-
src/lib/ →
|
|
69
|
-
convex/features/ → Backend mirrors
|
|
34
|
+
src/routes/ → Thin route files (import from features, no logic)
|
|
35
|
+
src/features/ → Feature code (components/, hooks.ts)
|
|
36
|
+
src/components/ → Shared UI only
|
|
37
|
+
src/lib/ → Utilities
|
|
38
|
+
convex/features/ → Backend (mirrors src/features/)
|
|
70
39
|
```
|
|
71
40
|
|
|
72
41
|
## Rules
|
|
73
42
|
|
|
74
|
-
1.
|
|
75
|
-
2.
|
|
76
|
-
3.
|
|
77
|
-
4. **Components in components/**: All feature components in `src/features/<name>/components/`
|
|
78
|
-
5. **Mirror structure**: Every `src/features/X` has `convex/features/X`
|
|
79
|
-
|
|
80
|
-
## Stack Quick Reference
|
|
81
|
-
|
|
82
|
-
- **Data fetching**: Use hooks from `src/features/<name>/hooks.ts` (they wrap Convex)
|
|
83
|
-
- **Mutations**: Use mutation hooks from `src/features/<name>/hooks.ts`
|
|
84
|
-
- **UI primitives**: Import from `~/components/ui/*` (shadcn)
|
|
85
|
-
- **Styling**: Tailwind classes only, no CSS files
|
|
86
|
-
- **Forms**: react-hook-form + zod for validation
|
|
43
|
+
1. Routes are thin wrappers - no business logic, just imports and renders
|
|
44
|
+
2. No cross-feature imports (`src/features/X` cannot import from `src/features/Y`)
|
|
45
|
+
3. Each `src/features/X` has matching `convex/features/X`
|
|
87
46
|
|
|
88
|
-
##
|
|
47
|
+
## Quick Reference
|
|
89
48
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
| `forge check` | BEFORE completing any task |
|
|
49
|
+
- **Data/Mutations**: Use hooks from `src/features/<name>/hooks.ts`
|
|
50
|
+
- **UI Components**: Import from `~/components/ui/*` (shadcn)
|
|
51
|
+
- **Styling**: Tailwind classes only
|