forgedev 1.1.0 → 1.1.3
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 +79 -7
- package/bin/devforge.js +10 -1
- package/package.json +1 -1
- package/src/claude-configurator.js +1 -0
- package/src/cli.js +11 -0
- 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/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/claude-code/agents/build-error-resolver.md +2 -3
- package/templates/claude-code/agents/database-reviewer.md +1 -1
- package/templates/claude-code/agents/doc-updater.md +1 -1
- package/templates/claude-code/agents/loop-operator.md +1 -2
- package/templates/claude-code/agents/uat-validator.md +2 -1
- package/templates/claude-code/claude-md/base.md +2 -2
- package/templates/claude-code/commands/build-fix.md +1 -1
- package/templates/claude-code/commands/code-review.md +1 -2
- package/templates/claude-code/commands/full-audit.md +60 -0
- package/templates/claude-code/commands/workflows.md +1 -0
- package/templates/claude-code/hooks/scripts/autofix-polyglot.mjs +12 -4
- package/templates/claude-code/hooks/scripts/autofix-python.mjs +11 -3
- package/templates/claude-code/hooks/scripts/autofix-typescript.mjs +11 -3
- 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 +1 -1
- package/templates/claude-code/skills/playwright/SKILL.md +2 -2
- package/templates/claude-code/skills/security-api/SKILL.md +2 -2
- package/templates/database/sqlalchemy-postgres/.env.example +1 -0
package/README.md
CHANGED
|
@@ -16,6 +16,9 @@ npx forgedev init
|
|
|
16
16
|
|
|
17
17
|
# Diagnose and optimize existing project
|
|
18
18
|
npx forgedev doctor
|
|
19
|
+
|
|
20
|
+
# Check for updates
|
|
21
|
+
npx forgedev update
|
|
19
22
|
```
|
|
20
23
|
|
|
21
24
|
## Four Modes, Four Audiences
|
|
@@ -174,14 +177,51 @@ Every project includes:
|
|
|
174
177
|
|
|
175
178
|
With Claude Code infrastructure enabled (default):
|
|
176
179
|
|
|
177
|
-
- **CLAUDE.md** tailored to your stack
|
|
178
|
-
- **Hooks** — auto-lint on edit, quality gate
|
|
179
|
-
- **
|
|
180
|
-
- **
|
|
181
|
-
- **
|
|
180
|
+
- **CLAUDE.md** tailored to your stack (with pitfalls and agents quick-reference)
|
|
181
|
+
- **Hooks** — cross-platform Node.js `.mjs` hooks (auto-lint on edit, quality gate, protected file guard)
|
|
182
|
+
- **17 Agents** — verification, development, review, and orchestration (see below)
|
|
183
|
+
- **20 Commands** — daily workflow, verification, release, development, session management
|
|
184
|
+
- **8 Skills** — framework-specific + universal knowledge
|
|
182
185
|
- **UAT templates** — scenario packs and CSV checklists
|
|
183
186
|
- **Prompt library** — the complete development prompt library
|
|
184
187
|
|
|
188
|
+
## Agents (17)
|
|
189
|
+
|
|
190
|
+
Every scaffolded project gets these agents in `.claude/agents/`:
|
|
191
|
+
|
|
192
|
+
| Agent | Role | Access |
|
|
193
|
+
|-------|------|--------|
|
|
194
|
+
| `architect` | System design, data models, API contracts | Read-only |
|
|
195
|
+
| `build-error-resolver` | Fix build/lint/type errors with minimal changes | Write |
|
|
196
|
+
| `chief-of-staff` | Orchestrate multiple agents for complex tasks | Write |
|
|
197
|
+
| `code-quality-reviewer` | Code quality review | Read-only |
|
|
198
|
+
| `database-reviewer` | Query optimization, schema review, N+1 detection | Read-only |
|
|
199
|
+
| `doc-updater` | Keep docs in sync with code changes | Write |
|
|
200
|
+
| `docs-lookup` | Search framework docs for answers | Read-only |
|
|
201
|
+
| `e2e-runner` | Generate and run Playwright E2E tests | Write |
|
|
202
|
+
| `harness-optimizer` | Audit Claude Code setup, suggest optimizations | Read-only |
|
|
203
|
+
| `loop-operator` | Autonomous improvement loops with stop conditions | Write |
|
|
204
|
+
| `planner` | Create implementation plans before coding | Read-only |
|
|
205
|
+
| `production-readiness` | Production deployment readiness review | Read-only |
|
|
206
|
+
| `refactor-cleaner` | Dead code removal, duplicate elimination | Write |
|
|
207
|
+
| `security-reviewer` | Security audit | Read-only |
|
|
208
|
+
| `spec-validator` | Validate implementation matches specification | Read-only |
|
|
209
|
+
| `tdd-guide` | Enforce RED-GREEN-REFACTOR TDD cycle | Write |
|
|
210
|
+
| `uat-validator` | QA validation of UAT scenarios | Read-only |
|
|
211
|
+
|
|
212
|
+
## Skills (8)
|
|
213
|
+
|
|
214
|
+
| Skill | Scope |
|
|
215
|
+
|-------|-------|
|
|
216
|
+
| `nextjs` | Next.js 15 App Router patterns |
|
|
217
|
+
| `fastapi` | FastAPI + SQLAlchemy 2.0 + Pydantic v2 |
|
|
218
|
+
| `playwright` | Playwright E2E testing |
|
|
219
|
+
| `security-web` | Web application security |
|
|
220
|
+
| `security-api` | API security |
|
|
221
|
+
| `ai-prompts` | AI/LLM integration patterns |
|
|
222
|
+
| `git-workflow` | Git branching, commits, PR workflow (universal) |
|
|
223
|
+
| `testing-patterns` | Test pyramid, AAA pattern, mocking (universal) |
|
|
224
|
+
|
|
185
225
|
## Development
|
|
186
226
|
|
|
187
227
|
```bash
|
|
@@ -190,6 +230,7 @@ npm test # run unit tests
|
|
|
190
230
|
node bin/devforge.js test-output # manual smoke test (guided + developer)
|
|
191
231
|
node bin/devforge.js init # test init mode (from any project dir)
|
|
192
232
|
node bin/devforge.js doctor # test doctor mode (from any project dir)
|
|
233
|
+
node bin/devforge.js update # check for updates
|
|
193
234
|
```
|
|
194
235
|
|
|
195
236
|
## Project Structure
|
|
@@ -198,7 +239,7 @@ node bin/devforge.js doctor # test doctor mode (from any project dir)
|
|
|
198
239
|
devforge/
|
|
199
240
|
├── bin/devforge.js # CLI entry point
|
|
200
241
|
├── src/
|
|
201
|
-
│ ├── cli.js # Command router (new, init, doctor)
|
|
242
|
+
│ ├── cli.js # Command router (new, init, doctor, update)
|
|
202
243
|
│ ├── index.js # New project orchestrator (guided + developer)
|
|
203
244
|
│ ├── guided.js # Guided mode (description → stack)
|
|
204
245
|
│ ├── prompts.js # Interactive prompts (Inquirer.js)
|
|
@@ -211,6 +252,8 @@ devforge/
|
|
|
211
252
|
│ ├── doctor.js # Doctor mode orchestrator
|
|
212
253
|
│ ├── doctor-checks.js # Diagnostic check functions
|
|
213
254
|
│ ├── doctor-prompts.js # Fix prompt generators
|
|
255
|
+
│ ├── update-check.js # npm registry version check
|
|
256
|
+
│ ├── update.js # Update command handler
|
|
214
257
|
│ └── utils.js # File ops, logging, colors
|
|
215
258
|
├── templates/ # Scaffold templates by category
|
|
216
259
|
│ ├── base/ # Every project gets this
|
|
@@ -225,26 +268,55 @@ devforge/
|
|
|
225
268
|
└── docs/ # Reference documentation
|
|
226
269
|
```
|
|
227
270
|
|
|
228
|
-
## Claude Code Commands
|
|
271
|
+
## Claude Code Commands (20)
|
|
229
272
|
|
|
230
273
|
After running `npx forgedev init`, these slash commands are available inside Claude Code:
|
|
231
274
|
|
|
275
|
+
**Daily Workflow:**
|
|
276
|
+
|
|
232
277
|
| Command | What It Does |
|
|
233
278
|
|---------|-------------|
|
|
234
279
|
| `/workflows` | Lists all available workflows |
|
|
235
280
|
| `/status` | Project dashboard — tests, branch, changes |
|
|
236
281
|
| `/next` | Figures out your next task |
|
|
237
282
|
| `/done` | Verifies task completion |
|
|
283
|
+
|
|
284
|
+
**Verification:**
|
|
285
|
+
|
|
286
|
+
| Command | What It Does |
|
|
287
|
+
|---------|-------------|
|
|
238
288
|
| `/verify-all` | Runs lint, type check, tests, then launches reviewers |
|
|
289
|
+
| `/full-audit` | Runs every audit and review agent in a single pass |
|
|
239
290
|
| `/audit-spec` | Validates implementation against a spec/PRD |
|
|
240
291
|
| `/audit-wiring` | Finds dead or unwired features |
|
|
241
292
|
| `/audit-security` | Runs a security audit |
|
|
293
|
+
| `/code-review` | Reviews uncommitted changes for security and quality |
|
|
294
|
+
|
|
295
|
+
**Release:**
|
|
296
|
+
|
|
297
|
+
| Command | What It Does |
|
|
298
|
+
|---------|-------------|
|
|
242
299
|
| `/pre-pr` | Runs the complete pre-PR checklist |
|
|
243
300
|
| `/run-uat` | Executes UAT scenarios |
|
|
301
|
+
|
|
302
|
+
**Development:**
|
|
303
|
+
|
|
304
|
+
| Command | What It Does |
|
|
305
|
+
|---------|-------------|
|
|
306
|
+
| `/plan` | Invoke planner agent for implementation planning |
|
|
307
|
+
| `/build-fix` | Incrementally fix build/lint/type errors |
|
|
308
|
+
| `/tdd` | Enforce test-driven development cycle |
|
|
244
309
|
| `/generate-prd` | Generates a PRD with Mermaid diagrams |
|
|
245
310
|
| `/generate-uat` | Generates UAT scenarios from codebase |
|
|
246
311
|
| `/optimize-claude-md` | Proposes splitting an oversized CLAUDE.md |
|
|
247
312
|
|
|
313
|
+
**Session:**
|
|
314
|
+
|
|
315
|
+
| Command | What It Does |
|
|
316
|
+
|---------|-------------|
|
|
317
|
+
| `/save-session` | Save work context for later resumption |
|
|
318
|
+
| `/resume-session` | Load saved session and continue where you left off |
|
|
319
|
+
|
|
248
320
|
## Install
|
|
249
321
|
|
|
250
322
|
```bash
|
package/bin/devforge.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { parseCommand } from '../src/cli.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
try {
|
|
5
|
+
await parseCommand(process.argv.slice(2));
|
|
6
|
+
} catch (err) {
|
|
7
|
+
// Graceful exit on Ctrl+C / prompt cancellation
|
|
8
|
+
if (err?.name === 'ExitPromptError' || err?.code === 'ERR_USE_AFTER_CLOSE') {
|
|
9
|
+
console.log('');
|
|
10
|
+
process.exit(0);
|
|
11
|
+
}
|
|
12
|
+
throw err;
|
|
13
|
+
}
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -46,6 +46,12 @@ 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);
|
|
@@ -73,6 +79,7 @@ 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:')}
|
|
@@ -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
|
+
// Prevent path traversal — project name must not escape cwd
|
|
16
|
+
if (/[\/\\]/.test(safeName) || safeName.includes('..')) {
|
|
17
|
+
log.error('Project name must not contain path separators or ".."');
|
|
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
|
+
}
|
|
@@ -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"]
|
|
@@ -8,9 +8,8 @@ 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
|
|
13
|
-
|
|
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
|
|
14
13
|
## Common Fix Patterns
|
|
15
14
|
|
|
16
15
|
| Error Type | Fix |
|
|
@@ -19,7 +19,7 @@ You are a database specialist. Your job is to review database code for performan
|
|
|
19
19
|
- [ ] Transactions are short-lived (no long-running transactions)
|
|
20
20
|
|
|
21
21
|
### Schema Design
|
|
22
|
-
- [ ] Primary keys use
|
|
22
|
+
- [ ] Primary keys use sequential identifiers (SERIAL, BIGSERIAL, UUIDv7) to avoid index fragmentation
|
|
23
23
|
- [ ] Foreign keys have indexes
|
|
24
24
|
- [ ] Timestamps use timezone-aware types (`timestamptz` not `timestamp`)
|
|
25
25
|
- [ ] Nullable columns have explicit defaults or are intentionally nullable
|
|
@@ -6,7 +6,7 @@ You are a documentation specialist. Your job is to keep project documentation ac
|
|
|
6
6
|
|
|
7
7
|
## Workflow
|
|
8
8
|
|
|
9
|
-
1. **Detect changes** — Run `git diff --name-only HEAD~1` to see
|
|
9
|
+
1. **Detect changes** — Run `git diff --name-only HEAD~1` to see files changed in the last commit
|
|
10
10
|
2. **Identify affected docs** — Map code changes to documentation that needs updating
|
|
11
11
|
3. **Update docs** — Edit README, API docs, changelogs, and inline comments
|
|
12
12
|
4. **Verify links** — Check that all referenced files and endpoints still exist
|
|
@@ -14,8 +14,7 @@ Execute iterative improvement loops safely: run a sequence of checks → fixes
|
|
|
14
14
|
2. **Set stop conditions** — Define when to stop (all tests pass, zero lint errors, or max 5 iterations)
|
|
15
15
|
3. **Execute iteration** — Fix one category of issues per iteration
|
|
16
16
|
4. **Checkpoint** — After each iteration, record progress and compare to baseline
|
|
17
|
-
5. **Evaluate** — If progress
|
|
18
|
-
6. **Report** — Show baseline vs final state with concrete numbers
|
|
17
|
+
5. **Evaluate** — If no progress across 2 consecutive iterations, stop and report6. **Report** — Show baseline vs final state with concrete numbers
|
|
19
18
|
|
|
20
19
|
## Stop Conditions (halt the loop if any are true)
|
|
21
20
|
|
|
@@ -16,7 +16,8 @@ Read-only. Never modify code.
|
|
|
16
16
|
a. Verify the feature exists in the codebase
|
|
17
17
|
b. Check if there's a corresponding automated test
|
|
18
18
|
c. If automated test exists, verify it covers the scenario's steps
|
|
19
|
-
d. Flag
|
|
19
|
+
d. Flag scenarios without automated tests
|
|
20
|
+
3. Scan test files to identify orphaned tests (tests without corresponding UAT scenarios)
|
|
20
21
|
|
|
21
22
|
## Output: Traceability Matrix
|
|
22
23
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
## RULES
|
|
15
15
|
- Never commit `.env` files or secrets
|
|
16
16
|
- Never modify migration files directly — generate new migrations instead
|
|
17
|
-
- All API responses use structured error format: `{ error: { code, message } }`
|
|
17
|
+
- All API responses use structured error format: `{ "error": { "code": "ERR_CODE", "message": "..." } }`
|
|
18
18
|
- Never leak stack traces to clients
|
|
19
19
|
- Health check endpoints must always be available
|
|
20
20
|
- Write tests for new features before marking them complete
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
## Pitfalls
|
|
25
25
|
- Never commit lock file merge conflicts — delete and regenerate
|
|
26
|
-
- Never use `any`
|
|
26
|
+
- Never use loose types (`any` in TS, `Any` in Python) — use strict types and narrow explicitly
|
|
27
27
|
- Never hardcode URLs, ports, or credentials — use environment variables
|
|
28
28
|
- Never catch errors silently — always log or re-throw
|
|
29
29
|
- Never push directly to main — always use feature branches
|
|
@@ -22,7 +22,7 @@ For each error:
|
|
|
22
22
|
1. Read the file to see error context
|
|
23
23
|
2. Diagnose the root cause (missing import, wrong type, syntax error)
|
|
24
24
|
3. Apply the smallest possible fix
|
|
25
|
-
4. Re-run
|
|
25
|
+
4. Re-run all three commands (build, lint, type check) to confirm the error is gone and no new errors were introduced
|
|
26
26
|
5. Move to the next error
|
|
27
27
|
|
|
28
28
|
## Step 4: Guardrails
|
|
@@ -33,11 +33,10 @@ For each changed file, check:
|
|
|
33
33
|
## Step 3: Generate Report
|
|
34
34
|
|
|
35
35
|
For each issue found:
|
|
36
|
-
- **Severity**: CRITICAL, HIGH, MEDIUM
|
|
36
|
+
- **Severity**: CRITICAL, HIGH, MEDIUM
|
|
37
37
|
- **File**: path and line number
|
|
38
38
|
- **Issue**: what's wrong
|
|
39
39
|
- **Fix**: how to fix it
|
|
40
|
-
|
|
41
40
|
## Step 4: Verdict
|
|
42
41
|
|
|
43
42
|
- If CRITICAL issues found → block commit, list required fixes
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Run every audit and review agent in a single pass. Use this when you want a comprehensive project health check.
|
|
2
|
+
|
|
3
|
+
## Step 1: Build + Lint + Tests
|
|
4
|
+
|
|
5
|
+
1. Run lint: `{{LINT_COMMAND}}`
|
|
6
|
+
2. Run type check: `{{TYPE_CHECK_COMMAND}}`
|
|
7
|
+
3. Run tests: `{{TEST_COMMAND}}`
|
|
8
|
+
|
|
9
|
+
If any step fails, report the failures but continue with the remaining audits.
|
|
10
|
+
|
|
11
|
+
## Step 2: Code Review (changed files)
|
|
12
|
+
|
|
13
|
+
1. Get changed files: `git diff --name-only HEAD`
|
|
14
|
+
2. For each changed file, check for:
|
|
15
|
+
- Hardcoded credentials, API keys, tokens
|
|
16
|
+
- SQL injection, XSS, path traversal
|
|
17
|
+
- Functions > 50 lines, files > 800 lines
|
|
18
|
+
- Missing error handling, console.log left in
|
|
19
|
+
- Missing tests for new code
|
|
20
|
+
|
|
21
|
+
## Step 3: Launch Review Agents
|
|
22
|
+
|
|
23
|
+
Run these agents in sequence on the full codebase:
|
|
24
|
+
|
|
25
|
+
1. **code-quality-reviewer** — code patterns, duplication, naming
|
|
26
|
+
2. **security-reviewer** — vulnerabilities, secrets, unsafe operations
|
|
27
|
+
3. **production-readiness** — deployment readiness, error handling, health checks
|
|
28
|
+
4. **database-reviewer** — query performance, N+1, schema issues (skip if no database)
|
|
29
|
+
|
|
30
|
+
## Step 4: Structural Audits
|
|
31
|
+
|
|
32
|
+
1. **Wiring audit** — verify all API endpoints are connected between frontend and backend
|
|
33
|
+
2. **Spec audit** — if `docs/` contains a spec/PRD, validate implementation coverage
|
|
34
|
+
|
|
35
|
+
## Step 5: Claude Code Setup
|
|
36
|
+
|
|
37
|
+
1. **harness-optimizer** — check if .claude/ setup follows best practices
|
|
38
|
+
|
|
39
|
+
## Step 6: Summary Report
|
|
40
|
+
|
|
41
|
+
Compile all findings into a single report grouped by severity:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
CRITICAL (must fix before merge):
|
|
45
|
+
- [list]
|
|
46
|
+
|
|
47
|
+
HIGH (fix soon):
|
|
48
|
+
- [list]
|
|
49
|
+
|
|
50
|
+
MEDIUM (improve when possible):
|
|
51
|
+
- [list]
|
|
52
|
+
|
|
53
|
+
LOW (nice to have):
|
|
54
|
+
- [list]
|
|
55
|
+
|
|
56
|
+
PASSED:
|
|
57
|
+
- [list of checks that found no issues]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Include total counts: X critical, Y high, Z medium, W low.
|
|
@@ -15,6 +15,7 @@ Show the developer what workflows are available.
|
|
|
15
15
|
|
|
16
16
|
### Verification
|
|
17
17
|
- `/verify-all` — Run lint, type check, tests, then launch all reviewers
|
|
18
|
+
- `/full-audit` — Run every audit and review agent in a single pass
|
|
18
19
|
- `/audit-spec` — Validate implementation against a spec/PRD
|
|
19
20
|
- `/audit-wiring` — Find dead or unwired features
|
|
20
21
|
- `/audit-security` — Run a security audit
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Auto-fix lint issues on saved TypeScript or Python files (polyglot)
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
5
6
|
|
|
6
7
|
let input = '';
|
|
7
8
|
process.stdin.setEncoding('utf8');
|
|
@@ -11,19 +12,26 @@ process.stdin.on('end', () => {
|
|
|
11
12
|
const data = JSON.parse(input);
|
|
12
13
|
const filePath = data?.tool_input?.file_path || '';
|
|
13
14
|
|
|
14
|
-
if (!filePath) {
|
|
15
|
+
if (!filePath || filePath.includes('..')) {
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Ensure path stays within the working directory
|
|
20
|
+
const resolved = resolve(filePath);
|
|
21
|
+
const cwd = resolve('.');
|
|
22
|
+
if (!resolved.startsWith(cwd)) {
|
|
15
23
|
process.exit(0);
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
|
|
19
27
|
try {
|
|
20
|
-
|
|
28
|
+
execFileSync('npx', ['eslint', '--fix', filePath], { stdio: 'pipe', cwd: 'frontend' });
|
|
21
29
|
} catch {
|
|
22
30
|
// eslint may exit non-zero for unfixable issues — that's okay
|
|
23
31
|
}
|
|
24
32
|
} else if (filePath.endsWith('.py')) {
|
|
25
33
|
try {
|
|
26
|
-
|
|
34
|
+
execFileSync('ruff', ['check', '--fix', filePath], { stdio: 'pipe', cwd: 'backend' });
|
|
27
35
|
} catch {
|
|
28
36
|
// ruff may exit non-zero for unfixable issues — that's okay
|
|
29
37
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Auto-fix lint issues on saved Python files
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
5
6
|
|
|
6
7
|
let input = '';
|
|
7
8
|
process.stdin.setEncoding('utf8');
|
|
@@ -11,13 +12,20 @@ process.stdin.on('end', () => {
|
|
|
11
12
|
const data = JSON.parse(input);
|
|
12
13
|
const filePath = data?.tool_input?.file_path || '';
|
|
13
14
|
|
|
14
|
-
if (!filePath) {
|
|
15
|
+
if (!filePath || filePath.includes('..')) {
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Ensure path stays within the working directory
|
|
20
|
+
const resolved = resolve(filePath);
|
|
21
|
+
const cwd = resolve('.');
|
|
22
|
+
if (!resolved.startsWith(cwd)) {
|
|
15
23
|
process.exit(0);
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
if (filePath.endsWith('.py')) {
|
|
19
27
|
try {
|
|
20
|
-
|
|
28
|
+
execFileSync('ruff', ['check', '--fix', filePath], { stdio: 'pipe', cwd: 'backend' });
|
|
21
29
|
} catch {
|
|
22
30
|
// ruff may exit non-zero for unfixable issues — that's okay
|
|
23
31
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Auto-fix lint issues on saved TypeScript files
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
5
6
|
|
|
6
7
|
let input = '';
|
|
7
8
|
process.stdin.setEncoding('utf8');
|
|
@@ -11,13 +12,20 @@ process.stdin.on('end', () => {
|
|
|
11
12
|
const data = JSON.parse(input);
|
|
12
13
|
const filePath = data?.tool_input?.file_path || '';
|
|
13
14
|
|
|
14
|
-
if (!filePath) {
|
|
15
|
+
if (!filePath || filePath.includes('..')) {
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Ensure path stays within the working directory
|
|
20
|
+
const resolved = resolve(filePath);
|
|
21
|
+
const cwd = resolve('.');
|
|
22
|
+
if (!resolved.startsWith(cwd)) {
|
|
15
23
|
process.exit(0);
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
|
|
19
27
|
try {
|
|
20
|
-
|
|
28
|
+
execFileSync('npx', ['eslint', '--fix', filePath], { stdio: 'pipe' });
|
|
21
29
|
} catch {
|
|
22
30
|
// eslint may exit non-zero for unfixable issues — that's okay
|
|
23
31
|
}
|
|
@@ -33,6 +33,7 @@ description: AI/LLM integration patterns and best practices
|
|
|
33
33
|
## Security
|
|
34
34
|
- Never include user secrets in prompts
|
|
35
35
|
- Sanitize user input before including in prompts
|
|
36
|
+
- Protect against prompt injection attacks (delimiter tokens, input validation, output filtering)
|
|
36
37
|
- Validate and sanitize AI output before using
|
|
37
38
|
- Don't trust AI output for security decisions
|
|
38
39
|
|
|
@@ -29,7 +29,7 @@ description: FastAPI + SQLAlchemy 2.0 + Pydantic v2 patterns
|
|
|
29
29
|
- Raise `AppError` subclasses, never `HTTPException` with raw strings
|
|
30
30
|
- Global exception handler catches unhandled errors
|
|
31
31
|
- Never expose stack traces or internal details to clients
|
|
32
|
-
- Use structured error format: `{ error: { code, message } }`
|
|
32
|
+
- Use structured error format: `{ "error": { "code": "ERR_CODE", "message": "Error description" } }`
|
|
33
33
|
|
|
34
34
|
## Testing
|
|
35
35
|
- Use `httpx.AsyncClient` with `ASGITransport` for async tests
|
|
@@ -61,4 +61,4 @@ If rebase gets messy: `git rebase --abort` and start over.
|
|
|
61
61
|
- Never commit `.env` files, credentials, or large binaries
|
|
62
62
|
- Never rebase commits that have been pushed and shared
|
|
63
63
|
- Never merge main into feature branches (rebase instead)
|
|
64
|
-
- Always pull before pushing: `git pull --rebase
|
|
64
|
+
- Always pull before pushing: `git pull --rebase` (pulls current branch's upstream)
|
|
@@ -25,8 +25,8 @@ description: Playwright E2E testing patterns and best practices
|
|
|
25
25
|
|
|
26
26
|
## Common Patterns
|
|
27
27
|
- Navigation: `await page.goto('/')` then assert page loaded
|
|
28
|
-
- Form filling: `await page.
|
|
29
|
-
- Clicking: `await page.
|
|
28
|
+
- Form filling: `await page.getByLabel('Email').fill('test@example.com')`
|
|
29
|
+
- Clicking: `await page.getByRole('button', { name: 'Submit' }).click()`
|
|
30
30
|
- Waiting: prefer auto-waiting over explicit waits
|
|
31
31
|
- Network: `page.waitForResponse()` for API-dependent tests
|
|
32
32
|
- Authentication: use `storageState` for persistent auth across tests
|
|
@@ -16,7 +16,7 @@ description: API security best practices
|
|
|
16
16
|
- Validate all input with Pydantic models
|
|
17
17
|
- Set max lengths on string fields
|
|
18
18
|
- Validate email formats, URLs, phone numbers
|
|
19
|
-
- Reject unexpected fields (
|
|
19
|
+
- Reject unexpected fields (set `extra = "forbid"` in Pydantic model config)
|
|
20
20
|
- Validate file uploads (size, type, extension)
|
|
21
21
|
|
|
22
22
|
## SQL Injection Prevention
|
|
@@ -38,7 +38,7 @@ description: API security best practices
|
|
|
38
38
|
- Never expose stack traces to clients
|
|
39
39
|
- Use generic error messages for auth failures
|
|
40
40
|
- Log detailed errors server-side only
|
|
41
|
-
- Return structured error responses: `{ error: { code, message } }`
|
|
41
|
+
- Return structured error responses: `{ "error": { "code": "ERR_CODE", "message": "Error description" } }`
|
|
42
42
|
|
|
43
43
|
## Secrets Management
|
|
44
44
|
- Store secrets in environment variables, never in code
|