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.
@@ -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, "app/routes", name, "index.tsx")
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, "app/routes", name, "$id.tsx")
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-UBPMMJ4L.js").then((m) => m.default),
23
- "add:feature": () => import("./add-feature-JBVJHKHX.js").then((m) => m.default),
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.cyan("Step 1/5:")} TanStack Start setup`);
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
- const step2 = logger.step(`${pc.cyan("Step 2/5:")} Adding Forge customizations...`);
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": "^1.9.4",
84
- autoprefixer: "^10.4.20",
85
- postcss: "^8.5.0",
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 tailwindDirectives = `@tailwind base;
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, tailwindDirectives + existingStyles);
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(`${pc.cyan("Step 2/5:")} Forge customizations added`);
181
+ step2.succeed("Forge customizations added");
166
182
  } catch (err) {
167
- step2.fail(`${pc.cyan("Step 2/5:")} Failed to add customizations`);
183
+ step2.fail("Failed to add customizations");
168
184
  throw err;
169
185
  }
170
186
  logger.blank();
171
- logger.log(` ${pc.cyan("Step 3/5:")} Installing dependencies...`);
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.cyan("Step 4/5:")} Convex setup`);
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.warn("Convex setup skipped or failed - you can run it later");
209
+ logger.blank();
210
+ logger.warn("Convex setup skipped - run 'npx convex dev' later");
186
211
  }
187
212
  logger.blank();
188
- logger.log(` ${pc.cyan("Step 5/5:")} shadcn/ui setup`);
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.warn("shadcn setup skipped or failed - you can run it later");
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.cyan("cd")} ${name}`);
199
- logger.log(` ${pc.cyan("pnpm dev")}`);
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 is configured. Claude Code will use forge CLI automatically.")}`);
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/1.9.4/schema.json",
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
- "ignore": ["node_modules", "dist", ".vinxi", "convex/_generated"]
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
- "organizeImports": {
18
- "enabled": true
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
- ## YOU MUST USE FORGE CLI
3
+ ## Stack
4
+ TanStack Start + Convex + Tailwind v4 + shadcn/ui + Biome
4
5
 
5
- When the user asks you to build ANY feature, you MUST:
6
+ ## IMPORTANT: Use Forge CLI for Features
6
7
 
7
- 1. FIRST run `forge add:feature <name>`
8
- 2. THEN fill in the generated files
9
- 3. NEVER create feature files manually
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
- ## Workflow Example
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
- User: "Add a comments feature with replies"
18
+ NEVER create these paths manually. Edit the scaffolded files instead.
39
19
 
40
- You MUST:
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
- ## Validation
22
+ ## Commands
55
23
 
56
- Before finishing ANY task, run:
57
24
  ```bash
58
- forge check
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
- ## Project Structure
31
+ ## Architecture
63
32
 
64
33
  ```
65
- app/routes/ → Thin route files only (import from features, no logic)
66
- src/features/ → All feature code (components, hooks, types)
67
- src/components/ → Shared UI only (used across features)
68
- src/lib/ → Pure utilities
69
- convex/features/ → Backend mirrors frontend features
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. **Routes are thin**: Only import and render. No business logic. No hooks defined here.
75
- 2. **No cross-feature imports**: `src/features/X` cannot import from `src/features/Y`
76
- 3. **Hooks in hooks.ts**: All feature hooks in `src/features/<name>/hooks.ts`
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
- ## Commands Reference
47
+ ## Quick Reference
89
48
 
90
- | Command | When to use |
91
- |---------|-------------|
92
- | `forge add:feature <name>` | BEFORE building any new feature |
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,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-forge-cli",
3
- "version": "0.2.3",
3
+ "version": "0.3.2",
4
4
  "description": "TypeScript stack scaffolding & enforcement CLI for TanStack Start + Convex",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
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
- "ignore": ["node_modules", "dist", ".vinxi", "convex/_generated"]
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
- "organizeImports": {
18
- "enabled": true
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
- ## YOU MUST USE FORGE CLI
3
+ ## Stack
4
+ TanStack Start + Convex + Tailwind v4 + shadcn/ui + Biome
4
5
 
5
- When the user asks you to build ANY feature, you MUST:
6
+ ## IMPORTANT: Use Forge CLI for Features
6
7
 
7
- 1. FIRST run `forge add:feature <name>`
8
- 2. THEN fill in the generated files
9
- 3. NEVER create feature files manually
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
- ## Workflow Example
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
- User: "Add a comments feature with replies"
18
+ NEVER create these paths manually. Edit the scaffolded files instead.
39
19
 
40
- You MUST:
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
- ## Validation
22
+ ## Commands
55
23
 
56
- Before finishing ANY task, run:
57
24
  ```bash
58
- forge check
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
- ## Project Structure
31
+ ## Architecture
63
32
 
64
33
  ```
65
- app/routes/ → Thin route files only (import from features, no logic)
66
- src/features/ → All feature code (components, hooks, types)
67
- src/components/ → Shared UI only (used across features)
68
- src/lib/ → Pure utilities
69
- convex/features/ → Backend mirrors frontend features
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. **Routes are thin**: Only import and render. No business logic. No hooks defined here.
75
- 2. **No cross-feature imports**: `src/features/X` cannot import from `src/features/Y`
76
- 3. **Hooks in hooks.ts**: All feature hooks in `src/features/<name>/hooks.ts`
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
- ## Commands Reference
47
+ ## Quick Reference
89
48
 
90
- | Command | When to use |
91
- |---------|-------------|
92
- | `forge add:feature <name>` | BEFORE building any new feature |
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
@@ -1,6 +0,0 @@
1
- export default {
2
- plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
5
- },
6
- };
@@ -1,12 +0,0 @@
1
- import type { Config } from "tailwindcss";
2
-
3
- export default {
4
- content: [
5
- "./app/**/*.{js,ts,jsx,tsx}",
6
- "./src/**/*.{js,ts,jsx,tsx}",
7
- ],
8
- theme: {
9
- extend: {},
10
- },
11
- plugins: [],
12
- } satisfies Config;
@@ -1,6 +0,0 @@
1
- export default {
2
- plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
5
- },
6
- };
@@ -1,12 +0,0 @@
1
- import type { Config } from "tailwindcss";
2
-
3
- export default {
4
- content: [
5
- "./app/**/*.{js,ts,jsx,tsx}",
6
- "./src/**/*.{js,ts,jsx,tsx}",
7
- ],
8
- theme: {
9
- extend: {},
10
- },
11
- plugins: [],
12
- } satisfies Config;