forgedev 1.0.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.md +38 -0
- package/LICENSE +21 -0
- package/README.md +246 -0
- package/bin/devforge.js +4 -0
- package/package.json +33 -0
- package/src/claude-configurator.js +260 -0
- package/src/cli.js +119 -0
- package/src/composer.js +214 -0
- package/src/doctor-checks.js +743 -0
- package/src/doctor-prompts.js +295 -0
- package/src/doctor.js +281 -0
- package/src/guided.js +315 -0
- package/src/index.js +148 -0
- package/src/init-mode.js +134 -0
- package/src/prompts.js +155 -0
- package/src/recommender.js +186 -0
- package/src/scanner.js +368 -0
- package/src/uat-generator.js +189 -0
- package/src/utils.js +57 -0
- package/templates/auth/jwt-custom/backend/app/api/auth.py.template +45 -0
- package/templates/auth/jwt-custom/backend/app/api/deps.py.template +16 -0
- package/templates/auth/jwt-custom/backend/app/core/security.py.template +34 -0
- package/templates/auth/nextauth/src/app/api/auth/[...nextauth]/route.ts.template +3 -0
- package/templates/auth/nextauth/src/lib/auth.ts.template +30 -0
- package/templates/auth/nextauth/src/middleware.ts.template +14 -0
- package/templates/backend/fastapi/backend/Dockerfile.template +12 -0
- package/templates/backend/fastapi/backend/app/__init__.py +0 -0
- package/templates/backend/fastapi/backend/app/api/__init__.py +0 -0
- package/templates/backend/fastapi/backend/app/api/health.py.template +32 -0
- package/templates/backend/fastapi/backend/app/core/__init__.py +0 -0
- package/templates/backend/fastapi/backend/app/core/config.py.template +25 -0
- package/templates/backend/fastapi/backend/app/core/errors.py +37 -0
- package/templates/backend/fastapi/backend/app/core/retry.py +32 -0
- package/templates/backend/fastapi/backend/app/main.py.template +58 -0
- package/templates/backend/fastapi/backend/app/models/__init__.py +0 -0
- package/templates/backend/fastapi/backend/app/schemas/__init__.py +0 -0
- package/templates/backend/fastapi/backend/pyproject.toml.template +19 -0
- package/templates/backend/fastapi/backend/requirements.txt.template +14 -0
- package/templates/base/.gitignore.template +29 -0
- package/templates/base/README.md.template +25 -0
- package/templates/claude-code/agents/code-quality-reviewer.md +41 -0
- package/templates/claude-code/agents/production-readiness.md +55 -0
- package/templates/claude-code/agents/security-reviewer.md +41 -0
- package/templates/claude-code/agents/spec-validator.md +34 -0
- package/templates/claude-code/agents/uat-validator.md +37 -0
- package/templates/claude-code/claude-md/base.md +33 -0
- package/templates/claude-code/claude-md/fastapi.md +12 -0
- package/templates/claude-code/claude-md/fullstack.md +12 -0
- package/templates/claude-code/claude-md/nextjs.md +11 -0
- package/templates/claude-code/commands/audit-security.md +11 -0
- package/templates/claude-code/commands/audit-spec.md +9 -0
- package/templates/claude-code/commands/audit-wiring.md +17 -0
- package/templates/claude-code/commands/done.md +19 -0
- package/templates/claude-code/commands/generate-prd.md +45 -0
- package/templates/claude-code/commands/generate-uat.md +35 -0
- package/templates/claude-code/commands/help.md +26 -0
- package/templates/claude-code/commands/next.md +20 -0
- package/templates/claude-code/commands/optimize-claude-md.md +31 -0
- package/templates/claude-code/commands/pre-pr.md +19 -0
- package/templates/claude-code/commands/run-uat.md +21 -0
- package/templates/claude-code/commands/status.md +24 -0
- package/templates/claude-code/commands/verify-all.md +11 -0
- package/templates/claude-code/hooks/polyglot.json +36 -0
- package/templates/claude-code/hooks/python.json +36 -0
- package/templates/claude-code/hooks/scripts/autofix-polyglot.sh +16 -0
- package/templates/claude-code/hooks/scripts/autofix-python.sh +14 -0
- package/templates/claude-code/hooks/scripts/autofix-typescript.sh +14 -0
- package/templates/claude-code/hooks/scripts/guard-protected-files.sh +21 -0
- package/templates/claude-code/hooks/typescript.json +36 -0
- package/templates/claude-code/skills/ai-prompts/SKILL.md +43 -0
- package/templates/claude-code/skills/fastapi/SKILL.md +38 -0
- package/templates/claude-code/skills/nextjs/SKILL.md +39 -0
- package/templates/claude-code/skills/playwright/SKILL.md +37 -0
- package/templates/claude-code/skills/security-api/SKILL.md +47 -0
- package/templates/claude-code/skills/security-web/SKILL.md +41 -0
- package/templates/database/prisma-postgres/.env.example +1 -0
- package/templates/database/prisma-postgres/prisma/schema.prisma.template +18 -0
- package/templates/database/sqlalchemy-postgres/.env.example +1 -0
- package/templates/database/sqlalchemy-postgres/backend/alembic/env.py.template +40 -0
- package/templates/database/sqlalchemy-postgres/backend/alembic/versions/.gitkeep +0 -0
- package/templates/database/sqlalchemy-postgres/backend/alembic.ini.template +36 -0
- package/templates/database/sqlalchemy-postgres/backend/app/db/__init__.py +0 -0
- package/templates/database/sqlalchemy-postgres/backend/app/db/base.py +5 -0
- package/templates/database/sqlalchemy-postgres/backend/app/db/session.py.template +48 -0
- package/templates/frontend/nextjs/next.config.ts.template +7 -0
- package/templates/frontend/nextjs/package.json.template +41 -0
- package/templates/frontend/nextjs/postcss.config.mjs +7 -0
- package/templates/frontend/nextjs/src/app/api/health/route.ts.template +10 -0
- package/templates/frontend/nextjs/src/app/globals.css +1 -0
- package/templates/frontend/nextjs/src/app/layout.tsx.template +22 -0
- package/templates/frontend/nextjs/src/app/page.tsx.template +10 -0
- package/templates/frontend/nextjs/src/lib/db.ts.template +40 -0
- package/templates/frontend/nextjs/src/lib/errors.ts +28 -0
- package/templates/frontend/nextjs/src/lib/utils.ts +6 -0
- package/templates/frontend/nextjs/tsconfig.json +23 -0
- package/templates/infra/docker-compose/docker-compose.yml.template +19 -0
- package/templates/testing/playwright/e2e/example.spec.ts.template +15 -0
- package/templates/testing/playwright/playwright.config.ts.template +22 -0
- package/templates/testing/vitest/src/__tests__/example.test.ts.template +12 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# DevForge
|
|
2
|
+
|
|
3
|
+
## WHAT
|
|
4
|
+
- Node.js CLI tool for universal project scaffolding
|
|
5
|
+
- ESM modules only (no require/CommonJS)
|
|
6
|
+
- Dependencies: Inquirer.js (prompts), Chalk (colors), Vitest (tests)
|
|
7
|
+
|
|
8
|
+
## Directory Map
|
|
9
|
+
- `bin/` — CLI entry point (`devforge.js`)
|
|
10
|
+
- `src/` — Core logic (index, prompts, recommender, composer, claude-configurator, uat-generator, utils)
|
|
11
|
+
- `templates/` — Scaffold templates organized by category (base, frontend, backend, database, auth, testing, infra, claude-code)
|
|
12
|
+
- `tests/` — Vitest test files
|
|
13
|
+
- `docs/` — Reference documentation (prompt library, playbook, multi-agent verification)
|
|
14
|
+
|
|
15
|
+
## HOW
|
|
16
|
+
- Lint: `npx eslint . --ext .js` (when eslint is added)
|
|
17
|
+
- Test: `npx vitest run`
|
|
18
|
+
- Test (watch): `npx vitest`
|
|
19
|
+
- Manual test: `node bin/devforge.js test-output`
|
|
20
|
+
|
|
21
|
+
## Commands
|
|
22
|
+
- `/project:help`, `/project:status`, `/project:next`, `/project:done` — daily workflow
|
|
23
|
+
- `/project:verify-all`, `/project:audit-spec`, `/project:audit-wiring`, `/project:audit-security` — verification
|
|
24
|
+
- `/project:pre-pr`, `/project:run-uat` — release workflow
|
|
25
|
+
|
|
26
|
+
## Agents (all READ-ONLY, disallowedTools: Write/Edit/MultiEdit)
|
|
27
|
+
- code-quality-reviewer, security-reviewer, spec-validator, production-readiness, uat-validator
|
|
28
|
+
|
|
29
|
+
## RULES
|
|
30
|
+
- ESM only — use `import`/`export`, never `require()`
|
|
31
|
+
- All source files are plain `.js` (no TypeScript for the CLI itself)
|
|
32
|
+
- Templates use `{{VARIABLE_NAME}}` placeholders — replaced via simple regex
|
|
33
|
+
- Files ending in `.template` get variable substitution; all others are binary-copied
|
|
34
|
+
- Template modules are composable: `templates/<category>/<stack>/` mirrors the output project structure
|
|
35
|
+
- Never modify files in `docs/` — those are read-only reference documents
|
|
36
|
+
- Keep `src/` files focused: each file has a single responsibility
|
|
37
|
+
- The recommender is a pure function: `(serviceType, refinements) → stackConfig`
|
|
38
|
+
- V1 supports 3 stacks: Next.js full-stack, FastAPI backend, polyglot (Next.js + FastAPI)
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DevForge Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# DevForge
|
|
2
|
+
|
|
3
|
+
Universal, AI-first project scaffolding CLI. Describe what you're building, get the right stack recommended, and ship with Claude Code infrastructure pre-configured.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# New project — guided (for beginners)
|
|
9
|
+
npx devforge new my-app
|
|
10
|
+
|
|
11
|
+
# New project — shorthand
|
|
12
|
+
npx devforge my-app
|
|
13
|
+
|
|
14
|
+
# Add dev guardrails to existing project
|
|
15
|
+
npx devforge init
|
|
16
|
+
|
|
17
|
+
# Diagnose and optimize existing project
|
|
18
|
+
npx devforge doctor
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Four Modes, Four Audiences
|
|
22
|
+
|
|
23
|
+
### 1. Guided Mode (beginners & non-developers)
|
|
24
|
+
|
|
25
|
+
Describe what you want in plain English. DevForge picks the stack.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
$ npx devforge new my-app
|
|
29
|
+
|
|
30
|
+
🔨 DevForge — Let's build something.
|
|
31
|
+
|
|
32
|
+
? How would you like to start?
|
|
33
|
+
💬 Describe what you want to build (recommended for beginners)
|
|
34
|
+
⚡ I know my stack — let me pick (for developers)
|
|
35
|
+
|
|
36
|
+
> Describe
|
|
37
|
+
|
|
38
|
+
Tell me about what you want to build:
|
|
39
|
+
> I want an app where restaurants manage their menu and customers order food
|
|
40
|
+
|
|
41
|
+
Got it! Here's what I'll set up for you:
|
|
42
|
+
|
|
43
|
+
What you'll get:
|
|
44
|
+
├── A website where you can:
|
|
45
|
+
│ • Manage menu
|
|
46
|
+
│ • Manage orders
|
|
47
|
+
│
|
|
48
|
+
├── User accounts (with different roles like admin and user)
|
|
49
|
+
├── Payment processing for orders or subscriptions
|
|
50
|
+
├── Search and filtering
|
|
51
|
+
├── A database to store all your data
|
|
52
|
+
│
|
|
53
|
+
└── Developer tools:
|
|
54
|
+
• Code quality checks (catches errors automatically)
|
|
55
|
+
• Guided workflows (type /project:help anytime you're stuck)
|
|
56
|
+
• Testing templates
|
|
57
|
+
|
|
58
|
+
? Sound right? Yes — create it!
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Zero technical jargon. DevForge makes all the decisions. After scaffolding, generates `docs/getting-started.md` with a beginner-friendly walkthrough.
|
|
62
|
+
|
|
63
|
+
### 2. Developer Mode (developers who know their stack)
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
$ npx devforge new my-app
|
|
67
|
+
|
|
68
|
+
? How would you like to start?
|
|
69
|
+
⚡ I know my stack — let me pick
|
|
70
|
+
|
|
71
|
+
? What are you building? Full-stack app
|
|
72
|
+
? Backend language? Python (polyglot)
|
|
73
|
+
? Need authentication? Yes
|
|
74
|
+
? Deployment target? Docker
|
|
75
|
+
|
|
76
|
+
Recommended stack:
|
|
77
|
+
Frontend: nextjs + typescript + tailwind + shadcn
|
|
78
|
+
Backend: fastapi + python + sqlalchemy
|
|
79
|
+
Database: postgresql (both)
|
|
80
|
+
Auth: both
|
|
81
|
+
Testing: vitest + playwright + pytest
|
|
82
|
+
Deploy: docker
|
|
83
|
+
Claude: CLAUDE.md + hooks + skills + agents + commands
|
|
84
|
+
|
|
85
|
+
? Proceed with this stack? Yes
|
|
86
|
+
|
|
87
|
+
✓ Done! Your project is ready.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 3. Init Mode (add guardrails to existing projects)
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
$ cd my-existing-project
|
|
94
|
+
$ npx devforge init
|
|
95
|
+
|
|
96
|
+
🔨 DevForge — Adding dev guardrails
|
|
97
|
+
|
|
98
|
+
Scanning...
|
|
99
|
+
|
|
100
|
+
Detected: nextjs (typescript) + fastapi (python) + postgresql (prisma) + vitest + playwright + pytest
|
|
101
|
+
|
|
102
|
+
Installing:
|
|
103
|
+
✓ .claude/hooks/ — auto-lint, quality gate, file protection
|
|
104
|
+
✓ .claude/agents/ — code quality, security, spec validator
|
|
105
|
+
✓ .claude/commands/ — help, status, next, done, audit, pre-pr
|
|
106
|
+
✓ .claude/skills/ — framework-specific knowledge
|
|
107
|
+
✓ docs/uat/ — acceptance test templates
|
|
108
|
+
⊘ CLAUDE.md — exists (tip: run /project:optimize-claude-md to slim it)
|
|
109
|
+
|
|
110
|
+
Done. Type /project:help to get started.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Zero questions. Scans, detects, installs.
|
|
114
|
+
|
|
115
|
+
### 4. Doctor Mode (diagnose & optimize existing projects)
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
$ npx devforge doctor
|
|
119
|
+
|
|
120
|
+
🔨 DevForge Doctor — Project Health Check
|
|
121
|
+
|
|
122
|
+
Scanning...
|
|
123
|
+
|
|
124
|
+
📊 Project Vitals:
|
|
125
|
+
Frontend: nextjs (typescript)
|
|
126
|
+
Backend: fastapi (python)
|
|
127
|
+
Database: postgresql (sqlalchemy)
|
|
128
|
+
Testing: vitest + playwright + pytest
|
|
129
|
+
|
|
130
|
+
Health Issues Found:
|
|
131
|
+
|
|
132
|
+
🔴 CRITICAL
|
|
133
|
+
1. CLAUDE.md is 647 lines (recommended limit: 150)
|
|
134
|
+
→ Instructions are being dropped
|
|
135
|
+
2. 4 endpoints have no authentication
|
|
136
|
+
→ Security vulnerability
|
|
137
|
+
|
|
138
|
+
🟡 WARNING
|
|
139
|
+
3. No health check endpoint
|
|
140
|
+
4. No UAT scenarios
|
|
141
|
+
5. 3 bare except: blocks
|
|
142
|
+
|
|
143
|
+
? What would you like to do?
|
|
144
|
+
🚑 Fix critical issues (guided, one at a time)
|
|
145
|
+
📋 Generate a full report (save to docs/doctor-report.md)
|
|
146
|
+
⚡ Auto-fix what's safe to auto-fix
|
|
147
|
+
📖 Just show me what to do (generates prompts for Claude Code)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Doctor diagnoses problems and generates the exact Claude Code prompt to fix each one.
|
|
151
|
+
|
|
152
|
+
## Supported Stacks (V1)
|
|
153
|
+
|
|
154
|
+
| Selection | Stack |
|
|
155
|
+
|---|---|
|
|
156
|
+
| Web app / Full-stack + TypeScript | Next.js 15 + Prisma + PostgreSQL + NextAuth + Vitest + Playwright |
|
|
157
|
+
| API service + Python | FastAPI + SQLAlchemy 2.0 + PostgreSQL + Alembic + Pytest |
|
|
158
|
+
| Full-stack + TS + Python | Next.js frontend + FastAPI backend (polyglot monorepo) |
|
|
159
|
+
| AI/ML service | Polyglot full-stack with AI integration flag |
|
|
160
|
+
|
|
161
|
+
## What Gets Generated
|
|
162
|
+
|
|
163
|
+
Every project includes:
|
|
164
|
+
|
|
165
|
+
- **Project scaffold** with working code, configs, and dependencies
|
|
166
|
+
- **Health check endpoints** (`/health`, `/healthz`)
|
|
167
|
+
- **Graceful shutdown handlers**
|
|
168
|
+
- **Database connection retry** with exponential backoff
|
|
169
|
+
- **Structured error responses** (never leaks stack traces)
|
|
170
|
+
|
|
171
|
+
With Claude Code infrastructure enabled (default):
|
|
172
|
+
|
|
173
|
+
- **CLAUDE.md** tailored to your stack
|
|
174
|
+
- **Hooks** — auto-lint on edit, quality gate on stop
|
|
175
|
+
- **Skills** — framework-specific knowledge
|
|
176
|
+
- **Agents** — 5-agent verification chain
|
|
177
|
+
- **Commands** — verify-all, audit-spec, audit-wiring, audit-security, pre-pr, run-uat, generate-prd, generate-uat, optimize-claude-md
|
|
178
|
+
- **UAT templates** — scenario packs and CSV checklists
|
|
179
|
+
- **Prompt library** — the complete development prompt library
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npm install
|
|
185
|
+
npm test # run unit tests
|
|
186
|
+
node bin/devforge.js test-output # manual smoke test (guided + developer)
|
|
187
|
+
node bin/devforge.js init # test init mode (from any project dir)
|
|
188
|
+
node bin/devforge.js doctor # test doctor mode (from any project dir)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Project Structure
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
devforge/
|
|
195
|
+
├── bin/devforge.js # CLI entry point
|
|
196
|
+
├── src/
|
|
197
|
+
│ ├── cli.js # Command router (new, init, doctor)
|
|
198
|
+
│ ├── index.js # New project orchestrator (guided + developer)
|
|
199
|
+
│ ├── guided.js # Guided mode (description → stack)
|
|
200
|
+
│ ├── prompts.js # Interactive prompts (Inquirer.js)
|
|
201
|
+
│ ├── recommender.js # Service type → stack recommendation
|
|
202
|
+
│ ├── composer.js # Template composition engine
|
|
203
|
+
│ ├── claude-configurator.js # Generates .claude/ infrastructure
|
|
204
|
+
│ ├── uat-generator.js # Generates UAT templates
|
|
205
|
+
│ ├── scanner.js # Project scanner (for init + doctor)
|
|
206
|
+
│ ├── init-mode.js # Init mode orchestrator
|
|
207
|
+
│ ├── doctor.js # Doctor mode orchestrator
|
|
208
|
+
│ ├── doctor-checks.js # Diagnostic check functions
|
|
209
|
+
│ ├── doctor-prompts.js # Fix prompt generators
|
|
210
|
+
│ └── utils.js # File ops, logging, colors
|
|
211
|
+
├── templates/ # Scaffold templates by category
|
|
212
|
+
│ ├── base/ # Every project gets this
|
|
213
|
+
│ ├── frontend/nextjs/ # Next.js App Router
|
|
214
|
+
│ ├── backend/fastapi/ # FastAPI + SQLAlchemy
|
|
215
|
+
│ ├── database/ # Prisma, SQLAlchemy
|
|
216
|
+
│ ├── auth/ # NextAuth, JWT
|
|
217
|
+
│ ├── testing/ # Vitest, Playwright, Pytest
|
|
218
|
+
│ ├── infra/ # Docker Compose, GitHub Actions
|
|
219
|
+
│ └── claude-code/ # Hooks, CLAUDE.md, skills, agents, commands
|
|
220
|
+
├── tests/ # Vitest tests
|
|
221
|
+
└── docs/ # Reference documentation
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Claude Code Commands
|
|
225
|
+
|
|
226
|
+
| Command | What It Does |
|
|
227
|
+
|---------|-------------|
|
|
228
|
+
| `/project:help` | Asks your situation, gives the exact prompt |
|
|
229
|
+
| `/project:status` | Project dashboard — tests, branch, changes |
|
|
230
|
+
| `/project:next` | Figures out your next task |
|
|
231
|
+
| `/project:done` | Verifies task completion |
|
|
232
|
+
| `/project:generate-prd` | Generates a PRD with Mermaid diagrams |
|
|
233
|
+
| `/project:generate-uat` | Generates UAT scenarios from codebase |
|
|
234
|
+
| `/project:optimize-claude-md` | Proposes splitting an oversized CLAUDE.md |
|
|
235
|
+
|
|
236
|
+
## Roadmap
|
|
237
|
+
|
|
238
|
+
- [ ] Go + Gin/Chi backend
|
|
239
|
+
- [ ] Rust + Axum backend
|
|
240
|
+
- [ ] React + Vite SPA (frontend-only)
|
|
241
|
+
- [ ] React Native / Expo mobile
|
|
242
|
+
- [ ] Plugin ecosystem for community templates
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
MIT
|
package/bin/devforge.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "forgedev",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Universal, AI-first project scaffolding CLI with Claude Code infrastructure",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"forgedev": "bin/devforge.js",
|
|
8
|
+
"devforge": "bin/devforge.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"scaffolding",
|
|
16
|
+
"cli",
|
|
17
|
+
"project-generator",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"ai-first"
|
|
20
|
+
],
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"chalk": "^5.4.1",
|
|
25
|
+
"@inquirer/prompts": "^7.10.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"vitest": "^3.1.1"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ROOT_DIR, ensureDir, writeFile, readTemplate, replaceVars, log } from './utils.js';
|
|
4
|
+
|
|
5
|
+
const CLAUDE_TEMPLATES_DIR = path.join(ROOT_DIR, 'templates', 'claude-code');
|
|
6
|
+
const DOCS_DIR = path.join(ROOT_DIR, 'docs');
|
|
7
|
+
|
|
8
|
+
export async function generateClaudeConfig(outputDir, stackConfig, options = {}) {
|
|
9
|
+
const vars = buildClaudeVars(stackConfig);
|
|
10
|
+
|
|
11
|
+
if (!options.skipClaudeMd) {
|
|
12
|
+
generateClaudeMd(outputDir, stackConfig, vars);
|
|
13
|
+
}
|
|
14
|
+
generateHooks(outputDir, stackConfig, { merge: options.mergeSettings });
|
|
15
|
+
generateSkills(outputDir, stackConfig);
|
|
16
|
+
generateAgents(outputDir, stackConfig, vars);
|
|
17
|
+
generateCommands(outputDir, stackConfig, vars);
|
|
18
|
+
copyPromptLibrary(outputDir);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function buildClaudeVars(config) {
|
|
22
|
+
const vars = {
|
|
23
|
+
PROJECT_NAME: config.projectName,
|
|
24
|
+
PROJECT_NAME_PASCAL: config.projectName.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(''),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (config.stackId === 'nextjs-fullstack') {
|
|
28
|
+
vars.STACK_SUMMARY = 'Next.js 15 (App Router) + TypeScript + Tailwind CSS + Prisma + PostgreSQL';
|
|
29
|
+
vars.LINT_COMMAND = 'npx eslint .';
|
|
30
|
+
vars.TYPE_CHECK_COMMAND = 'npx tsc --noEmit';
|
|
31
|
+
vars.TEST_COMMAND = 'npx vitest run';
|
|
32
|
+
vars.BUILD_COMMAND = 'npm run build';
|
|
33
|
+
vars.DEV_COMMAND = 'npm run dev';
|
|
34
|
+
vars.DIR_MAP = `- src/app/ — Next.js App Router pages and API routes
|
|
35
|
+
- src/lib/ — Shared utilities, database client, error handling
|
|
36
|
+
- src/components/ — React components
|
|
37
|
+
- prisma/ — Database schema and migrations
|
|
38
|
+
- e2e/ — Playwright E2E tests`;
|
|
39
|
+
} else if (config.stackId === 'fastapi-backend') {
|
|
40
|
+
vars.STACK_SUMMARY = 'FastAPI + Python + SQLAlchemy 2.0 + PostgreSQL + Alembic';
|
|
41
|
+
vars.LINT_COMMAND = 'ruff check .';
|
|
42
|
+
vars.TYPE_CHECK_COMMAND = 'pyright';
|
|
43
|
+
vars.TEST_COMMAND = 'pytest';
|
|
44
|
+
vars.BUILD_COMMAND = 'docker build -t app .';
|
|
45
|
+
vars.DEV_COMMAND = 'uvicorn app.main:app --reload';
|
|
46
|
+
vars.DIR_MAP = `- backend/app/ — FastAPI application
|
|
47
|
+
- backend/app/api/ — API route handlers
|
|
48
|
+
- backend/app/core/ — Config, security, error handling
|
|
49
|
+
- backend/app/db/ — Database session and models
|
|
50
|
+
- backend/app/models/ — SQLAlchemy models
|
|
51
|
+
- backend/app/schemas/ — Pydantic schemas
|
|
52
|
+
- backend/tests/ — Pytest tests
|
|
53
|
+
- backend/alembic/ — Database migrations`;
|
|
54
|
+
} else if (config.stackId === 'polyglot-fullstack') {
|
|
55
|
+
vars.STACK_SUMMARY = 'Next.js 15 (frontend) + FastAPI (backend) + PostgreSQL';
|
|
56
|
+
vars.LINT_COMMAND = 'cd frontend && npx eslint . && cd ../backend && ruff check .';
|
|
57
|
+
vars.TYPE_CHECK_COMMAND = 'cd frontend && npx tsc --noEmit';
|
|
58
|
+
vars.TEST_COMMAND = 'cd frontend && npx vitest run && cd ../backend && pytest';
|
|
59
|
+
vars.BUILD_COMMAND = 'docker compose build';
|
|
60
|
+
vars.DEV_COMMAND = 'docker compose up';
|
|
61
|
+
vars.DIR_MAP = `- frontend/ — Next.js 15 App Router application
|
|
62
|
+
- frontend/src/app/ — Pages and API routes
|
|
63
|
+
- frontend/src/lib/ — Shared utilities
|
|
64
|
+
- backend/ — FastAPI application
|
|
65
|
+
- backend/app/api/ — API route handlers
|
|
66
|
+
- backend/app/core/ — Config, security, error handling
|
|
67
|
+
- backend/app/db/ — Database session and models
|
|
68
|
+
- e2e/ — Playwright E2E tests`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Build skills list for CLAUDE.md reference
|
|
72
|
+
const skillsList = [];
|
|
73
|
+
if (config.frontend?.framework === 'nextjs') {
|
|
74
|
+
skillsList.push('- `@.claude/skills/nextjs/` — Next.js patterns and conventions');
|
|
75
|
+
skillsList.push('- `@.claude/skills/security-web/` — Frontend security practices');
|
|
76
|
+
}
|
|
77
|
+
if (config.backend?.framework === 'fastapi') {
|
|
78
|
+
skillsList.push('- `@.claude/skills/fastapi/` — FastAPI patterns and conventions');
|
|
79
|
+
skillsList.push('- `@.claude/skills/security-api/` — API security practices');
|
|
80
|
+
}
|
|
81
|
+
if (config.testing?.e2e === 'playwright') {
|
|
82
|
+
skillsList.push('- `@.claude/skills/playwright/` — E2E testing patterns');
|
|
83
|
+
}
|
|
84
|
+
if (config.ai) {
|
|
85
|
+
skillsList.push('- `@.claude/skills/ai-prompts/` — AI/LLM prompt patterns');
|
|
86
|
+
}
|
|
87
|
+
vars.SKILLS_LIST = skillsList.length > 0 ? skillsList.join('\n') : '- (none generated)';
|
|
88
|
+
|
|
89
|
+
return vars;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function generateClaudeMd(outputDir, config, vars) {
|
|
93
|
+
// Read base template
|
|
94
|
+
const basePath = path.join(CLAUDE_TEMPLATES_DIR, 'claude-md', 'base.md');
|
|
95
|
+
let content = readTemplate(basePath);
|
|
96
|
+
|
|
97
|
+
// Read stack-specific section
|
|
98
|
+
let stackSection = '';
|
|
99
|
+
if (config.stackId === 'nextjs-fullstack') {
|
|
100
|
+
stackSection = readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'claude-md', 'nextjs.md'));
|
|
101
|
+
} else if (config.stackId === 'fastapi-backend') {
|
|
102
|
+
stackSection = readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'claude-md', 'fastapi.md'));
|
|
103
|
+
} else if (config.stackId === 'polyglot-fullstack') {
|
|
104
|
+
stackSection = readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'claude-md', 'fullstack.md'));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
content = content.replace('{{STACK_SPECIFIC_RULES}}', stackSection);
|
|
108
|
+
content = replaceVars(content, vars);
|
|
109
|
+
|
|
110
|
+
writeFile(path.join(outputDir, 'CLAUDE.md'), content);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function generateHooks(outputDir, config, options = {}) {
|
|
114
|
+
let hookFile;
|
|
115
|
+
let scriptFiles = ['guard-protected-files.sh'];
|
|
116
|
+
|
|
117
|
+
if (config.stackId === 'nextjs-fullstack') {
|
|
118
|
+
hookFile = 'typescript.json';
|
|
119
|
+
scriptFiles.push('autofix-typescript.sh');
|
|
120
|
+
} else if (config.stackId === 'fastapi-backend') {
|
|
121
|
+
hookFile = 'python.json';
|
|
122
|
+
scriptFiles.push('autofix-python.sh');
|
|
123
|
+
} else if (config.stackId === 'polyglot-fullstack') {
|
|
124
|
+
hookFile = 'polyglot.json';
|
|
125
|
+
scriptFiles.push('autofix-polyglot.sh');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const settingsPath = path.join(outputDir, '.claude', 'settings.json');
|
|
129
|
+
|
|
130
|
+
if (options.merge && fs.existsSync(settingsPath)) {
|
|
131
|
+
// Merge hooks into existing settings.json
|
|
132
|
+
const existing = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
133
|
+
const incoming = JSON.parse(readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'hooks', hookFile)));
|
|
134
|
+
const merged = deepMergeSettings(existing, incoming);
|
|
135
|
+
writeFile(settingsPath, JSON.stringify(merged, null, 2));
|
|
136
|
+
} else {
|
|
137
|
+
const hookPath = path.join(CLAUDE_TEMPLATES_DIR, 'hooks', hookFile);
|
|
138
|
+
const content = readTemplate(hookPath);
|
|
139
|
+
writeFile(settingsPath, content);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Copy hook scripts
|
|
143
|
+
const hooksDir = path.join(outputDir, '.claude', 'hooks');
|
|
144
|
+
ensureDir(hooksDir);
|
|
145
|
+
for (const script of scriptFiles) {
|
|
146
|
+
const srcPath = path.join(CLAUDE_TEMPLATES_DIR, 'hooks', 'scripts', script);
|
|
147
|
+
if (fs.existsSync(srcPath)) {
|
|
148
|
+
fs.copyFileSync(srcPath, path.join(hooksDir, script));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function deepMergeSettings(existing, incoming) {
|
|
154
|
+
const merged = { ...existing };
|
|
155
|
+
if (incoming.hooks) {
|
|
156
|
+
merged.hooks = merged.hooks || {};
|
|
157
|
+
for (const [hookType, hookArr] of Object.entries(incoming.hooks)) {
|
|
158
|
+
if (!merged.hooks[hookType]) {
|
|
159
|
+
merged.hooks[hookType] = hookArr;
|
|
160
|
+
} else {
|
|
161
|
+
// Append incoming hooks that don't already exist (by command)
|
|
162
|
+
const existingCommands = new Set(
|
|
163
|
+
merged.hooks[hookType].flatMap(h => (h.hooks || []).map(hk => hk.command))
|
|
164
|
+
);
|
|
165
|
+
for (const hook of hookArr) {
|
|
166
|
+
const isNew = (hook.hooks || []).some(hk => !existingCommands.has(hk.command));
|
|
167
|
+
if (isNew) {
|
|
168
|
+
merged.hooks[hookType].push(hook);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return merged;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function generateSkills(outputDir, config) {
|
|
178
|
+
const skillsToInclude = [];
|
|
179
|
+
|
|
180
|
+
if (config.frontend?.framework === 'nextjs') {
|
|
181
|
+
skillsToInclude.push('nextjs');
|
|
182
|
+
skillsToInclude.push('security-web');
|
|
183
|
+
}
|
|
184
|
+
if (config.backend?.framework === 'fastapi') {
|
|
185
|
+
skillsToInclude.push('fastapi');
|
|
186
|
+
skillsToInclude.push('security-api');
|
|
187
|
+
}
|
|
188
|
+
if (config.testing?.e2e === 'playwright') {
|
|
189
|
+
skillsToInclude.push('playwright');
|
|
190
|
+
}
|
|
191
|
+
if (config.ai) {
|
|
192
|
+
skillsToInclude.push('ai-prompts');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (const skill of skillsToInclude) {
|
|
196
|
+
const srcPath = path.join(CLAUDE_TEMPLATES_DIR, 'skills', skill, 'SKILL.md');
|
|
197
|
+
if (fs.existsSync(srcPath)) {
|
|
198
|
+
const destPath = path.join(outputDir, '.claude', 'skills', skill, 'SKILL.md');
|
|
199
|
+
ensureDir(path.dirname(destPath));
|
|
200
|
+
fs.copyFileSync(srcPath, destPath);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function generateAgents(outputDir, config, vars) {
|
|
206
|
+
const agentsDir = path.join(CLAUDE_TEMPLATES_DIR, 'agents');
|
|
207
|
+
const agents = [
|
|
208
|
+
'code-quality-reviewer.md',
|
|
209
|
+
'security-reviewer.md',
|
|
210
|
+
'spec-validator.md',
|
|
211
|
+
'production-readiness.md',
|
|
212
|
+
'uat-validator.md',
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
for (const agent of agents) {
|
|
216
|
+
const srcPath = path.join(agentsDir, agent);
|
|
217
|
+
if (fs.existsSync(srcPath)) {
|
|
218
|
+
let content = readTemplate(srcPath);
|
|
219
|
+
content = replaceVars(content, vars);
|
|
220
|
+
writeFile(path.join(outputDir, '.claude', 'agents', agent), content);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function generateCommands(outputDir, config, vars) {
|
|
226
|
+
const commandsDir = path.join(CLAUDE_TEMPLATES_DIR, 'commands');
|
|
227
|
+
const commands = [
|
|
228
|
+
'help.md',
|
|
229
|
+
'status.md',
|
|
230
|
+
'next.md',
|
|
231
|
+
'done.md',
|
|
232
|
+
'verify-all.md',
|
|
233
|
+
'audit-spec.md',
|
|
234
|
+
'audit-wiring.md',
|
|
235
|
+
'audit-security.md',
|
|
236
|
+
'pre-pr.md',
|
|
237
|
+
'run-uat.md',
|
|
238
|
+
'generate-prd.md',
|
|
239
|
+
'generate-uat.md',
|
|
240
|
+
'optimize-claude-md.md',
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
for (const cmd of commands) {
|
|
244
|
+
const srcPath = path.join(commandsDir, cmd);
|
|
245
|
+
if (fs.existsSync(srcPath)) {
|
|
246
|
+
let content = readTemplate(srcPath);
|
|
247
|
+
content = replaceVars(content, vars);
|
|
248
|
+
writeFile(path.join(outputDir, '.claude', 'commands', cmd), content);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function copyPromptLibrary(outputDir) {
|
|
254
|
+
const srcPath = path.join(DOCS_DIR, '01-universal-prompt-library.md');
|
|
255
|
+
if (fs.existsSync(srcPath)) {
|
|
256
|
+
const destPath = path.join(outputDir, 'docs', 'prompt-library.md');
|
|
257
|
+
ensureDir(path.dirname(destPath));
|
|
258
|
+
fs.copyFileSync(srcPath, destPath);
|
|
259
|
+
}
|
|
260
|
+
}
|