forgedev 1.1.0 → 1.2.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/README.md +80 -7
- package/bin/devforge.js +11 -1
- package/docs/00-README.md +310 -0
- package/docs/01-universal-prompt-library.md +1049 -0
- package/docs/02-claude-code-mastery-playbook.md +283 -0
- package/docs/03-multi-agent-verification.md +565 -0
- package/docs/04-errata-and-verification-checklist.md +284 -0
- package/docs/05-universal-scaffolder-vision.md +452 -0
- package/docs/06-confidence-assessment-and-repo-prompt.md +407 -0
- package/docs/errata.md +58 -0
- package/docs/multi-agent-verification.md +66 -0
- package/docs/plans/.gitkeep +0 -0
- package/docs/playbook.md +95 -0
- package/docs/prompt-library.md +160 -0
- package/docs/uat/UAT_CHECKLIST.csv +9 -0
- package/docs/uat/UAT_TEMPLATE.md +163 -0
- package/package.json +10 -2
- package/src/claude-configurator.js +2 -0
- package/src/cli.js +16 -5
- package/src/doctor-prompts.js +9 -2
- package/src/doctor.js +19 -0
- package/src/index.js +7 -0
- package/src/update-check.js +49 -0
- package/src/update.js +33 -0
- package/src/utils.js +1 -1
- package/templates/auth/jwt-custom/backend/app/core/security.py.template +4 -1
- package/templates/backend/fastapi/backend/app/core/config.py.template +2 -2
- package/templates/base/docs/plans/.gitkeep +0 -0
- package/templates/base/docs/uat/UAT_CHECKLIST.csv.template +2 -0
- package/templates/base/docs/uat/UAT_TEMPLATE.md.template +22 -0
- package/templates/claude-code/agents/build-error-resolver.md +4 -4
- package/templates/claude-code/agents/code-quality-reviewer.md +1 -1
- package/templates/claude-code/agents/database-reviewer.md +2 -2
- package/templates/claude-code/agents/doc-updater.md +1 -1
- package/templates/claude-code/agents/harness-optimizer.md +26 -0
- package/templates/claude-code/agents/loop-operator.md +1 -1
- package/templates/claude-code/agents/product-strategist.md +124 -0
- package/templates/claude-code/agents/security-reviewer.md +1 -0
- package/templates/claude-code/agents/spec-validator.md +31 -1
- package/templates/claude-code/agents/uat-validator.md +6 -1
- package/templates/claude-code/claude-md/base.md +3 -2
- package/templates/claude-code/claude-md/nextjs.md +1 -1
- package/templates/claude-code/commands/build-fix.md +1 -1
- package/templates/claude-code/commands/code-review.md +6 -1
- package/templates/claude-code/commands/full-audit.md +61 -0
- package/templates/claude-code/commands/workflows.md +4 -0
- package/templates/claude-code/hooks/scripts/autofix-polyglot.mjs +28 -10
- package/templates/claude-code/hooks/scripts/autofix-python.mjs +11 -4
- package/templates/claude-code/hooks/scripts/autofix-typescript.mjs +11 -3
- package/templates/claude-code/hooks/scripts/guard-protected-files.mjs +2 -2
- package/templates/claude-code/skills/ai-prompts/SKILL.md +1 -0
- package/templates/claude-code/skills/fastapi/SKILL.md +1 -1
- package/templates/claude-code/skills/git-workflow/SKILL.md +3 -3
- package/templates/claude-code/skills/nextjs/SKILL.md +1 -1
- package/templates/claude-code/skills/playwright/SKILL.md +8 -7
- package/templates/claude-code/skills/security-api/SKILL.md +2 -2
- package/templates/claude-code/skills/security-web/SKILL.md +1 -0
- package/templates/database/sqlalchemy-postgres/.env.example +1 -0
- package/templates/infra/github-actions/.github/workflows/ci.yml.template +49 -0
- package/templates/testing/pytest/backend/tests/__init__.py +0 -0
- package/templates/testing/pytest/backend/tests/conftest.py.template +11 -0
- package/templates/testing/pytest/backend/tests/test_health.py.template +10 -0
- package/templates/testing/vitest/vitest.config.ts.template +18 -0
- package/CLAUDE.md +0 -38
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# DevForge Prompt Library
|
|
2
|
+
|
|
3
|
+
8 workflow guides for developing DevForge. Each workflow includes the exact prompts to use.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Flow 1: Add a New Stack
|
|
8
|
+
|
|
9
|
+
When you want to add support for a new tech stack (e.g., Hono, React+Vite, Express).
|
|
10
|
+
|
|
11
|
+
**Step 1: Plan**
|
|
12
|
+
```
|
|
13
|
+
I want to add [stack] support to DevForge. Enter plan mode. Research:
|
|
14
|
+
1. What files/directories are needed for a typical [stack] project
|
|
15
|
+
2. What dependencies go in package.json / requirements.txt
|
|
16
|
+
3. What the recommender decision tree should look like
|
|
17
|
+
Write a plan to docs/plans/add-[stack].md
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Step 2: Templates**
|
|
21
|
+
```
|
|
22
|
+
Following the plan in docs/plans/add-[stack].md, create template files in
|
|
23
|
+
templates/[category]/[stack]/. Use {{VARIABLE_NAME}} for substitution.
|
|
24
|
+
Follow the patterns in existing templates like templates/frontend/nextjs/.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Step 3: Recommender**
|
|
28
|
+
```
|
|
29
|
+
Update src/recommender.js to route to the new [stack] templates.
|
|
30
|
+
Add the new templateModules paths. Update formatStackSummary.
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Step 4: Test**
|
|
34
|
+
```
|
|
35
|
+
Add tests in tests/recommender.test.js for the new stack routing.
|
|
36
|
+
Run npx vitest run to verify all tests pass.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Flow 2: Create a New Template
|
|
42
|
+
|
|
43
|
+
When adding individual template files to an existing stack.
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
I want to add a [template] to the [stack] stack. Create the template file at
|
|
47
|
+
templates/[category]/[stack]/[path]. Use {{VARIABLE_NAME}} placeholders where
|
|
48
|
+
the project name, description, or config values should go. Check
|
|
49
|
+
src/composer.js buildVariables() for available variables.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Flow 3: Fix a Bug
|
|
55
|
+
|
|
56
|
+
**Step 1: Reproduce**
|
|
57
|
+
```
|
|
58
|
+
There's a bug: [describe]. Write a failing test in tests/ that reproduces it.
|
|
59
|
+
Run npx vitest run to confirm the test fails.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Step 2: Fix**
|
|
63
|
+
```
|
|
64
|
+
Fix the bug that causes [test name] to fail. Run npx vitest run to confirm
|
|
65
|
+
the fix and that no other tests break.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Flow 4: Refactor
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
I want to refactor [module/function]. Enter plan mode. First:
|
|
74
|
+
1. Check test coverage for the code being refactored
|
|
75
|
+
2. Add tests for any uncovered behavior
|
|
76
|
+
3. Plan the refactoring steps (each should keep tests green)
|
|
77
|
+
Write a plan to docs/plans/refactor-[module].md
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Flow 5: Add a Feature
|
|
83
|
+
|
|
84
|
+
For features that touch multiple modules (prompts, recommender, composer, configurator).
|
|
85
|
+
|
|
86
|
+
**Step 1: Plan**
|
|
87
|
+
```
|
|
88
|
+
I want to add [feature] to DevForge. Enter plan mode. Trace through:
|
|
89
|
+
- src/prompts.js — does the user need to be asked anything new?
|
|
90
|
+
- src/recommender.js — does the decision tree change?
|
|
91
|
+
- src/composer.js — are new template variables needed?
|
|
92
|
+
- src/claude-configurator.js — does the generated infrastructure change?
|
|
93
|
+
- src/uat-generator.js — do UAT scenarios need updating?
|
|
94
|
+
Write a plan to docs/plans/[feature].md
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Step 2: Implement**
|
|
98
|
+
```
|
|
99
|
+
Following docs/plans/[feature].md, implement the feature. Work module by module.
|
|
100
|
+
Run npx vitest run after each module change.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Flow 6: Verification
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Run /project:verify-all
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
This launches all 5 agents (code-quality, security, spec-validator, production-readiness, uat-validator) and runs tests.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Flow 7: Pre-PR
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
Run /project:pre-pr
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This runs tests, smoke test, code quality review, security review, and checks for staged secrets.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Flow 8: UAT
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Run /project:run-uat
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
This reads docs/uat/UAT_TEMPLATE.md, maps scenarios to tests, runs them, and updates UAT_CHECKLIST.csv.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Utility Prompts
|
|
136
|
+
|
|
137
|
+
### "I'm lost"
|
|
138
|
+
```
|
|
139
|
+
Read CLAUDE.md, git log --oneline -10, and git status. Tell me where I am,
|
|
140
|
+
what I was working on, and what I should do next.
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### "Is this right?"
|
|
144
|
+
```
|
|
145
|
+
Review my changes (git diff). Check if they follow DevForge patterns:
|
|
146
|
+
ESM imports with .js extensions, chalk for output, path.join for paths,
|
|
147
|
+
{{VARIABLE}} for templates. Flag anything that looks wrong.
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### "Before I PR"
|
|
151
|
+
```
|
|
152
|
+
Run /project:pre-pr
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### "Explain this code"
|
|
156
|
+
```
|
|
157
|
+
Read [file] and explain what it does, how it fits into the DevForge pipeline
|
|
158
|
+
(prompts → recommender → composer → configurator → uat-generator), and what
|
|
159
|
+
calls it.
|
|
160
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
UAT_ID,Scenario,Priority,Automated,Test_File,Status,Last_Run,Notes
|
|
2
|
+
UAT-001,Scaffold Next.js Full-Stack,P0,PARTIAL,tests/composer.test.js,NOT RUN,,Manual smoke test required
|
|
3
|
+
UAT-002,Scaffold FastAPI Backend,P0,PARTIAL,tests/composer.test.js,NOT RUN,,Manual smoke test required
|
|
4
|
+
UAT-003,Scaffold Polyglot Full-Stack,P0,PARTIAL,tests/composer.test.js,NOT RUN,,Manual smoke test required
|
|
5
|
+
UAT-004,Recommender Selects Correct Stack,P0,YES,tests/recommender.test.js,NOT RUN,,
|
|
6
|
+
UAT-005,Template Variable Substitution,P0,YES,tests/composer.test.js,NOT RUN,,
|
|
7
|
+
UAT-006,Claude Code Infrastructure Generated,P1,YES,tests/claude-configurator.test.js,NOT RUN,,
|
|
8
|
+
UAT-007,Invalid Input Handling,P1,NO,,NOT RUN,,Manual test required
|
|
9
|
+
UAT-008,Unsupported Stack Selection,P1,PARTIAL,tests/recommender.test.js,NOT RUN,,
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# UAT Scenario Pack: DevForge
|
|
2
|
+
|
|
3
|
+
## Pre-Conditions
|
|
4
|
+
- [ ] Node.js >= 18 installed
|
|
5
|
+
- [ ] npm available
|
|
6
|
+
- [ ] DevForge dependencies installed (`npm install`)
|
|
7
|
+
- [ ] No existing `test-output/` directory
|
|
8
|
+
|
|
9
|
+
## Scenarios
|
|
10
|
+
|
|
11
|
+
### UAT-001: Scaffold Next.js Full-Stack Project — Happy Path
|
|
12
|
+
**Priority:** P0
|
|
13
|
+
**Preconditions:** Clean environment, no test-output/ directory
|
|
14
|
+
**Steps:**
|
|
15
|
+
1. Run `node bin/devforge.js test-output`
|
|
16
|
+
2. Select "Full-stack app"
|
|
17
|
+
3. Select "TypeScript" for language
|
|
18
|
+
4. Select "Yes" for authentication
|
|
19
|
+
5. Select "No" for AI integration
|
|
20
|
+
6. Select "Docker" for deployment
|
|
21
|
+
7. Confirm the recommended stack
|
|
22
|
+
**Expected Result:**
|
|
23
|
+
- `test-output/` directory created
|
|
24
|
+
- Contains `package.json` with Next.js, React, TypeScript, Tailwind, Prisma, NextAuth dependencies
|
|
25
|
+
- Contains `src/app/layout.tsx`, `src/app/page.tsx`
|
|
26
|
+
- Contains `src/app/api/health/route.ts` (health check endpoint)
|
|
27
|
+
- Contains `prisma/schema.prisma`
|
|
28
|
+
- Contains `.claude/` directory with hooks, agents, commands
|
|
29
|
+
- Contains `CLAUDE.md` with Next.js-specific rules
|
|
30
|
+
- Contains `docs/uat/UAT_TEMPLATE.md`
|
|
31
|
+
**Actual Result:** ___
|
|
32
|
+
**Status:** NOT RUN
|
|
33
|
+
**Tester:** ___
|
|
34
|
+
**Date:** ___
|
|
35
|
+
**Notes:** ___
|
|
36
|
+
|
|
37
|
+
### UAT-002: Scaffold FastAPI Backend Project — Happy Path
|
|
38
|
+
**Priority:** P0
|
|
39
|
+
**Preconditions:** Clean environment, no test-output/ directory
|
|
40
|
+
**Steps:**
|
|
41
|
+
1. Run `node bin/devforge.js test-output`
|
|
42
|
+
2. Select "API / backend service"
|
|
43
|
+
3. Select "Python" for language
|
|
44
|
+
4. Select "Yes" for authentication
|
|
45
|
+
5. Select "No" for AI integration
|
|
46
|
+
6. Select "Docker" for deployment
|
|
47
|
+
7. Confirm the recommended stack
|
|
48
|
+
**Expected Result:**
|
|
49
|
+
- `test-output/` directory created
|
|
50
|
+
- Contains `backend/requirements.txt` with FastAPI, SQLAlchemy, Pydantic
|
|
51
|
+
- Contains `backend/app/main.py` with health endpoint and graceful shutdown
|
|
52
|
+
- Contains `backend/app/api/health.py`
|
|
53
|
+
- Contains `backend/app/core/config.py`, `errors.py`, `retry.py`
|
|
54
|
+
- Contains `backend/tests/` with pytest fixtures
|
|
55
|
+
- Contains `.claude/` directory with Python-specific hooks
|
|
56
|
+
- Contains `CLAUDE.md` with FastAPI-specific rules
|
|
57
|
+
**Actual Result:** ___
|
|
58
|
+
**Status:** NOT RUN
|
|
59
|
+
**Tester:** ___
|
|
60
|
+
**Date:** ___
|
|
61
|
+
**Notes:** ___
|
|
62
|
+
|
|
63
|
+
### UAT-003: Scaffold Polyglot Full-Stack Project — Happy Path
|
|
64
|
+
**Priority:** P0
|
|
65
|
+
**Preconditions:** Clean environment, no test-output/ directory
|
|
66
|
+
**Steps:**
|
|
67
|
+
1. Run `node bin/devforge.js test-output`
|
|
68
|
+
2. Select "Full-stack app"
|
|
69
|
+
3. Select "TypeScript" and "Python" for language
|
|
70
|
+
4. Select "Yes" for authentication
|
|
71
|
+
5. Select "Yes" for AI integration
|
|
72
|
+
6. Select "Docker" for deployment
|
|
73
|
+
7. Confirm the recommended stack
|
|
74
|
+
**Expected Result:**
|
|
75
|
+
- `test-output/` directory created
|
|
76
|
+
- Contains both `frontend/` and `backend/` directories
|
|
77
|
+
- Contains `docker-compose.yml` at root
|
|
78
|
+
- Contains Next.js frontend and FastAPI backend
|
|
79
|
+
- Contains both Prisma and SQLAlchemy database configs
|
|
80
|
+
- Contains polyglot Claude Code hooks (TypeScript + Python)
|
|
81
|
+
**Actual Result:** ___
|
|
82
|
+
**Status:** NOT RUN
|
|
83
|
+
**Tester:** ___
|
|
84
|
+
**Date:** ___
|
|
85
|
+
**Notes:** ___
|
|
86
|
+
|
|
87
|
+
### UAT-004: Recommender Selects Correct Stack
|
|
88
|
+
**Priority:** P0
|
|
89
|
+
**Preconditions:** None
|
|
90
|
+
**Steps:**
|
|
91
|
+
1. Run `npx vitest run tests/recommender.test.js`
|
|
92
|
+
2. Verify all test cases pass
|
|
93
|
+
3. Verify: web_app + TypeScript → Next.js full-stack
|
|
94
|
+
4. Verify: api_service + Python → FastAPI backend
|
|
95
|
+
5. Verify: full_stack + TS + Python → polyglot
|
|
96
|
+
6. Verify: unsupported combos return helpful error
|
|
97
|
+
**Expected Result:** All recommender tests pass, all 3 stacks correctly selected
|
|
98
|
+
**Actual Result:** ___
|
|
99
|
+
**Status:** NOT RUN
|
|
100
|
+
**Tester:** ___
|
|
101
|
+
**Date:** ___
|
|
102
|
+
**Notes:** ___
|
|
103
|
+
|
|
104
|
+
### UAT-005: Template Variable Substitution
|
|
105
|
+
**Priority:** P0
|
|
106
|
+
**Preconditions:** None
|
|
107
|
+
**Steps:**
|
|
108
|
+
1. Run `npx vitest run tests/composer.test.js`
|
|
109
|
+
2. Verify `{{PROJECT_NAME}}` replaced in all .template files
|
|
110
|
+
3. Verify non-.template files copied without modification
|
|
111
|
+
4. Verify .gitkeep files preserved
|
|
112
|
+
5. Verify no `{{` patterns remain in output
|
|
113
|
+
**Expected Result:** All composer tests pass, variables correctly substituted
|
|
114
|
+
**Actual Result:** ___
|
|
115
|
+
**Status:** NOT RUN
|
|
116
|
+
**Tester:** ___
|
|
117
|
+
**Date:** ___
|
|
118
|
+
**Notes:** ___
|
|
119
|
+
|
|
120
|
+
### UAT-006: Claude Code Infrastructure Generated
|
|
121
|
+
**Priority:** P1
|
|
122
|
+
**Preconditions:** Scaffold a project first
|
|
123
|
+
**Steps:**
|
|
124
|
+
1. Run `npx vitest run tests/claude-configurator.test.js`
|
|
125
|
+
2. Verify `.claude/settings.json` created with correct hooks
|
|
126
|
+
3. Verify CLAUDE.md generated with stack-specific content
|
|
127
|
+
4. Verify agents copied (5 agents)
|
|
128
|
+
5. Verify skills copied (filtered by stack)
|
|
129
|
+
6. Verify commands copied (6 commands)
|
|
130
|
+
**Expected Result:** All claude-configurator tests pass, infrastructure complete
|
|
131
|
+
**Actual Result:** ___
|
|
132
|
+
**Status:** NOT RUN
|
|
133
|
+
**Tester:** ___
|
|
134
|
+
**Date:** ___
|
|
135
|
+
**Notes:** ___
|
|
136
|
+
|
|
137
|
+
### UAT-007: Invalid Input Handling
|
|
138
|
+
**Priority:** P1
|
|
139
|
+
**Preconditions:** None
|
|
140
|
+
**Steps:**
|
|
141
|
+
1. Run `node bin/devforge.js` (no project name) — should show error
|
|
142
|
+
2. Run `node bin/devforge.js .` (invalid name) — should show error
|
|
143
|
+
3. Create `test-output/` dir, then run `node bin/devforge.js test-output` — should warn about existing dir
|
|
144
|
+
**Expected Result:** Clear error messages, no crashes, exit code 1
|
|
145
|
+
**Actual Result:** ___
|
|
146
|
+
**Status:** NOT RUN
|
|
147
|
+
**Tester:** ___
|
|
148
|
+
**Date:** ___
|
|
149
|
+
**Notes:** ___
|
|
150
|
+
|
|
151
|
+
### UAT-008: Unsupported Stack Selection
|
|
152
|
+
**Priority:** P1
|
|
153
|
+
**Preconditions:** None
|
|
154
|
+
**Steps:**
|
|
155
|
+
1. Run `node bin/devforge.js test-output`
|
|
156
|
+
2. Select "Mobile app" or "Desktop app"
|
|
157
|
+
3. Observe the recommendation
|
|
158
|
+
**Expected Result:** Displays message that the stack is not yet supported in V1, suggests closest supported option
|
|
159
|
+
**Actual Result:** ___
|
|
160
|
+
**Status:** NOT RUN
|
|
161
|
+
**Tester:** ___
|
|
162
|
+
**Date:** ___
|
|
163
|
+
**Notes:** ___
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forgedev",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Universal, AI-first project scaffolding CLI with Claude Code infrastructure",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,5 +29,13 @@
|
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|
|
31
31
|
"node": ">=18.0.0"
|
|
32
|
-
}
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"bin/",
|
|
35
|
+
"src/",
|
|
36
|
+
"templates/",
|
|
37
|
+
"docs/",
|
|
38
|
+
"LICENSE",
|
|
39
|
+
"README.md"
|
|
40
|
+
]
|
|
33
41
|
}
|
|
@@ -226,6 +226,7 @@ function generateAgents(outputDir, config, vars) {
|
|
|
226
226
|
'chief-of-staff.md',
|
|
227
227
|
'loop-operator.md',
|
|
228
228
|
'harness-optimizer.md',
|
|
229
|
+
'product-strategist.md',
|
|
229
230
|
];
|
|
230
231
|
|
|
231
232
|
for (const agent of agents) {
|
|
@@ -260,6 +261,7 @@ function generateCommands(outputDir, config, vars) {
|
|
|
260
261
|
'tdd.md',
|
|
261
262
|
'save-session.md',
|
|
262
263
|
'resume-session.md',
|
|
264
|
+
'full-audit.md',
|
|
263
265
|
];
|
|
264
266
|
|
|
265
267
|
for (const cmd of commands) {
|
package/src/cli.js
CHANGED
|
@@ -46,15 +46,21 @@ export async function parseCommand(args) {
|
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
if (command === 'update') {
|
|
50
|
+
const { runUpdate } = await import('./update.js');
|
|
51
|
+
await runUpdate();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
49
55
|
// Shorthand: devforge my-app → devforge new my-app
|
|
50
56
|
if (!command.startsWith('-')) {
|
|
51
57
|
const targetDir = path.resolve(process.cwd(), command);
|
|
52
58
|
if (fs.existsSync(targetDir)) {
|
|
53
|
-
console.
|
|
59
|
+
console.error('');
|
|
54
60
|
log.warn(`"${command}" already exists. Did you mean:`);
|
|
55
|
-
console.
|
|
56
|
-
console.
|
|
57
|
-
console.
|
|
61
|
+
console.error(` ${chalk.bold('devforge init')} Add dev guardrails to current project`);
|
|
62
|
+
console.error(` ${chalk.bold('devforge doctor')} Diagnose and optimize current project`);
|
|
63
|
+
console.error('');
|
|
58
64
|
process.exit(1);
|
|
59
65
|
}
|
|
60
66
|
const { runNew } = await import('./index.js');
|
|
@@ -73,13 +79,14 @@ function showUsage() {
|
|
|
73
79
|
devforge new <name> Create a new project
|
|
74
80
|
devforge init Add dev guardrails to current project
|
|
75
81
|
devforge doctor Diagnose and optimize current project
|
|
82
|
+
devforge update Check for newer version
|
|
76
83
|
devforge <name> Shorthand for ${chalk.dim('devforge new <name>')}
|
|
77
84
|
|
|
78
85
|
${chalk.bold('Options:')}
|
|
79
86
|
-h, --help Show this help message
|
|
80
87
|
-v, --version Show version number
|
|
81
88
|
|
|
82
|
-
Run ${chalk.cyan('devforge
|
|
89
|
+
Run ${chalk.cyan('devforge --help')} for more details.
|
|
83
90
|
`);
|
|
84
91
|
}
|
|
85
92
|
|
|
@@ -105,6 +112,10 @@ function showHelp() {
|
|
|
105
112
|
flaky tests, dead code, duplicate code, and more.
|
|
106
113
|
Generates Claude Code prompts to fix each issue.
|
|
107
114
|
|
|
115
|
+
${chalk.bold('devforge update')}
|
|
116
|
+
Check if a newer version of DevForge is available.
|
|
117
|
+
Shows upgrade instructions if an update exists.
|
|
118
|
+
|
|
108
119
|
${chalk.bold('Supported stacks (V1):')}
|
|
109
120
|
- Next.js full-stack (TypeScript + Prisma + PostgreSQL)
|
|
110
121
|
- FastAPI backend (Python + SQLAlchemy + PostgreSQL)
|
package/src/doctor-prompts.js
CHANGED
|
@@ -176,6 +176,15 @@ ${fileList}
|
|
|
176
176
|
|
|
177
177
|
Extract all prompts into a dedicated prompts file (e.g., src/lib/prompts.ts or prompts/). This makes prompts easier to version, A/B test, and iterate on without changing application code.`;
|
|
178
178
|
},
|
|
179
|
+
|
|
180
|
+
DEVFORGE_UPDATE: (issue) => {
|
|
181
|
+
return `A newer version of DevForge is available.
|
|
182
|
+
|
|
183
|
+
Run: npm install -g forgedev@latest
|
|
184
|
+
Then re-run: npx forgedev init
|
|
185
|
+
|
|
186
|
+
This will update your project's agents, commands, skills, and hooks to the latest version.`;
|
|
187
|
+
},
|
|
179
188
|
};
|
|
180
189
|
|
|
181
190
|
export function generatePrompt(issue) {
|
|
@@ -223,8 +232,6 @@ export function generateReport(issues, projectName) {
|
|
|
223
232
|
const critical = issues.filter(i => i.severity === 'critical');
|
|
224
233
|
const warnings = issues.filter(i => i.severity === 'warning');
|
|
225
234
|
const info = issues.filter(i => i.severity === 'info');
|
|
226
|
-
const healthy = []; // Could be populated by passing in good checks
|
|
227
|
-
|
|
228
235
|
let report = `# DevForge Doctor Report — ${projectName}
|
|
229
236
|
Generated: ${new Date().toISOString().split('T')[0]}
|
|
230
237
|
|
package/src/doctor.js
CHANGED
|
@@ -29,6 +29,25 @@ export async function runDoctor(projectDir) {
|
|
|
29
29
|
// Run all checks
|
|
30
30
|
const issues = runAllChecks(projectDir, scan);
|
|
31
31
|
|
|
32
|
+
// Check for DevForge updates (5s timeout, won't crash on failure)
|
|
33
|
+
try {
|
|
34
|
+
const { checkForUpdate } = await import('./update-check.js');
|
|
35
|
+
const updateResult = await checkForUpdate();
|
|
36
|
+
if (updateResult?.updateAvailable) {
|
|
37
|
+
issues.push({
|
|
38
|
+
severity: 'info',
|
|
39
|
+
title: `DevForge update available: ${updateResult.current} → ${updateResult.latest}`,
|
|
40
|
+
impact: 'Newer version may include improved agents, commands, and bug fixes',
|
|
41
|
+
files: [],
|
|
42
|
+
autoFixable: false,
|
|
43
|
+
promptId: 'DEVFORGE_UPDATE',
|
|
44
|
+
effort: 'quick',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
// Silently ignore — network issues shouldn't block doctor
|
|
49
|
+
}
|
|
50
|
+
|
|
32
51
|
if (issues.length === 0) {
|
|
33
52
|
console.log(chalk.green(' ✓ Your project looks healthy! No issues found.'));
|
|
34
53
|
console.log('');
|
package/src/index.js
CHANGED
|
@@ -11,6 +11,13 @@ import { generateUAT } from './uat-generator.js';
|
|
|
11
11
|
|
|
12
12
|
export async function runNew(projectName) {
|
|
13
13
|
const safeName = toKebabCase(projectName);
|
|
14
|
+
|
|
15
|
+
// Validate project name — must be a clean kebab-case identifier
|
|
16
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(safeName)) {
|
|
17
|
+
log.error('Project name must start with a letter or number and contain only lowercase letters, numbers, and hyphens.');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
const outputDir = path.resolve(process.cwd(), safeName);
|
|
15
22
|
|
|
16
23
|
if (fs.existsSync(outputDir)) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
|
|
3
|
+
const PACKAGE_NAME = 'forgedev';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Compare two semver strings (major.minor.patch).
|
|
7
|
+
* Returns 1 if a > b, -1 if a < b, 0 if equal.
|
|
8
|
+
*/
|
|
9
|
+
export function compareVersions(a, b) {
|
|
10
|
+
const pa = a.split('.').map(Number);
|
|
11
|
+
const pb = b.split('.').map(Number);
|
|
12
|
+
for (let i = 0; i < 3; i++) {
|
|
13
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return 1;
|
|
14
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return -1;
|
|
15
|
+
}
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Check npm registry for a newer version of forgedev.
|
|
21
|
+
* Returns { current, latest, updateAvailable } or null on failure.
|
|
22
|
+
*/
|
|
23
|
+
export async function checkForUpdate() {
|
|
24
|
+
const pkg = JSON.parse(
|
|
25
|
+
fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
|
|
26
|
+
);
|
|
27
|
+
const currentVersion = pkg.version;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const response = await fetch(
|
|
31
|
+
`https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
|
|
32
|
+
{ signal: AbortSignal.timeout(5000) }
|
|
33
|
+
);
|
|
34
|
+
if (!response.ok) return null;
|
|
35
|
+
const data = await response.json();
|
|
36
|
+
const latestVersion = data.version;
|
|
37
|
+
|
|
38
|
+
// Validate version format before trusting registry response
|
|
39
|
+
if (!/^\d+\.\d+\.\d+/.test(latestVersion)) return null;
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
current: currentVersion,
|
|
43
|
+
latest: latestVersion,
|
|
44
|
+
updateAvailable: compareVersions(latestVersion, currentVersion) > 0,
|
|
45
|
+
};
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/update.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { log } from './utils.js';
|
|
3
|
+
import { checkForUpdate } from './update-check.js';
|
|
4
|
+
|
|
5
|
+
export async function runUpdate() {
|
|
6
|
+
console.log('');
|
|
7
|
+
console.log(chalk.bold.cyan(' DevForge') + chalk.dim(' — Checking for updates...'));
|
|
8
|
+
console.log('');
|
|
9
|
+
|
|
10
|
+
const result = await checkForUpdate();
|
|
11
|
+
|
|
12
|
+
if (result === null) {
|
|
13
|
+
log.warn(' Could not reach the npm registry. Check your internet connection.');
|
|
14
|
+
console.log('');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!result.updateAvailable) {
|
|
19
|
+
log.success(` ✓ You're on the latest version (${result.current})`);
|
|
20
|
+
console.log('');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
log.warn(` Update available: ${result.current} → ${result.latest}`);
|
|
25
|
+
console.log('');
|
|
26
|
+
console.log(' To update:');
|
|
27
|
+
console.log(` ${chalk.bold('npm install -g forgedev@latest')} ${chalk.dim('(if installed globally)')}`);
|
|
28
|
+
console.log(` ${chalk.bold('npx forgedev@latest new my-app')} ${chalk.dim('(one-time use)')}`);
|
|
29
|
+
console.log('');
|
|
30
|
+
log.dim(' To update an existing project\'s Claude Code infrastructure:');
|
|
31
|
+
log.dim(' cd my-project && npx forgedev@latest init');
|
|
32
|
+
console.log('');
|
|
33
|
+
}
|
package/src/utils.js
CHANGED
|
@@ -11,7 +11,7 @@ export const ROOT_DIR = path.resolve(__dirname, '..');
|
|
|
11
11
|
export const log = {
|
|
12
12
|
info: (msg) => console.log(chalk.cyan(msg)),
|
|
13
13
|
success: (msg) => console.log(chalk.green(msg)),
|
|
14
|
-
warn: (msg) => console.
|
|
14
|
+
warn: (msg) => console.error(chalk.yellow(msg)),
|
|
15
15
|
error: (msg) => console.error(chalk.red(msg)),
|
|
16
16
|
step: (n, total, msg) => console.log(chalk.blue(`[${n}/${total}] ${msg}`)),
|
|
17
17
|
dim: (msg) => console.log(chalk.dim(msg)),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from datetime import datetime, timedelta, timezone
|
|
2
3
|
|
|
3
4
|
from jose import JWTError, jwt
|
|
@@ -7,7 +8,9 @@ from app.core.config import settings
|
|
|
7
8
|
|
|
8
9
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
9
10
|
|
|
10
|
-
SECRET_KEY = "
|
|
11
|
+
SECRET_KEY = os.environ.get("JWT_SECRET_KEY")
|
|
12
|
+
if not SECRET_KEY:
|
|
13
|
+
raise RuntimeError("JWT_SECRET_KEY environment variable is required. Set it in your .env file.")
|
|
11
14
|
ALGORITHM = "HS256"
|
|
12
15
|
ACCESS_TOKEN_EXPIRE_MINUTES = 30
|
|
13
16
|
|
|
@@ -6,8 +6,8 @@ class Settings(BaseSettings):
|
|
|
6
6
|
app_name: str = "{{PROJECT_NAME_PASCAL}}"
|
|
7
7
|
debug: bool = False
|
|
8
8
|
|
|
9
|
-
# Database
|
|
10
|
-
database_url: str
|
|
9
|
+
# Database — no default: must be set via .env or environment
|
|
10
|
+
database_url: str
|
|
11
11
|
|
|
12
12
|
# CORS
|
|
13
13
|
cors_origins: list[str] = ["http://localhost:3000"]
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# UAT Scenario Pack: {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
## Pre-Conditions
|
|
4
|
+
- [ ] Application is deployed to staging
|
|
5
|
+
- [ ] Test accounts are created
|
|
6
|
+
- [ ] Test data is seeded
|
|
7
|
+
|
|
8
|
+
## Scenarios
|
|
9
|
+
|
|
10
|
+
### UAT-001: Health Check — Happy Path
|
|
11
|
+
**Priority:** P0
|
|
12
|
+
**Preconditions:** Application is running
|
|
13
|
+
**Steps:**
|
|
14
|
+
1. Send GET request to /health (or /api/health)
|
|
15
|
+
2. Verify response status is 200
|
|
16
|
+
3. Verify response body contains status: "ok"
|
|
17
|
+
**Expected Result:** Health endpoint responds with 200 and status ok
|
|
18
|
+
**Actual Result:** ___
|
|
19
|
+
**Status:** NOT RUN
|
|
20
|
+
**Tester:** ___
|
|
21
|
+
**Date:** ___
|
|
22
|
+
**Notes:** ___
|
|
@@ -8,19 +8,19 @@ You are a build error resolution specialist. Your job is to fix build/type/lint
|
|
|
8
8
|
|
|
9
9
|
1. **Collect errors** — Run `{{BUILD_COMMAND}}`, `{{LINT_COMMAND}}`, and `{{TYPE_CHECK_COMMAND}}` to capture all errors
|
|
10
10
|
2. **Group by file** — Sort errors by file path, fix in dependency order (imports/types before logic)
|
|
11
|
-
3. **Fix one at a time** — Read the file, diagnose root cause, apply minimal edit
|
|
12
|
-
4. **Verify** — After each fix, confirm the error is gone and no new errors were introduced
|
|
11
|
+
3. **Fix one error at a time** — Read the file, diagnose root cause, apply minimal edit
|
|
12
|
+
4. **Verify** — After each fix, re-run all three commands to confirm the error is gone and no new errors were introduced
|
|
13
13
|
|
|
14
14
|
## Common Fix Patterns
|
|
15
15
|
|
|
16
16
|
| Error Type | Fix |
|
|
17
17
|
|-----------|-----|
|
|
18
18
|
| Missing import | Add the import statement |
|
|
19
|
-
| Type mismatch | Add type annotation or
|
|
19
|
+
| Type mismatch | Add correct type annotation, adjust code to match expected types, or fix the actual type |
|
|
20
20
|
| Undefined variable | Check spelling, add declaration, or fix import |
|
|
21
21
|
| Missing dependency | Suggest install command (`npm install X` or `pip install X`) |
|
|
22
22
|
| Config error | Compare with known working defaults |
|
|
23
|
-
| Circular dependency | Identify the cycle,
|
|
23
|
+
| Circular dependency | Identify the cycle, report to user with suggested breaking strategies |
|
|
24
24
|
|
|
25
25
|
## Rules
|
|
26
26
|
|
|
@@ -38,4 +38,4 @@ Stack: {{STACK_SUMMARY}}
|
|
|
38
38
|
- [ ] Functions are reasonably sized (< 50 lines)
|
|
39
39
|
|
|
40
40
|
## Output
|
|
41
|
-
For each issue: **File** | **Line** | **Severity** (critical/
|
|
41
|
+
For each issue: **File** | **Line** | **Severity** (critical/high/medium/low) | **Issue** | **Fix**
|