forgedev 1.2.0 → 1.3.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 +57 -10
- package/bin/chainproof.js +126 -0
- package/package.json +25 -7
- package/src/chainproof-bridge.js +330 -0
- package/src/ci-mode.js +85 -0
- package/src/claude-configurator.js +86 -49
- package/src/cli.js +30 -7
- package/src/composer.js +159 -34
- package/src/doctor-checks-chainproof.js +106 -0
- package/src/doctor-checks.js +39 -20
- package/src/doctor-prompts.js +9 -9
- package/src/doctor.js +37 -4
- package/src/guided.js +3 -3
- package/src/index.js +31 -10
- package/src/init-mode.js +64 -11
- package/src/menu.js +178 -0
- package/src/prompts.js +5 -12
- package/src/recommender.js +134 -10
- package/src/scanner.js +57 -2
- package/src/uat-generator.js +204 -189
- package/src/update-check.js +9 -4
- package/src/update.js +1 -1
- package/src/utils.js +64 -5
- package/templates/ai/guardrails-py/backend/app/ai/__init__.py +29 -0
- package/templates/ai/guardrails-py/backend/app/ai/audit_log.py +133 -0
- package/templates/ai/guardrails-py/backend/app/ai/client.py.template +323 -0
- package/templates/ai/guardrails-py/backend/app/ai/health.py.template +157 -0
- package/templates/ai/guardrails-py/backend/app/ai/input_guard.py +98 -0
- package/templates/ai/guardrails-ts/src/lib/ai/audit-log.ts.template +164 -0
- package/templates/ai/guardrails-ts/src/lib/ai/client.ts.template +403 -0
- package/templates/ai/guardrails-ts/src/lib/ai/health.ts.template +165 -0
- package/templates/ai/guardrails-ts/src/lib/ai/index.ts.template +17 -0
- package/templates/ai/guardrails-ts/src/lib/ai/input-guard.ts.template +124 -0
- package/templates/auth/nextauth/src/lib/auth.ts.template +12 -7
- package/templates/backend/express/Dockerfile.template +18 -0
- package/templates/backend/express/package.json.template +33 -0
- package/templates/backend/express/src/index.ts.template +34 -0
- package/templates/backend/express/src/routes/health.ts.template +27 -0
- package/templates/backend/express/tsconfig.json +17 -0
- package/templates/backend/fastapi/backend/Dockerfile.template +5 -0
- package/templates/backend/fastapi/backend/app/api/health.py.template +1 -1
- package/templates/backend/fastapi/backend/app/core/config.py.template +1 -1
- package/templates/backend/fastapi/backend/app/core/errors.py +1 -1
- package/templates/backend/fastapi/backend/app/main.py.template +3 -1
- package/templates/backend/fastapi/backend/requirements.txt.template +2 -0
- package/templates/backend/hono/Dockerfile.template +18 -0
- package/templates/backend/hono/package.json.template +31 -0
- package/templates/backend/hono/src/index.ts.template +32 -0
- package/templates/backend/hono/src/routes/health.ts.template +27 -0
- package/templates/backend/hono/tsconfig.json +18 -0
- package/templates/base/docs/uat/UAT_TEMPLATE.md.template +1 -1
- package/templates/chainproof/base/.chainproof/config.json.template +11 -0
- package/templates/chainproof/base/.chainproof/mcp-server.mjs +310 -0
- package/templates/chainproof/base/.mcp.json +9 -0
- package/templates/chainproof/fastapi/.chainproof/middleware.json.template +14 -0
- package/templates/chainproof/nextjs/.chainproof/hooks.json.template +19 -0
- package/templates/chainproof/polyglot/.chainproof/config.json.template +21 -0
- package/templates/claude-code/agents/architect.md +25 -11
- package/templates/claude-code/agents/build-error-resolver.md +19 -5
- package/templates/claude-code/agents/chief-of-staff.md +42 -8
- package/templates/claude-code/agents/code-quality-reviewer.md +14 -0
- package/templates/claude-code/agents/database-reviewer.md +15 -1
- package/templates/claude-code/agents/deep-reviewer.md +191 -0
- package/templates/claude-code/agents/doc-updater.md +19 -5
- package/templates/claude-code/agents/docs-lookup.md +19 -5
- package/templates/claude-code/agents/e2e-runner.md +26 -12
- package/templates/claude-code/agents/enforcement-gate.md +102 -0
- package/templates/claude-code/agents/frontend-builder.md +188 -0
- package/templates/claude-code/agents/harness-optimizer.md +36 -1
- package/templates/claude-code/agents/loop-operator.md +27 -13
- package/templates/claude-code/agents/planner.md +21 -7
- package/templates/claude-code/agents/product-strategist.md +24 -10
- package/templates/claude-code/agents/production-readiness.md +14 -0
- package/templates/claude-code/agents/prompt-auditor.md +115 -0
- package/templates/claude-code/agents/refactor-cleaner.md +22 -8
- package/templates/claude-code/agents/security-reviewer.md +14 -0
- package/templates/claude-code/agents/spec-validator.md +15 -1
- package/templates/claude-code/agents/tdd-guide.md +21 -7
- package/templates/claude-code/agents/uat-validator.md +14 -0
- package/templates/claude-code/claude-md/base.md +14 -7
- package/templates/claude-code/claude-md/fastapi.md +8 -8
- package/templates/claude-code/claude-md/fullstack.md +6 -6
- package/templates/claude-code/claude-md/hono.md +18 -0
- package/templates/claude-code/claude-md/nextjs.md +5 -5
- package/templates/claude-code/claude-md/remix.md +18 -0
- package/templates/claude-code/commands/audit-security.md +14 -0
- package/templates/claude-code/commands/audit-spec.md +14 -0
- package/templates/claude-code/commands/audit-wiring.md +14 -0
- package/templates/claude-code/commands/build-fix.md +28 -0
- package/templates/claude-code/commands/build-ui.md +59 -0
- package/templates/claude-code/commands/code-review.md +53 -31
- package/templates/claude-code/commands/fix-loop.md +211 -0
- package/templates/claude-code/commands/full-audit.md +36 -8
- package/templates/claude-code/commands/generate-prd.md +1 -1
- package/templates/claude-code/commands/generate-sdd.md +74 -0
- package/templates/claude-code/commands/generate-uat.md +107 -35
- package/templates/claude-code/commands/help.md +68 -0
- package/templates/claude-code/commands/live-uat.md +268 -0
- package/templates/claude-code/commands/optimize-claude-md.md +15 -1
- package/templates/claude-code/commands/plan.md +3 -3
- package/templates/claude-code/commands/pre-pr.md +57 -19
- package/templates/claude-code/commands/product-strategist.md +21 -0
- package/templates/claude-code/commands/resume-session.md +10 -10
- package/templates/claude-code/commands/run-uat.md +59 -2
- package/templates/claude-code/commands/save-session.md +10 -10
- package/templates/claude-code/commands/simplify.md +36 -0
- package/templates/claude-code/commands/tdd.md +17 -18
- package/templates/claude-code/commands/verify-all.md +24 -0
- package/templates/claude-code/commands/verify-intent.md +55 -0
- package/templates/claude-code/commands/workflows.md +52 -40
- package/templates/claude-code/hooks/polyglot.json +10 -1
- package/templates/claude-code/hooks/python.json +10 -1
- package/templates/claude-code/hooks/scripts/autofix-polyglot.mjs +2 -2
- package/templates/claude-code/hooks/scripts/autofix-python.mjs +1 -1
- package/templates/claude-code/hooks/scripts/autofix-typescript.mjs +1 -1
- package/templates/claude-code/hooks/scripts/code-hygiene.mjs +293 -0
- package/templates/claude-code/hooks/scripts/pre-commit-gate.mjs +207 -0
- package/templates/claude-code/hooks/typescript.json +10 -1
- package/templates/claude-code/skills/ai-prompts/SKILL.md +119 -41
- package/templates/claude-code/skills/git-workflow/SKILL.md +5 -5
- package/templates/claude-code/skills/nextjs/SKILL.md +1 -1
- package/templates/claude-code/skills/playwright/SKILL.md +5 -5
- package/templates/claude-code/skills/security-api/SKILL.md +1 -1
- package/templates/claude-code/skills/security-web/SKILL.md +1 -1
- package/templates/claude-code/skills/testing-patterns/SKILL.md +9 -9
- package/templates/database/prisma-postgres/{.env.example → .env.example.template} +1 -0
- package/templates/database/sqlalchemy-postgres/{.env.example → .env.example.template} +1 -0
- package/templates/docs-portal/fastapi/backend/app/portal/__pycache__/docs_reader.cpython-314.pyc +0 -0
- package/templates/docs-portal/fastapi/backend/app/portal/docs_reader.py +201 -0
- package/templates/docs-portal/fastapi/backend/app/portal/html_renderer.py +229 -0
- package/templates/docs-portal/fastapi/backend/app/portal/router.py.template +35 -0
- package/templates/docs-portal/nextjs/src/app/portal/[category]/[slug]/page.tsx +81 -0
- package/templates/docs-portal/nextjs/src/app/portal/[category]/page.tsx +65 -0
- package/templates/docs-portal/nextjs/src/app/portal/layout.tsx.template +54 -0
- package/templates/docs-portal/nextjs/src/app/portal/page.tsx +85 -0
- package/templates/docs-portal/nextjs/src/components/portal/markdown-renderer.tsx +101 -0
- package/templates/docs-portal/nextjs/src/components/portal/mobile-portal-nav.tsx +81 -0
- package/templates/docs-portal/nextjs/src/components/portal/portal-nav.tsx +86 -0
- package/templates/docs-portal/nextjs/src/lib/docs.ts +139 -0
- package/templates/frontend/nextjs/package.json.template +3 -1
- package/templates/frontend/react/index.html.template +12 -0
- package/templates/frontend/react/package.json.template +34 -0
- package/templates/frontend/react/src/App.tsx.template +10 -0
- package/templates/frontend/react/src/index.css +1 -0
- package/templates/frontend/react/src/main.tsx +10 -0
- package/templates/frontend/react/tsconfig.json +17 -0
- package/templates/frontend/react/vite.config.ts.template +15 -0
- package/templates/frontend/react/vitest.config.ts +9 -0
- package/templates/frontend/remix/app/root.tsx.template +31 -0
- package/templates/frontend/remix/app/routes/_index.tsx.template +19 -0
- package/templates/frontend/remix/app/routes/api.health.ts.template +10 -0
- package/templates/frontend/remix/app/tailwind.css +1 -0
- package/templates/frontend/remix/package.json.template +39 -0
- package/templates/frontend/remix/tsconfig.json +18 -0
- package/templates/frontend/remix/vite.config.ts.template +7 -0
- package/templates/infra/github-actions/.github/workflows/ci.yml.template +3 -0
- package/docs/00-README.md +0 -310
- package/docs/01-universal-prompt-library.md +0 -1049
- package/docs/02-claude-code-mastery-playbook.md +0 -283
- package/docs/03-multi-agent-verification.md +0 -565
- package/docs/04-errata-and-verification-checklist.md +0 -284
- package/docs/05-universal-scaffolder-vision.md +0 -452
- package/docs/06-confidence-assessment-and-repo-prompt.md +0 -407
- package/docs/errata.md +0 -58
- package/docs/multi-agent-verification.md +0 -66
- package/docs/playbook.md +0 -95
- package/docs/prompt-library.md +0 -160
- package/docs/uat/UAT_CHECKLIST.csv +0 -9
- package/docs/uat/UAT_TEMPLATE.md +0 -163
- package/templates/claude-code/commands/done.md +0 -19
- /package/{docs/plans/.gitkeep → templates/docs-portal/fastapi/backend/app/portal/__init__.py} +0 -0
package/src/doctor-prompts.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const PROMPT_TEMPLATES = {
|
|
2
2
|
CLAUDE_MD_TOO_LONG: (issue) => {
|
|
3
3
|
const lines = issue.title.match(/(\d+) lines/)?.[1] || '?';
|
|
4
|
-
return `Read CLAUDE.md. It's ${lines} lines
|
|
4
|
+
return `Read CLAUDE.md. It's ${lines} lines, too long for Claude Code to follow reliably (target: <150).
|
|
5
5
|
|
|
6
6
|
Propose a split:
|
|
7
7
|
- What stays in CLAUDE.md (universal rules, commands, pitfalls)
|
|
@@ -25,7 +25,7 @@ Write a test for each endpoint confirming 401 without auth.`;
|
|
|
25
25
|
|
|
26
26
|
FLAKY_TESTS: (issue) => {
|
|
27
27
|
const fileList = (issue.files || []).map(f => `- ${f}`).join('\n');
|
|
28
|
-
return `These tests use waitForTimeout() or hardcoded delays
|
|
28
|
+
return `These tests use waitForTimeout() or hardcoded delays. They will fail randomly:
|
|
29
29
|
${fileList}
|
|
30
30
|
|
|
31
31
|
For each:
|
|
@@ -55,10 +55,10 @@ ${fileList}
|
|
|
55
55
|
For each: replace with a specific exception type.
|
|
56
56
|
- If catching expected errors: except ValueError, except KeyError, etc.
|
|
57
57
|
- If catching any exception for logging: except Exception as e: with logging
|
|
58
|
-
- Never use bare except:
|
|
58
|
+
- Never use bare except: because it hides bugs`;
|
|
59
59
|
},
|
|
60
60
|
|
|
61
|
-
MISSING_HEALTH: (
|
|
61
|
+
MISSING_HEALTH: (_issue) => {
|
|
62
62
|
return `Add a health check endpoint to the application.
|
|
63
63
|
|
|
64
64
|
For FastAPI: Add a /health endpoint that returns {"status": "ok"} and optionally checks database connectivity.
|
|
@@ -68,7 +68,7 @@ For both: Include database connectivity check if a database is configured.
|
|
|
68
68
|
This endpoint is used by load balancers and monitoring to verify the app is running.`;
|
|
69
69
|
},
|
|
70
70
|
|
|
71
|
-
MISSING_SHUTDOWN: (
|
|
71
|
+
MISSING_SHUTDOWN: (_issue) => {
|
|
72
72
|
return `Add graceful shutdown handling to the application.
|
|
73
73
|
|
|
74
74
|
For FastAPI: Use the lifespan context manager to handle startup/shutdown events.
|
|
@@ -114,7 +114,7 @@ For each:
|
|
|
114
114
|
3. Update imports
|
|
115
115
|
4. Run tests after each extraction
|
|
116
116
|
|
|
117
|
-
Don't refactor all at once
|
|
117
|
+
Don't refactor all at once. Do one file per session.`;
|
|
118
118
|
},
|
|
119
119
|
|
|
120
120
|
MISSING_SCOPED_CLAUDE_MD: (issue) => {
|
|
@@ -177,7 +177,7 @@ ${fileList}
|
|
|
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
179
|
|
|
180
|
-
DEVFORGE_UPDATE: (
|
|
180
|
+
DEVFORGE_UPDATE: (_issue) => {
|
|
181
181
|
return `A newer version of DevForge is available.
|
|
182
182
|
|
|
183
183
|
Run: npm install -g forgedev@latest
|
|
@@ -221,7 +221,7 @@ ${prompt}
|
|
|
221
221
|
sessionNum++;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
return `# Fix Prompts
|
|
224
|
+
return `# Fix Prompts - Run These in Claude Code (In Order)
|
|
225
225
|
|
|
226
226
|
${sections.join('\n')}
|
|
227
227
|
Run each as a separate Claude Code session. /clear between sessions.
|
|
@@ -232,7 +232,7 @@ export function generateReport(issues, projectName) {
|
|
|
232
232
|
const critical = issues.filter(i => i.severity === 'critical');
|
|
233
233
|
const warnings = issues.filter(i => i.severity === 'warning');
|
|
234
234
|
const info = issues.filter(i => i.severity === 'info');
|
|
235
|
-
let report = `# DevForge Doctor Report
|
|
235
|
+
let report = `# DevForge Doctor Report - ${projectName}
|
|
236
236
|
Generated: ${new Date().toISOString().split('T')[0]}
|
|
237
237
|
|
|
238
238
|
## Summary
|
package/src/doctor.js
CHANGED
|
@@ -9,7 +9,7 @@ import { askDoctorAction } from './prompts.js';
|
|
|
9
9
|
|
|
10
10
|
export async function runDoctor(projectDir) {
|
|
11
11
|
console.log('');
|
|
12
|
-
console.log(chalk.bold.cyan(' 🔨 DevForge Doctor') + chalk.dim('
|
|
12
|
+
console.log(chalk.bold.cyan(' 🔨 DevForge Doctor') + chalk.dim(' Project Health Check'));
|
|
13
13
|
console.log('');
|
|
14
14
|
console.log(' Scanning...');
|
|
15
15
|
console.log('');
|
|
@@ -45,7 +45,7 @@ export async function runDoctor(projectDir) {
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
} catch {
|
|
48
|
-
// Silently ignore
|
|
48
|
+
// Silently ignore. Network issues shouldn't block doctor
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
if (issues.length === 0) {
|
|
@@ -247,8 +247,7 @@ async function autoFixSafe(issues, projectDir) {
|
|
|
247
247
|
fs.chmodSync(hookPath, '755');
|
|
248
248
|
console.log(chalk.green(` ✓ Fixed ${path.join('.claude/hooks', hookFile)} permissions (chmod +x)`));
|
|
249
249
|
fixed++;
|
|
250
|
-
} catch {
|
|
251
|
-
// Skip
|
|
250
|
+
} catch { // Permission change failed on this hook, continue
|
|
252
251
|
}
|
|
253
252
|
}
|
|
254
253
|
}
|
|
@@ -262,6 +261,8 @@ async function autoFixSafe(issues, projectDir) {
|
|
|
262
261
|
|
|
263
262
|
if (!content.includes('.claude/todos')) entriesToAdd.push('.claude/todos');
|
|
264
263
|
if (!content.includes('.claude/plans')) entriesToAdd.push('.claude/plans');
|
|
264
|
+
if (!content.includes('.env.local')) entriesToAdd.push('.env.local');
|
|
265
|
+
if (!content.includes('.env.*.local')) entriesToAdd.push('.env.*.local');
|
|
265
266
|
|
|
266
267
|
if (entriesToAdd.length > 0) {
|
|
267
268
|
const addition = '\n# Claude Code temp files\n' + entriesToAdd.join('\n') + '\n';
|
|
@@ -271,6 +272,38 @@ async function autoFixSafe(issues, projectDir) {
|
|
|
271
272
|
}
|
|
272
273
|
}
|
|
273
274
|
|
|
275
|
+
// Create missing .env.example if .env exists but no example
|
|
276
|
+
const envPath = path.join(projectDir, '.env');
|
|
277
|
+
const envExamplePath = path.join(projectDir, '.env.example');
|
|
278
|
+
if (fs.existsSync(envPath) && !fs.existsSync(envExamplePath)) {
|
|
279
|
+
const envContent = fs.readFileSync(envPath, 'utf-8');
|
|
280
|
+
const exampleContent = envContent
|
|
281
|
+
.split('\n')
|
|
282
|
+
.map(line => {
|
|
283
|
+
if (!line.includes('=') || line.startsWith('#')) return line;
|
|
284
|
+
const key = line.split('=')[0];
|
|
285
|
+
return `${key}=`;
|
|
286
|
+
})
|
|
287
|
+
.join('\n');
|
|
288
|
+
fs.writeFileSync(envExamplePath, exampleContent, 'utf-8');
|
|
289
|
+
console.log(chalk.green(' ✓ Created .env.example from .env (values stripped)'));
|
|
290
|
+
fixed++;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Create missing CLAUDE.md for subdirectories in polyglot projects
|
|
294
|
+
const frontendDir = path.join(projectDir, 'frontend');
|
|
295
|
+
const backendDir = path.join(projectDir, 'backend');
|
|
296
|
+
if (fs.existsSync(frontendDir) && fs.existsSync(backendDir)) {
|
|
297
|
+
for (const subdir of ['frontend', 'backend']) {
|
|
298
|
+
const subdirClaudeMd = path.join(projectDir, subdir, 'CLAUDE.md');
|
|
299
|
+
if (!fs.existsSync(subdirClaudeMd)) {
|
|
300
|
+
fs.writeFileSync(subdirClaudeMd, `# ${subdir}\n\nSee root CLAUDE.md for project-level rules. This file contains ${subdir}-specific overrides.\n`, 'utf-8');
|
|
301
|
+
console.log(chalk.green(` ✓ Created ${subdir}/CLAUDE.md (scoped)`));
|
|
302
|
+
fixed++;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
274
307
|
const skipped = issues.filter(i => !i.autoFixable).length;
|
|
275
308
|
|
|
276
309
|
if (fixed === 0) {
|
package/src/guided.js
CHANGED
|
@@ -91,7 +91,7 @@ export function analyzeDescription(text) {
|
|
|
91
91
|
suggestedServiceType = 'web_app';
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
// AI service override
|
|
94
|
+
// AI service override: if AI is the primary focus
|
|
95
95
|
if (features.includes('ai') && !features.includes('dashboard') && !features.includes('payments')) {
|
|
96
96
|
suggestedServiceType = 'ai_service';
|
|
97
97
|
}
|
|
@@ -114,7 +114,7 @@ export function mapFeaturesToStack(analysis) {
|
|
|
114
114
|
return stackConfig;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
export function buildGuidedPreview(analysis,
|
|
117
|
+
export function buildGuidedPreview(analysis, _stackConfig) {
|
|
118
118
|
const lines = [];
|
|
119
119
|
|
|
120
120
|
lines.push(chalk.bold(' What you\'ll get:'));
|
|
@@ -208,7 +208,7 @@ npm run dev`;
|
|
|
208
208
|
|
|
209
209
|
DevForge created a starter version of your app with all the basic
|
|
210
210
|
building blocks in place. Think of it like getting a house with the
|
|
211
|
-
foundation, walls, and plumbing already done
|
|
211
|
+
foundation, walls, and plumbing already done. You just need to
|
|
212
212
|
furnish and decorate it.
|
|
213
213
|
|
|
214
214
|
## Your Project Structure (Plain English)
|
package/src/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import { log, toKebabCase } from './utils.js';
|
|
5
|
+
import { log, toKebabCase, copyEnvCmd } from './utils.js';
|
|
6
6
|
import { askServiceType, askRefinements, askNewMode, confirmStack } from './prompts.js';
|
|
7
7
|
import { recommend } from './recommender.js';
|
|
8
8
|
import { compose } from './composer.js';
|
|
@@ -12,9 +12,9 @@ import { generateUAT } from './uat-generator.js';
|
|
|
12
12
|
export async function runNew(projectName) {
|
|
13
13
|
const safeName = toKebabCase(projectName);
|
|
14
14
|
|
|
15
|
-
// Validate project name
|
|
16
|
-
if (!/^[a-z0-9][a-z0-9
|
|
17
|
-
log.error('Project name must start with a letter
|
|
15
|
+
// Validate project name. Must be a clean kebab-case identifier
|
|
16
|
+
if (!/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(safeName)) {
|
|
17
|
+
log.error('Project name must start with a letter, contain only lowercase letters, numbers, and hyphens, and not have consecutive or trailing hyphens.');
|
|
18
18
|
process.exit(1);
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -26,7 +26,7 @@ export async function runNew(projectName) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
console.log('');
|
|
29
|
-
console.log(chalk.bold.cyan(' 🔨 DevForge') + chalk.dim('
|
|
29
|
+
console.log(chalk.bold.cyan(' 🔨 DevForge') + chalk.dim(' Let\'s build something.'));
|
|
30
30
|
console.log('');
|
|
31
31
|
|
|
32
32
|
const mode = await askNewMode();
|
|
@@ -62,7 +62,7 @@ async function runDeveloperFlow(safeName, outputDir) {
|
|
|
62
62
|
|
|
63
63
|
export async function scaffold(outputDir, stackConfig) {
|
|
64
64
|
console.log('');
|
|
65
|
-
const totalSteps = stackConfig.claudeCode ?
|
|
65
|
+
const totalSteps = stackConfig.claudeCode ? 5 : 4;
|
|
66
66
|
let step = 0;
|
|
67
67
|
|
|
68
68
|
step++;
|
|
@@ -79,6 +79,11 @@ export async function scaffold(outputDir, stackConfig) {
|
|
|
79
79
|
log.step(step, totalSteps, 'Generating UAT templates...');
|
|
80
80
|
await generateUAT(outputDir, stackConfig);
|
|
81
81
|
|
|
82
|
+
step++;
|
|
83
|
+
log.step(step, totalSteps, 'Initializing ChainProof trust chain...');
|
|
84
|
+
const { initChainproof } = await import('./chainproof-bridge.js');
|
|
85
|
+
initChainproof(outputDir);
|
|
86
|
+
|
|
82
87
|
step++;
|
|
83
88
|
log.step(step, totalSteps, 'Initializing git repository...');
|
|
84
89
|
initGit(outputDir);
|
|
@@ -93,7 +98,7 @@ function initGit(outputDir) {
|
|
|
93
98
|
try {
|
|
94
99
|
execSync('git init', { cwd: outputDir, stdio: 'ignore' });
|
|
95
100
|
} catch {
|
|
96
|
-
|
|
101
|
+
log.dim(' git not available, skipping repository initialization');
|
|
97
102
|
}
|
|
98
103
|
}
|
|
99
104
|
|
|
@@ -109,7 +114,7 @@ export function printNextSteps(projectName, config, isGuided = false) {
|
|
|
109
114
|
console.log(chalk.bold(' 📖 New to coding? Here\'s what to do next:'));
|
|
110
115
|
console.log(' 1. Open this folder in VS Code (or any code editor)');
|
|
111
116
|
console.log(' 2. If you have Claude Code installed, type /workflows');
|
|
112
|
-
console.log('
|
|
117
|
+
console.log(' It will guide you step by step');
|
|
113
118
|
console.log(' 3. Or read docs/getting-started.md for a beginner-friendly walkthrough');
|
|
114
119
|
console.log('');
|
|
115
120
|
return;
|
|
@@ -120,7 +125,7 @@ export function printNextSteps(projectName, config, isGuided = false) {
|
|
|
120
125
|
|
|
121
126
|
if (config.stackId === 'nextjs-fullstack') {
|
|
122
127
|
console.log(' npm install');
|
|
123
|
-
console.log(
|
|
128
|
+
console.log(` ${copyEnvCmd()}`);
|
|
124
129
|
console.log(' npx prisma db push');
|
|
125
130
|
console.log(' npm run dev');
|
|
126
131
|
} else if (config.stackId === 'fastapi-backend') {
|
|
@@ -128,7 +133,7 @@ export function printNextSteps(projectName, config, isGuided = false) {
|
|
|
128
133
|
console.log(' python -m venv venv');
|
|
129
134
|
console.log(' source venv/bin/activate # or venv\\Scripts\\activate on Windows');
|
|
130
135
|
console.log(' pip install -r requirements.txt');
|
|
131
|
-
console.log(
|
|
136
|
+
console.log(` ${copyEnvCmd()}`);
|
|
132
137
|
console.log(' uvicorn app.main:app --reload');
|
|
133
138
|
} else if (config.stackId === 'polyglot-fullstack') {
|
|
134
139
|
console.log(' docker compose up -d postgres');
|
|
@@ -136,6 +141,21 @@ export function printNextSteps(projectName, config, isGuided = false) {
|
|
|
136
141
|
console.log(' cd frontend && npm install && npm run dev');
|
|
137
142
|
console.log(' # Backend:');
|
|
138
143
|
console.log(' cd backend && pip install -r requirements.txt && uvicorn app.main:app --reload');
|
|
144
|
+
} else if (config.stackId === 'react-express') {
|
|
145
|
+
console.log(' # Frontend:');
|
|
146
|
+
console.log(' cd frontend && npm install && npm run dev');
|
|
147
|
+
console.log(' # Backend (in a separate terminal):');
|
|
148
|
+
console.log(` cd backend && npm install && ${copyEnvCmd()} && npx prisma db push && npm run dev`);
|
|
149
|
+
} else if (config.stackId === 'remix-fullstack') {
|
|
150
|
+
console.log(' npm install');
|
|
151
|
+
console.log(` ${copyEnvCmd()}`);
|
|
152
|
+
console.log(' npx prisma db push');
|
|
153
|
+
console.log(' npm run dev');
|
|
154
|
+
} else if (config.stackId === 'hono-api') {
|
|
155
|
+
console.log(' npm install');
|
|
156
|
+
console.log(` ${copyEnvCmd()}`);
|
|
157
|
+
console.log(' npx prisma db push');
|
|
158
|
+
console.log(' npm run dev');
|
|
139
159
|
}
|
|
140
160
|
|
|
141
161
|
if (config.claudeCode) {
|
|
@@ -149,6 +169,7 @@ export function printNextSteps(projectName, config, isGuided = false) {
|
|
|
149
169
|
console.log(chalk.dim(' - .claude/commands/ (audit, verify, pre-pr)'));
|
|
150
170
|
console.log(chalk.dim(' - docs/prompt-library.md'));
|
|
151
171
|
console.log(chalk.dim(' - docs/uat/ (acceptance testing)'));
|
|
172
|
+
console.log(chalk.dim(' - .chainproof/ (trust chain tracking)'));
|
|
152
173
|
}
|
|
153
174
|
|
|
154
175
|
console.log('');
|
package/src/init-mode.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
2
3
|
import chalk from 'chalk';
|
|
3
|
-
import { log } from './utils.js';
|
|
4
|
+
import { log, ROOT_DIR, ensureDir } from './utils.js';
|
|
4
5
|
import { scanProject } from './scanner.js';
|
|
5
6
|
import { generateClaudeConfig } from './claude-configurator.js';
|
|
6
7
|
import { generateUAT } from './uat-generator.js';
|
|
8
|
+
import { initChainproof } from './chainproof-bridge.js';
|
|
7
9
|
|
|
8
10
|
export async function runInit(projectDir) {
|
|
9
11
|
console.log('');
|
|
10
|
-
console.log(chalk.bold.cyan(' 🔨 DevForge') + chalk.dim('
|
|
12
|
+
console.log(chalk.bold.cyan(' 🔨 DevForge') + chalk.dim(' Adding dev guardrails'));
|
|
11
13
|
console.log('');
|
|
12
14
|
console.log(' Scanning...');
|
|
13
15
|
console.log('');
|
|
@@ -54,35 +56,47 @@ export async function runInit(projectDir) {
|
|
|
54
56
|
await generateClaudeConfig(projectDir, stackConfig, { skipClaudeMd, mergeSettings });
|
|
55
57
|
|
|
56
58
|
if (!skipClaudeMd) {
|
|
57
|
-
console.log(chalk.green(' ✓ ') + 'CLAUDE.md
|
|
59
|
+
console.log(chalk.green(' ✓ ') + 'CLAUDE.md (project context + rules)');
|
|
58
60
|
} else {
|
|
59
|
-
console.log(chalk.yellow(' ⊘ ') + `CLAUDE.md
|
|
61
|
+
console.log(chalk.yellow(' ⊘ ') + `CLAUDE.md already exists (tip: run ${chalk.cyan('/optimize-claude-md')} to slim it)`);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
if (!scan.infrastructure.hasHooks) {
|
|
63
|
-
console.log(chalk.green(' ✓ ') + '.claude/hooks/
|
|
65
|
+
console.log(chalk.green(' ✓ ') + '.claude/hooks/ (auto-lint, quality gate, file protection)');
|
|
64
66
|
} else {
|
|
65
|
-
console.log(chalk.yellow(' ⊘ ') + '.claude/hooks/
|
|
67
|
+
console.log(chalk.yellow(' ⊘ ') + '.claude/hooks/ already configured');
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
if (!scan.infrastructure.hasAgents) {
|
|
69
|
-
console.log(chalk.green(' ✓ ') + '.claude/agents/
|
|
71
|
+
console.log(chalk.green(' ✓ ') + '.claude/agents/ (code quality, security, spec validator)');
|
|
70
72
|
}
|
|
71
73
|
if (!scan.infrastructure.hasCommands) {
|
|
72
|
-
console.log(chalk.green(' ✓ ') + '.claude/commands/
|
|
74
|
+
console.log(chalk.green(' ✓ ') + '.claude/commands/ (help, status, next, done, audit, pre-pr)');
|
|
73
75
|
}
|
|
74
76
|
if (!scan.infrastructure.hasSkills) {
|
|
75
|
-
console.log(chalk.green(' ✓ ') + '.claude/skills/
|
|
77
|
+
console.log(chalk.green(' ✓ ') + '.claude/skills/ (framework-specific knowledge)');
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
// Generate UAT templates
|
|
79
81
|
if (!scan.infrastructure.hasUAT) {
|
|
80
82
|
await generateUAT(projectDir, stackConfig);
|
|
81
|
-
console.log(chalk.green(' ✓ ') + 'docs/uat/
|
|
83
|
+
console.log(chalk.green(' ✓ ') + 'docs/uat/ (acceptance test templates)');
|
|
82
84
|
} else {
|
|
83
|
-
console.log(chalk.yellow(' ⊘ ') + 'docs/uat/
|
|
85
|
+
console.log(chalk.yellow(' ⊘ ') + 'docs/uat/ already exists');
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
// Initialize ChainProof trust chain
|
|
89
|
+
const chainproofDir = path.join(projectDir, '.chainproof');
|
|
90
|
+
if (!fs.existsSync(chainproofDir)) {
|
|
91
|
+
initChainproof(projectDir);
|
|
92
|
+
console.log(chalk.green(' ✓ ') + '.chainproof/ (trust chain initialized)');
|
|
93
|
+
} else {
|
|
94
|
+
console.log(chalk.yellow(' ⊘ ') + '.chainproof/ already exists');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Install ChainProof MCP server and configure .mcp.json
|
|
98
|
+
setupChainproofMcp(projectDir);
|
|
99
|
+
|
|
86
100
|
console.log('');
|
|
87
101
|
log.success(' Done. Your project is now configured for Claude Code.');
|
|
88
102
|
console.log('');
|
|
@@ -136,3 +150,42 @@ export function buildConfigFromScan(scan) {
|
|
|
136
150
|
|
|
137
151
|
return config;
|
|
138
152
|
}
|
|
153
|
+
|
|
154
|
+
export function setupChainproofMcp(projectDir) {
|
|
155
|
+
// Copy MCP server script into .chainproof/
|
|
156
|
+
const serverSrc = path.join(ROOT_DIR, 'templates', 'chainproof', 'base', '.chainproof', 'mcp-server.mjs');
|
|
157
|
+
const serverDest = path.join(projectDir, '.chainproof', 'mcp-server.mjs');
|
|
158
|
+
if (fs.existsSync(serverSrc) && !fs.existsSync(serverDest)) {
|
|
159
|
+
ensureDir(path.dirname(serverDest));
|
|
160
|
+
fs.copyFileSync(serverSrc, serverDest);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Configure .mcp.json (merge if exists)
|
|
164
|
+
const mcpPath = path.join(projectDir, '.mcp.json');
|
|
165
|
+
const chainproofMcpEntry = {
|
|
166
|
+
command: 'node',
|
|
167
|
+
args: ['.chainproof/mcp-server.mjs'],
|
|
168
|
+
env: {},
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
if (fs.existsSync(mcpPath)) {
|
|
172
|
+
try {
|
|
173
|
+
const existing = JSON.parse(fs.readFileSync(mcpPath, 'utf-8'));
|
|
174
|
+
existing.mcpServers = existing.mcpServers || {};
|
|
175
|
+
if (!existing.mcpServers.chainproof) {
|
|
176
|
+
existing.mcpServers.chainproof = chainproofMcpEntry;
|
|
177
|
+
fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2) + '\n', 'utf-8');
|
|
178
|
+
console.log(chalk.green(' ✓ ') + '.mcp.json (added ChainProof server)');
|
|
179
|
+
} else {
|
|
180
|
+
console.log(chalk.yellow(' ⊘ ') + '.mcp.json already has ChainProof configured');
|
|
181
|
+
}
|
|
182
|
+
} catch {
|
|
183
|
+
// Corrupted .mcp.json, don't touch it
|
|
184
|
+
console.log(chalk.yellow(' ⊘ ') + '.mcp.json exists but could not be parsed');
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
const mcpConfig = { mcpServers: { chainproof: chainproofMcpEntry } };
|
|
188
|
+
fs.writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2) + '\n', 'utf-8');
|
|
189
|
+
console.log(chalk.green(' ✓ ') + '.mcp.json (ChainProof MCP auto-configured)');
|
|
190
|
+
}
|
|
191
|
+
}
|
package/src/menu.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { select, input, Separator } from '@inquirer/prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
|
|
5
|
+
const COMMAND_GROUPS = [
|
|
6
|
+
{
|
|
7
|
+
name: 'Getting Started',
|
|
8
|
+
commands: [
|
|
9
|
+
{ value: 'new', label: 'Create a new project', description: 'Scaffold a full project with AI-powered stack selection' },
|
|
10
|
+
{ value: 'init', label: 'Add guardrails to existing project', description: 'Install hooks, agents, and commands into your current codebase' },
|
|
11
|
+
],
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'Daily Workflow',
|
|
15
|
+
commands: [
|
|
16
|
+
{ value: 'status', label: '/status', description: 'Run all checks and show a project dashboard' },
|
|
17
|
+
{ value: 'next', label: '/next', description: 'Figure out what to work on next' },
|
|
18
|
+
{ value: 'done', label: '/done', description: 'Verify current task is actually complete before moving on' },
|
|
19
|
+
{ value: 'help', label: '/help', description: 'Not sure what to do? Get guided to the right workflow' },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'Development',
|
|
24
|
+
commands: [
|
|
25
|
+
{ value: 'plan', label: '/plan', description: 'Create a comprehensive implementation plan before writing code' },
|
|
26
|
+
{ value: 'tdd', label: '/tdd', description: 'Write failing tests first, then implement (test-driven)' },
|
|
27
|
+
{ value: 'build-fix', label: '/build-fix', description: 'Fix build, lint, and type errors with minimal changes' },
|
|
28
|
+
{ value: 'build-ui', label: '/build-ui', description: 'Build frontend UI components with AI-powered generation' },
|
|
29
|
+
{ value: 'code-review', label: '/code-review', description: 'Review uncommitted changes for issues and quality' },
|
|
30
|
+
{ value: 'simplify', label: '/simplify', description: 'Find duplicate code, long files, and extract shared utilities' },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'Verification',
|
|
35
|
+
commands: [
|
|
36
|
+
{ value: 'verify-all', label: '/verify-all', description: 'Run the full verification chain on current changes' },
|
|
37
|
+
{ value: 'full-audit', label: '/full-audit', description: 'Run every audit and review agent in a single pass' },
|
|
38
|
+
{ value: 'audit-spec', label: '/audit-spec', description: 'Validate code against the specification' },
|
|
39
|
+
{ value: 'audit-wiring', label: '/audit-wiring', description: 'Verify API endpoints are wired between frontend and backend' },
|
|
40
|
+
{ value: 'audit-security', label: '/audit-security', description: 'Run a focused security audit on changed files' },
|
|
41
|
+
{ value: 'verify-intent', label: '/verify-intent', description: 'Check Intent Verification Protocol compliance' },
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'Release',
|
|
46
|
+
commands: [
|
|
47
|
+
{ value: 'pre-pr', label: '/pre-pr', description: 'Run the complete pre-PR checklist before creating a pull request' },
|
|
48
|
+
{ value: 'run-uat', label: '/run-uat', description: 'Execute UAT verification against test scenarios' },
|
|
49
|
+
{ value: 'live-uat', label: '/live-uat', description: 'Run live UAT by interacting with the running application' },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'Generation',
|
|
54
|
+
commands: [
|
|
55
|
+
{ value: 'generate-prd', label: '/generate-prd', description: 'Generate a Product Requirements Document' },
|
|
56
|
+
{ value: 'generate-sdd', label: '/generate-sdd', description: 'Generate a Software Design Document from the codebase' },
|
|
57
|
+
{ value: 'generate-uat', label: '/generate-uat', description: 'Generate UAT test scenarios for the project' },
|
|
58
|
+
{ value: 'optimize-claude-md', label: '/optimize-claude-md', description: 'Analyze and optimize the CLAUDE.md file' },
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'Session',
|
|
63
|
+
commands: [
|
|
64
|
+
{ value: 'save-session', label: '/save-session', description: 'Save current session state for later' },
|
|
65
|
+
{ value: 'resume-session', label: '/resume-session', description: 'Load a saved session and pick up where you left off' },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'Project Tools',
|
|
70
|
+
commands: [
|
|
71
|
+
{ value: 'doctor', label: 'Diagnose project', description: 'Find and fix issues like dead code, flaky tests, oversized files' },
|
|
72
|
+
{ value: 'ci', label: 'CI health check', description: 'Non-interactive health checks for CI/CD pipelines' },
|
|
73
|
+
{ value: 'update', label: 'Check for updates', description: 'See if a newer version of DevForge is available' },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
// Commands that are Claude Code slash commands (run inside Claude Code, not the terminal)
|
|
79
|
+
const CLAUDE_COMMANDS = new Set([
|
|
80
|
+
'status', 'next', 'done', 'help', 'plan', 'tdd', 'build-fix', 'build-ui',
|
|
81
|
+
'code-review', 'simplify', 'verify-all', 'full-audit', 'audit-spec', 'generate-sdd',
|
|
82
|
+
'audit-wiring', 'audit-security', 'verify-intent', 'pre-pr', 'run-uat',
|
|
83
|
+
'live-uat', 'generate-prd', 'generate-uat', 'optimize-claude-md',
|
|
84
|
+
'save-session', 'resume-session',
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
export async function showInteractiveMenu() {
|
|
88
|
+
console.log('');
|
|
89
|
+
console.log(` ${chalk.bold.cyan('DevForge')} ${chalk.dim('AI-first project scaffolding')}`);
|
|
90
|
+
console.log('');
|
|
91
|
+
|
|
92
|
+
// Build choices with separators for groups
|
|
93
|
+
const choices = [];
|
|
94
|
+
let recommendation = null;
|
|
95
|
+
|
|
96
|
+
// Detect recommendation based on project state
|
|
97
|
+
try {
|
|
98
|
+
if (!fs.existsSync('package.json') && !fs.existsSync('pyproject.toml')) {
|
|
99
|
+
recommendation = 'new';
|
|
100
|
+
} else if (!fs.existsSync('.claude')) {
|
|
101
|
+
recommendation = 'init';
|
|
102
|
+
}
|
|
103
|
+
} catch { /* ignore */ }
|
|
104
|
+
|
|
105
|
+
for (const group of COMMAND_GROUPS) {
|
|
106
|
+
choices.push(new Separator(chalk.dim(` ${group.name}`)));
|
|
107
|
+
for (const cmd of group.commands) {
|
|
108
|
+
const isRecommended = cmd.value === recommendation;
|
|
109
|
+
const badge = isRecommended ? chalk.green(' recommended') : '';
|
|
110
|
+
const label = CLAUDE_COMMANDS.has(cmd.value)
|
|
111
|
+
? chalk.cyan(cmd.label)
|
|
112
|
+
: chalk.bold(cmd.label);
|
|
113
|
+
|
|
114
|
+
choices.push({
|
|
115
|
+
value: cmd.value,
|
|
116
|
+
name: `${label}${badge} ${chalk.dim(cmd.description)}`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const selected = await select({
|
|
122
|
+
message: 'What would you like to do?',
|
|
123
|
+
choices,
|
|
124
|
+
pageSize: 15,
|
|
125
|
+
loop: false,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return selected;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function handleMenuSelection(selected) {
|
|
132
|
+
// CLI commands — execute directly
|
|
133
|
+
if (selected === 'new') {
|
|
134
|
+
const name = await input({ message: 'Project name:' });
|
|
135
|
+
if (!name) return;
|
|
136
|
+
const { runNew } = await import('./index.js');
|
|
137
|
+
await runNew(name);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (selected === 'init') {
|
|
142
|
+
const { runInit } = await import('./init-mode.js');
|
|
143
|
+
await runInit(process.cwd());
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (selected === 'doctor') {
|
|
148
|
+
const { runDoctor } = await import('./doctor.js');
|
|
149
|
+
await runDoctor(process.cwd());
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (selected === 'ci') {
|
|
154
|
+
const { runCI } = await import('./ci-mode.js');
|
|
155
|
+
await runCI(process.cwd());
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (selected === 'update') {
|
|
160
|
+
const { runUpdate } = await import('./update.js');
|
|
161
|
+
await runUpdate();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Claude Code commands — show how to run them
|
|
166
|
+
if (CLAUDE_COMMANDS.has(selected)) {
|
|
167
|
+
console.log('');
|
|
168
|
+
console.log(` ${chalk.cyan('/')}${chalk.bold.cyan(selected)} is a Claude Code command.`);
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(` To use it, open ${chalk.bold('Claude Code')} in your project and type:`);
|
|
171
|
+
console.log(` ${chalk.green(`/${selected}`)}`);
|
|
172
|
+
console.log('');
|
|
173
|
+
console.log(` ${chalk.dim('These commands work inside Claude Code (the AI assistant).')}`);
|
|
174
|
+
console.log(` ${chalk.dim('They run agents that analyze, review, and modify your code.')}`);
|
|
175
|
+
console.log('');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
}
|
package/src/prompts.js
CHANGED
|
@@ -21,19 +21,12 @@ const LANGUAGE_CHOICES = [
|
|
|
21
21
|
{ value: 'rust', name: 'Rust' },
|
|
22
22
|
];
|
|
23
23
|
|
|
24
|
-
const DEPLOYMENT_CHOICES = [
|
|
25
|
-
{ value: 'docker', name: 'Docker / Docker Compose' },
|
|
26
|
-
{ value: 'vercel', name: 'Vercel' },
|
|
27
|
-
{ value: 'aws', name: 'AWS' },
|
|
28
|
-
{ value: 'gcp', name: 'Google Cloud' },
|
|
29
|
-
];
|
|
30
|
-
|
|
31
24
|
export async function askNewMode() {
|
|
32
25
|
const mode = await select({
|
|
33
26
|
message: 'How would you like to start?',
|
|
34
27
|
choices: [
|
|
35
28
|
{ value: 'guided', name: '💬 Describe what you want to build (recommended for beginners)' },
|
|
36
|
-
{ value: 'developer', name: '⚡ I know my stack
|
|
29
|
+
{ value: 'developer', name: '⚡ I know my stack, let me pick (for developers)' },
|
|
37
30
|
],
|
|
38
31
|
});
|
|
39
32
|
return mode;
|
|
@@ -41,7 +34,7 @@ export async function askNewMode() {
|
|
|
41
34
|
|
|
42
35
|
export async function askDescription() {
|
|
43
36
|
const description = await input({
|
|
44
|
-
message: 'Tell me about what you want to build.\n Don\'t worry about technical details
|
|
37
|
+
message: 'Tell me about what you want to build.\n Don\'t worry about technical details. Just describe it like you\'re explaining it to a friend.\n\n ',
|
|
45
38
|
});
|
|
46
39
|
return description;
|
|
47
40
|
}
|
|
@@ -57,8 +50,8 @@ export async function askGuidedConfirm() {
|
|
|
57
50
|
const choice = await select({
|
|
58
51
|
message: 'Sound right?',
|
|
59
52
|
choices: [
|
|
60
|
-
{ value: 'yes', name: 'Yes
|
|
61
|
-
{ value: 'adjust', name: 'No
|
|
53
|
+
{ value: 'yes', name: 'Yes, create it!' },
|
|
54
|
+
{ value: 'adjust', name: 'No, let me adjust' },
|
|
62
55
|
],
|
|
63
56
|
});
|
|
64
57
|
return choice;
|
|
@@ -88,7 +81,7 @@ export async function askServiceType() {
|
|
|
88
81
|
export async function askRefinements(serviceType) {
|
|
89
82
|
const refinements = {};
|
|
90
83
|
|
|
91
|
-
// Q1: Language preference
|
|
84
|
+
// Q1: Language preference. Adapt choices based on service type
|
|
92
85
|
if (['api_service', 'cli_tool', 'microservice'].includes(serviceType)) {
|
|
93
86
|
refinements.language = await select({
|
|
94
87
|
message: 'Language preference?',
|