forgedev 1.2.0 → 1.4.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.
Files changed (183) hide show
  1. package/README.md +57 -10
  2. package/bin/chainproof.js +126 -0
  3. package/bin/devforge.js +1 -1
  4. package/package.json +25 -7
  5. package/src/chainproof-bridge.js +330 -0
  6. package/src/ci-mode.js +85 -0
  7. package/src/claude-configurator.js +171 -78
  8. package/src/cli.js +30 -7
  9. package/src/composer.js +242 -214
  10. package/src/doctor-checks-chainproof.js +106 -0
  11. package/src/doctor-checks.js +39 -20
  12. package/src/doctor-prompts.js +9 -9
  13. package/src/doctor.js +37 -4
  14. package/src/guided.js +3 -3
  15. package/src/index.js +31 -10
  16. package/src/init-mode.js +76 -12
  17. package/src/menu.js +178 -0
  18. package/src/prompts.js +5 -12
  19. package/src/recommender.js +163 -30
  20. package/src/scanner.js +57 -2
  21. package/src/uat-generator.js +204 -189
  22. package/src/update-check.js +9 -4
  23. package/src/update.js +57 -13
  24. package/src/utils.js +162 -5
  25. package/templates/ai/guardrails-py/backend/app/ai/__init__.py +29 -0
  26. package/templates/ai/guardrails-py/backend/app/ai/audit_log.py +133 -0
  27. package/templates/ai/guardrails-py/backend/app/ai/client.py.template +323 -0
  28. package/templates/ai/guardrails-py/backend/app/ai/health.py.template +157 -0
  29. package/templates/ai/guardrails-py/backend/app/ai/input_guard.py +98 -0
  30. package/templates/ai/guardrails-ts/src/lib/ai/audit-log.ts.template +164 -0
  31. package/templates/ai/guardrails-ts/src/lib/ai/client.ts.template +403 -0
  32. package/templates/ai/guardrails-ts/src/lib/ai/health.ts.template +165 -0
  33. package/templates/ai/guardrails-ts/src/lib/ai/index.ts.template +17 -0
  34. package/templates/ai/guardrails-ts/src/lib/ai/input-guard.ts.template +124 -0
  35. package/templates/auth/nextauth/src/lib/auth.ts.template +12 -7
  36. package/templates/backend/express/Dockerfile.template +18 -0
  37. package/templates/backend/express/package.json.template +33 -0
  38. package/templates/backend/express/src/index.ts.template +34 -0
  39. package/templates/backend/express/src/routes/health.ts.template +27 -0
  40. package/templates/backend/express/tsconfig.json +17 -0
  41. package/templates/backend/fastapi/backend/Dockerfile.template +5 -0
  42. package/templates/backend/fastapi/backend/app/api/health.py.template +1 -1
  43. package/templates/backend/fastapi/backend/app/core/config.py.template +1 -1
  44. package/templates/backend/fastapi/backend/app/core/errors.py +1 -1
  45. package/templates/backend/fastapi/backend/app/main.py.template +3 -1
  46. package/templates/backend/fastapi/backend/requirements.txt.template +2 -0
  47. package/templates/backend/hono/Dockerfile.template +18 -0
  48. package/templates/backend/hono/package.json.template +31 -0
  49. package/templates/backend/hono/src/index.ts.template +32 -0
  50. package/templates/backend/hono/src/routes/health.ts.template +27 -0
  51. package/templates/backend/hono/tsconfig.json +18 -0
  52. package/templates/base/.gitignore.template +3 -0
  53. package/templates/base/docs/uat/UAT_TEMPLATE.md.template +1 -1
  54. package/templates/chainproof/base/.chainproof/config.json.template +11 -0
  55. package/templates/chainproof/base/.chainproof/mcp-server.mjs +310 -0
  56. package/templates/chainproof/base/.mcp.json +9 -0
  57. package/templates/chainproof/fastapi/.chainproof/middleware.json.template +14 -0
  58. package/templates/chainproof/nextjs/.chainproof/hooks.json.template +19 -0
  59. package/templates/chainproof/polyglot/.chainproof/config.json.template +21 -0
  60. package/templates/claude-code/agents/architect.md +25 -11
  61. package/templates/claude-code/agents/build-error-resolver.md +19 -5
  62. package/templates/claude-code/agents/chief-of-staff.md +42 -8
  63. package/templates/claude-code/agents/code-quality-reviewer.md +14 -0
  64. package/templates/claude-code/agents/database-reviewer.md +15 -1
  65. package/templates/claude-code/agents/deep-reviewer.md +191 -0
  66. package/templates/claude-code/agents/doc-updater.md +19 -5
  67. package/templates/claude-code/agents/docs-lookup.md +19 -5
  68. package/templates/claude-code/agents/e2e-runner.md +26 -12
  69. package/templates/claude-code/agents/enforcement-gate.md +102 -0
  70. package/templates/claude-code/agents/frontend-builder.md +188 -0
  71. package/templates/claude-code/agents/harness-optimizer.md +36 -1
  72. package/templates/claude-code/agents/loop-operator.md +27 -13
  73. package/templates/claude-code/agents/planner.md +21 -7
  74. package/templates/claude-code/agents/product-strategist.md +24 -10
  75. package/templates/claude-code/agents/production-readiness.md +14 -0
  76. package/templates/claude-code/agents/prompt-auditor.md +115 -0
  77. package/templates/claude-code/agents/refactor-cleaner.md +22 -8
  78. package/templates/claude-code/agents/security-reviewer.md +14 -0
  79. package/templates/claude-code/agents/spec-validator.md +15 -1
  80. package/templates/claude-code/agents/tdd-guide.md +21 -7
  81. package/templates/claude-code/agents/uat-validator.md +14 -0
  82. package/templates/claude-code/claude-md/base.md +14 -7
  83. package/templates/claude-code/claude-md/fastapi.md +8 -8
  84. package/templates/claude-code/claude-md/fullstack.md +6 -6
  85. package/templates/claude-code/claude-md/hono.md +18 -0
  86. package/templates/claude-code/claude-md/nextjs.md +5 -5
  87. package/templates/claude-code/claude-md/remix.md +18 -0
  88. package/templates/claude-code/commands/audit-security.md +14 -0
  89. package/templates/claude-code/commands/audit-spec.md +14 -0
  90. package/templates/claude-code/commands/audit-wiring.md +14 -0
  91. package/templates/claude-code/commands/build-fix.md +28 -0
  92. package/templates/claude-code/commands/build-ui.md +59 -0
  93. package/templates/claude-code/commands/code-review.md +53 -31
  94. package/templates/claude-code/commands/fix-loop.md +211 -0
  95. package/templates/claude-code/commands/full-audit.md +36 -8
  96. package/templates/claude-code/commands/generate-prd.md +1 -1
  97. package/templates/claude-code/commands/generate-sdd.md +74 -0
  98. package/templates/claude-code/commands/generate-uat.md +107 -35
  99. package/templates/claude-code/commands/help.md +68 -0
  100. package/templates/claude-code/commands/live-uat.md +268 -0
  101. package/templates/claude-code/commands/optimize-claude-md.md +15 -1
  102. package/templates/claude-code/commands/plan.md +3 -3
  103. package/templates/claude-code/commands/pre-pr.md +57 -19
  104. package/templates/claude-code/commands/product-strategist.md +21 -0
  105. package/templates/claude-code/commands/resume-session.md +10 -10
  106. package/templates/claude-code/commands/run-uat.md +59 -2
  107. package/templates/claude-code/commands/save-session.md +10 -10
  108. package/templates/claude-code/commands/simplify.md +36 -0
  109. package/templates/claude-code/commands/tdd.md +17 -18
  110. package/templates/claude-code/commands/verify-all.md +24 -0
  111. package/templates/claude-code/commands/verify-intent.md +55 -0
  112. package/templates/claude-code/commands/workflows.md +52 -40
  113. package/templates/claude-code/hooks/polyglot.json +10 -1
  114. package/templates/claude-code/hooks/python.json +10 -1
  115. package/templates/claude-code/hooks/scripts/autofix-polyglot.mjs +2 -2
  116. package/templates/claude-code/hooks/scripts/autofix-python.mjs +1 -1
  117. package/templates/claude-code/hooks/scripts/autofix-typescript.mjs +1 -1
  118. package/templates/claude-code/hooks/scripts/code-hygiene.mjs +293 -0
  119. package/templates/claude-code/hooks/scripts/pre-commit-gate.mjs +207 -0
  120. package/templates/claude-code/hooks/typescript.json +10 -1
  121. package/templates/claude-code/skills/ai-prompts/SKILL.md +119 -41
  122. package/templates/claude-code/skills/git-workflow/SKILL.md +5 -5
  123. package/templates/claude-code/skills/nextjs/SKILL.md +1 -1
  124. package/templates/claude-code/skills/playwright/SKILL.md +5 -5
  125. package/templates/claude-code/skills/security-api/SKILL.md +1 -1
  126. package/templates/claude-code/skills/security-web/SKILL.md +1 -1
  127. package/templates/claude-code/skills/testing-patterns/SKILL.md +9 -9
  128. package/templates/database/prisma-postgres/{.env.example → .env.example.template} +1 -0
  129. package/templates/database/sqlalchemy-postgres/{.env.example → .env.example.template} +1 -0
  130. package/templates/docs-portal/fastapi/backend/app/portal/__pycache__/docs_reader.cpython-314.pyc +0 -0
  131. package/templates/docs-portal/fastapi/backend/app/portal/docs_reader.py +201 -0
  132. package/templates/docs-portal/fastapi/backend/app/portal/html_renderer.py +229 -0
  133. package/templates/docs-portal/fastapi/backend/app/portal/router.py.template +35 -0
  134. package/templates/docs-portal/nextjs/src/app/portal/[category]/[slug]/page.tsx +81 -0
  135. package/templates/docs-portal/nextjs/src/app/portal/[category]/page.tsx +65 -0
  136. package/templates/docs-portal/nextjs/src/app/portal/layout.tsx.template +54 -0
  137. package/templates/docs-portal/nextjs/src/app/portal/page.tsx +85 -0
  138. package/templates/docs-portal/nextjs/src/components/portal/markdown-renderer.tsx +101 -0
  139. package/templates/docs-portal/nextjs/src/components/portal/mobile-portal-nav.tsx +81 -0
  140. package/templates/docs-portal/nextjs/src/components/portal/portal-nav.tsx +86 -0
  141. package/templates/docs-portal/nextjs/src/lib/docs.ts +139 -0
  142. package/templates/frontend/nextjs/package.json.template +3 -1
  143. package/templates/frontend/react/index.html.template +12 -0
  144. package/templates/frontend/react/package.json.template +34 -0
  145. package/templates/frontend/react/src/App.tsx.template +10 -0
  146. package/templates/frontend/react/src/index.css +1 -0
  147. package/templates/frontend/react/src/main.tsx +10 -0
  148. package/templates/frontend/react/tsconfig.json +17 -0
  149. package/templates/frontend/react/vite.config.ts.template +15 -0
  150. package/templates/frontend/react/vitest.config.ts +9 -0
  151. package/templates/frontend/remix/app/root.tsx.template +31 -0
  152. package/templates/frontend/remix/app/routes/_index.tsx.template +19 -0
  153. package/templates/frontend/remix/app/routes/api.health.ts.template +10 -0
  154. package/templates/frontend/remix/app/tailwind.css +1 -0
  155. package/templates/frontend/remix/package.json.template +39 -0
  156. package/templates/frontend/remix/tsconfig.json +18 -0
  157. package/templates/frontend/remix/vite.config.ts.template +7 -0
  158. package/templates/infra/github-actions/.github/workflows/ci.yml.template +3 -0
  159. package/templates/infra/k8s/k8s/deployment.yml.template +70 -0
  160. package/templates/infra/k8s/k8s/hpa.yml.template +24 -0
  161. package/templates/infra/k8s/k8s/ingress.yml.template +26 -0
  162. package/templates/infra/k8s/k8s/kustomization.yml.template +13 -0
  163. package/templates/infra/k8s/k8s/namespace.yml.template +4 -0
  164. package/templates/infra/k8s/k8s/networkpolicy.yml.template +41 -0
  165. package/templates/infra/k8s/k8s/secrets.yml.template +10 -0
  166. package/templates/infra/k8s/k8s/service.yml.template +15 -0
  167. package/templates/testing/load/k6/README.md.template +48 -0
  168. package/templates/testing/load/k6/load-test.js.template +57 -0
  169. package/docs/00-README.md +0 -310
  170. package/docs/01-universal-prompt-library.md +0 -1049
  171. package/docs/02-claude-code-mastery-playbook.md +0 -283
  172. package/docs/03-multi-agent-verification.md +0 -565
  173. package/docs/04-errata-and-verification-checklist.md +0 -284
  174. package/docs/05-universal-scaffolder-vision.md +0 -452
  175. package/docs/06-confidence-assessment-and-repo-prompt.md +0 -407
  176. package/docs/errata.md +0 -58
  177. package/docs/multi-agent-verification.md +0 -66
  178. package/docs/playbook.md +0 -95
  179. package/docs/prompt-library.md +0 -160
  180. package/docs/uat/UAT_CHECKLIST.csv +0 -9
  181. package/docs/uat/UAT_TEMPLATE.md +0 -163
  182. package/templates/claude-code/commands/done.md +0 -19
  183. /package/{docs/plans/.gitkeep → templates/docs-portal/fastapi/backend/app/portal/__init__.py} +0 -0
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { ROOT_DIR, ensureDir, writeFile, readTemplate, replaceVars, log } from './utils.js';
3
+ import { ROOT_DIR, ensureDir, writeFile, readTemplate, replaceVars, getStackCommands, toPascalCase } from './utils.js';
4
4
 
5
5
  const CLAUDE_TEMPLATES_DIR = path.join(ROOT_DIR, 'templates', 'claude-code');
6
6
  const DOCS_DIR = path.join(ROOT_DIR, 'docs');
@@ -13,79 +13,108 @@ export async function generateClaudeConfig(outputDir, stackConfig, options = {})
13
13
  }
14
14
  generateHooks(outputDir, stackConfig, { merge: options.mergeSettings });
15
15
  generateSkills(outputDir, stackConfig);
16
- generateAgents(outputDir, stackConfig, vars);
17
- generateCommands(outputDir, stackConfig, vars);
16
+ const agents = generateAgents(outputDir, stackConfig, vars);
17
+ const commands = generateCommands(outputDir, stackConfig, vars);
18
18
  copyPromptLibrary(outputDir);
19
+ stampVersion(outputDir);
20
+
21
+ return { agents, commands };
22
+ }
23
+
24
+ function stampVersion(outputDir) {
25
+ const pkg = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, 'package.json'), 'utf-8'));
26
+ writeFile(path.join(outputDir, '.claude', '.devforge-version'), JSON.stringify({
27
+ version: pkg.version,
28
+ generatedAt: new Date().toISOString(),
29
+ }, null, 2) + '\n');
19
30
  }
20
31
 
21
32
  function buildClaudeVars(config) {
22
33
  const vars = {
23
34
  PROJECT_NAME: config.projectName,
24
- PROJECT_NAME_PASCAL: config.projectName.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(''),
35
+ PROJECT_NAME_PASCAL: toPascalCase(config.projectName),
25
36
  };
26
37
 
27
- if (config.stackId === 'nextjs-fullstack') {
28
- vars.STACK_SUMMARY = 'Next.js 15 (App Router) + TypeScript + Tailwind CSS + Prisma + PostgreSQL';
29
- vars.LINT_COMMAND = 'npx eslint .';
30
- vars.TYPE_CHECK_COMMAND = 'npx tsc --noEmit';
31
- vars.TEST_COMMAND = 'npx vitest run';
32
- vars.BUILD_COMMAND = 'npm run build';
33
- vars.DEV_COMMAND = 'npm run dev';
34
- vars.DIR_MAP = `- src/app/ Next.js App Router pages and API routes
35
- - src/lib/ Shared utilities, database client, error handling
36
- - src/components/ React components
37
- - prisma/ Database schema and migrations
38
- - e2e/ — Playwright E2E tests`;
39
- } else if (config.stackId === 'fastapi-backend') {
40
- vars.STACK_SUMMARY = 'FastAPI + Python + SQLAlchemy 2.0 + PostgreSQL + Alembic';
41
- vars.LINT_COMMAND = 'ruff check .';
42
- vars.TYPE_CHECK_COMMAND = 'pyright';
43
- vars.TEST_COMMAND = 'pytest';
44
- vars.BUILD_COMMAND = 'docker build -t app .';
45
- vars.DEV_COMMAND = 'uvicorn app.main:app --reload';
46
- vars.DIR_MAP = `- backend/app/ FastAPI application
47
- - backend/app/api/ API route handlers
48
- - backend/app/core/ Config, security, error handling
49
- - backend/app/db/ — Database session and models
50
- - backend/app/models/ — SQLAlchemy models
51
- - backend/app/schemas/ Pydantic schemas
52
- - backend/tests/ Pytest tests
53
- - backend/alembic/ Database migrations`;
54
- } else if (config.stackId === 'polyglot-fullstack') {
55
- vars.STACK_SUMMARY = 'Next.js 15 (frontend) + FastAPI (backend) + PostgreSQL';
56
- vars.LINT_COMMAND = 'cd frontend && npx eslint . && cd ../backend && ruff check .';
57
- vars.TYPE_CHECK_COMMAND = 'cd frontend && npx tsc --noEmit';
58
- vars.TEST_COMMAND = 'cd frontend && npx vitest run && cd ../backend && pytest';
59
- vars.BUILD_COMMAND = 'docker compose build';
60
- vars.DEV_COMMAND = 'docker compose up';
61
- vars.DIR_MAP = `- frontend/ — Next.js 15 App Router application
62
- - frontend/src/app/ Pages and API routes
63
- - frontend/src/lib/ Shared utilities
64
- - backend/ FastAPI application
65
- - backend/app/api/ API route handlers
66
- - backend/app/core/ Config, security, error handling
67
- - backend/app/db/ Database session and models
68
- - e2e/ Playwright E2E tests`;
38
+ // Commands vary by stack (shared with composer)
39
+ Object.assign(vars, getStackCommands(config.stackId));
40
+
41
+ const claudeVars = {
42
+ 'nextjs-fullstack': {
43
+ STACK_SUMMARY: 'Next.js 15 (App Router) + TypeScript + Tailwind CSS + Prisma + PostgreSQL',
44
+ DIR_MAP: `- src/app/ - Next.js App Router pages and API routes
45
+ - src/lib/ - Shared utilities, database client, error handling
46
+ - src/components/ - React components
47
+ - prisma/ - Database schema and migrations
48
+ - e2e/ - Playwright E2E tests`,
49
+ },
50
+ 'fastapi-backend': {
51
+ STACK_SUMMARY: 'FastAPI + Python + SQLAlchemy 2.0 + PostgreSQL + Alembic',
52
+ DIR_MAP: `- backend/app/ - FastAPI application
53
+ - backend/app/api/ - API route handlers
54
+ - backend/app/core/ - Config, security, error handling
55
+ - backend/app/db/ - Database session and models
56
+ - backend/app/models/ - SQLAlchemy models
57
+ - backend/app/schemas/ - Pydantic schemas
58
+ - backend/tests/ - Pytest tests
59
+ - backend/alembic/ - Database migrations`,
60
+ },
61
+ 'polyglot-fullstack': {
62
+ STACK_SUMMARY: 'Next.js 15 (frontend) + FastAPI (backend) + PostgreSQL',
63
+ DIR_MAP: `- frontend/ - Next.js 15 App Router application
64
+ - frontend/src/app/ - Pages and API routes
65
+ - frontend/src/lib/ - Shared utilities
66
+ - backend/ - FastAPI application
67
+ - backend/app/api/ - API route handlers
68
+ - backend/app/core/ - Config, security, error handling
69
+ - backend/app/db/ - Database session and models
70
+ - e2e/ - Playwright E2E tests`,
71
+ },
72
+ 'react-express': {
73
+ STACK_SUMMARY: 'React (Vite) + Express + TypeScript + Prisma + PostgreSQL',
74
+ DIR_MAP: `- frontend/ - React (Vite) SPA
75
+ - frontend/src/ - React components and pages
76
+ - backend/ - Express API server
77
+ - backend/src/ - Express routes and middleware
78
+ - backend/src/routes/ - API route handlers
79
+ - backend/prisma/ - Database schema and migrations`,
80
+ },
81
+ 'remix-fullstack': {
82
+ STACK_SUMMARY: 'Remix + Vite + TypeScript + Tailwind CSS + Prisma + PostgreSQL',
83
+ DIR_MAP: `- app/ - Remix application
84
+ - app/routes/ - File-based routes and API resource routes
85
+ - app/routes/api.health.ts - Health check endpoint
86
+ - prisma/ - Database schema and migrations`,
87
+ },
88
+ 'hono-api': {
89
+ STACK_SUMMARY: 'Hono + TypeScript + Prisma + PostgreSQL',
90
+ DIR_MAP: `- src/ - Hono application
91
+ - src/routes/ - API route handlers
92
+ - src/routes/health.ts - Health check endpoints
93
+ - prisma/ - Database schema and migrations`,
94
+ },
95
+ };
96
+ if (claudeVars[config.stackId]) {
97
+ Object.assign(vars, claudeVars[config.stackId]);
69
98
  }
70
99
 
71
100
  // Build skills list for CLAUDE.md reference
72
101
  const skillsList = [
73
- '- `@.claude/skills/git-workflow/` Git branching, commits, and PR workflow',
74
- '- `@.claude/skills/testing-patterns/` Test pyramid, AAA pattern, mocking strategies',
102
+ '- `@.claude/skills/git-workflow/`: Git branching, commits, and PR workflow',
103
+ '- `@.claude/skills/testing-patterns/`: Test pyramid, AAA pattern, mocking strategies',
75
104
  ];
76
105
  if (config.frontend?.framework === 'nextjs') {
77
- skillsList.push('- `@.claude/skills/nextjs/` Next.js patterns and conventions');
78
- skillsList.push('- `@.claude/skills/security-web/` Frontend security practices');
106
+ skillsList.push('- `@.claude/skills/nextjs/`: Next.js patterns and conventions');
107
+ skillsList.push('- `@.claude/skills/security-web/`: Frontend security practices');
79
108
  }
80
109
  if (config.backend?.framework === 'fastapi') {
81
- skillsList.push('- `@.claude/skills/fastapi/` FastAPI patterns and conventions');
82
- skillsList.push('- `@.claude/skills/security-api/` API security practices');
110
+ skillsList.push('- `@.claude/skills/fastapi/`: FastAPI patterns and conventions');
111
+ skillsList.push('- `@.claude/skills/security-api/`: API security practices');
83
112
  }
84
113
  if (config.testing?.e2e === 'playwright') {
85
- skillsList.push('- `@.claude/skills/playwright/` E2E testing patterns');
114
+ skillsList.push('- `@.claude/skills/playwright/`: E2E testing patterns');
86
115
  }
87
116
  if (config.ai) {
88
- skillsList.push('- `@.claude/skills/ai-prompts/` AI/LLM prompt patterns');
117
+ skillsList.push('- `@.claude/skills/ai-prompts/`: AI/LLM prompt patterns');
89
118
  }
90
119
  vars.SKILLS_LIST = skillsList.length > 0 ? skillsList.join('\n') : '- (none generated)';
91
120
 
@@ -98,14 +127,18 @@ function generateClaudeMd(outputDir, config, vars) {
98
127
  let content = readTemplate(basePath);
99
128
 
100
129
  // Read stack-specific section
101
- let stackSection = '';
102
- if (config.stackId === 'nextjs-fullstack') {
103
- stackSection = readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'claude-md', 'nextjs.md'));
104
- } else if (config.stackId === 'fastapi-backend') {
105
- stackSection = readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'claude-md', 'fastapi.md'));
106
- } else if (config.stackId === 'polyglot-fullstack') {
107
- stackSection = readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'claude-md', 'fullstack.md'));
108
- }
130
+ const claudeMdTemplates = {
131
+ 'nextjs-fullstack': 'nextjs.md',
132
+ 'fastapi-backend': 'fastapi.md',
133
+ 'polyglot-fullstack': 'fullstack.md',
134
+ 'react-express': 'fullstack.md',
135
+ 'remix-fullstack': 'remix.md',
136
+ 'hono-api': 'hono.md',
137
+ };
138
+ const mdFile = claudeMdTemplates[config.stackId];
139
+ const stackSection = mdFile
140
+ ? readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'claude-md', mdFile))
141
+ : '';
109
142
 
110
143
  content = content.replace('{{STACK_SPECIFIC_RULES}}', stackSection);
111
144
  content = replaceVars(content, vars);
@@ -114,18 +147,19 @@ function generateClaudeMd(outputDir, config, vars) {
114
147
  }
115
148
 
116
149
  function generateHooks(outputDir, config, options = {}) {
117
- let hookFile;
118
- let scriptFiles = ['guard-protected-files.mjs'];
119
-
120
- if (config.stackId === 'nextjs-fullstack') {
121
- hookFile = 'typescript.json';
122
- scriptFiles.push('autofix-typescript.mjs');
123
- } else if (config.stackId === 'fastapi-backend') {
124
- hookFile = 'python.json';
125
- scriptFiles.push('autofix-python.mjs');
126
- } else if (config.stackId === 'polyglot-fullstack') {
127
- hookFile = 'polyglot.json';
128
- scriptFiles.push('autofix-polyglot.mjs');
150
+ const hookConfig = {
151
+ 'nextjs-fullstack': { file: 'typescript.json', autofix: 'autofix-typescript.mjs' },
152
+ 'fastapi-backend': { file: 'python.json', autofix: 'autofix-python.mjs' },
153
+ 'polyglot-fullstack': { file: 'polyglot.json', autofix: 'autofix-polyglot.mjs' },
154
+ 'react-express': { file: 'typescript.json', autofix: 'autofix-typescript.mjs' },
155
+ 'remix-fullstack': { file: 'typescript.json', autofix: 'autofix-typescript.mjs' },
156
+ 'hono-api': { file: 'typescript.json', autofix: 'autofix-typescript.mjs' },
157
+ };
158
+ const hook = hookConfig[config.stackId];
159
+ const hookFile = hook?.file;
160
+ const scriptFiles = ['guard-protected-files.mjs', 'code-hygiene.mjs', 'pre-commit-gate.mjs'];
161
+ if (hook?.autofix) {
162
+ scriptFiles.push(hook.autofix);
129
163
  }
130
164
 
131
165
  const settingsPath = path.join(outputDir, '.claude', 'settings.json');
@@ -134,7 +168,7 @@ function generateHooks(outputDir, config, options = {}) {
134
168
  // Merge hooks into existing settings.json
135
169
  const existing = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
136
170
  const incoming = JSON.parse(readTemplate(path.join(CLAUDE_TEMPLATES_DIR, 'hooks', hookFile)));
137
- const merged = deepMergeSettings(existing, incoming);
171
+ const merged = mergeHooksIntoSettings(existing, incoming);
138
172
  writeFile(settingsPath, JSON.stringify(merged, null, 2));
139
173
  } else {
140
174
  const hookPath = path.join(CLAUDE_TEMPLATES_DIR, 'hooks', hookFile);
@@ -153,7 +187,7 @@ function generateHooks(outputDir, config, options = {}) {
153
187
  }
154
188
  }
155
189
 
156
- function deepMergeSettings(existing, incoming) {
190
+ function mergeHooksIntoSettings(existing, incoming) {
157
191
  const merged = { ...existing };
158
192
  if (incoming.hooks) {
159
193
  merged.hooks = merged.hooks || {};
@@ -178,7 +212,7 @@ function deepMergeSettings(existing, incoming) {
178
212
  }
179
213
 
180
214
  function generateSkills(outputDir, config) {
181
- // Universal skills always included
215
+ // Universal skills, always included
182
216
  const skillsToInclude = ['git-workflow', 'testing-patterns'];
183
217
 
184
218
  if (config.frontend?.framework === 'nextjs') {
@@ -227,6 +261,10 @@ function generateAgents(outputDir, config, vars) {
227
261
  'loop-operator.md',
228
262
  'harness-optimizer.md',
229
263
  'product-strategist.md',
264
+ 'prompt-auditor.md',
265
+ 'frontend-builder.md',
266
+ 'enforcement-gate.md',
267
+ 'deep-reviewer.md',
230
268
  ];
231
269
 
232
270
  for (const agent of agents) {
@@ -234,9 +272,14 @@ function generateAgents(outputDir, config, vars) {
234
272
  if (fs.existsSync(srcPath)) {
235
273
  let content = readTemplate(srcPath);
236
274
  content = replaceVars(content, vars);
275
+ content = stampManaged(content);
237
276
  writeFile(path.join(outputDir, '.claude', 'agents', agent), content);
238
277
  }
239
278
  }
279
+
280
+ // Clean up orphaned agents from older versions
281
+ const removed = cleanOrphans(path.join(outputDir, '.claude', 'agents'), agents);
282
+ return { count: agents.length, removed };
240
283
  }
241
284
 
242
285
  function generateCommands(outputDir, config, vars) {
@@ -245,7 +288,6 @@ function generateCommands(outputDir, config, vars) {
245
288
  'workflows.md',
246
289
  'status.md',
247
290
  'next.md',
248
- 'done.md',
249
291
  'verify-all.md',
250
292
  'audit-spec.md',
251
293
  'audit-wiring.md',
@@ -257,11 +299,19 @@ function generateCommands(outputDir, config, vars) {
257
299
  'optimize-claude-md.md',
258
300
  'plan.md',
259
301
  'build-fix.md',
302
+ 'fix-loop.md',
260
303
  'code-review.md',
261
304
  'tdd.md',
262
305
  'save-session.md',
263
306
  'resume-session.md',
264
307
  'full-audit.md',
308
+ 'verify-intent.md',
309
+ 'build-ui.md',
310
+ 'help.md',
311
+ 'live-uat.md',
312
+ 'simplify.md',
313
+ 'generate-sdd.md',
314
+ 'product-strategist.md',
265
315
  ];
266
316
 
267
317
  for (const cmd of commands) {
@@ -269,9 +319,52 @@ function generateCommands(outputDir, config, vars) {
269
319
  if (fs.existsSync(srcPath)) {
270
320
  let content = readTemplate(srcPath);
271
321
  content = replaceVars(content, vars);
322
+ content = stampManaged(content);
272
323
  writeFile(path.join(outputDir, '.claude', 'commands', cmd), content);
273
324
  }
274
325
  }
326
+
327
+ // Clean up orphaned commands from older versions
328
+ const removed = cleanOrphans(path.join(outputDir, '.claude', 'commands'), commands);
329
+ return { count: commands.length, removed };
330
+ }
331
+
332
+ const MANAGED_MARKER = '<!-- Generated by DevForge -->';
333
+
334
+ /**
335
+ * Append the DevForge managed marker to generated file content.
336
+ */
337
+ function stampManaged(content) {
338
+ return content.trimEnd() + '\n\n' + MANAGED_MARKER + '\n';
339
+ }
340
+
341
+ /**
342
+ * Remove DevForge-managed .md files that are no longer in the current manifest.
343
+ * Only deletes files stamped with the DevForge marker. User-created custom
344
+ * files are left untouched. Returns array of removed filenames.
345
+ */
346
+ function cleanOrphans(dir, expectedFiles) {
347
+ const removed = [];
348
+ if (!fs.existsSync(dir)) return removed;
349
+
350
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
351
+ const existing = entries
352
+ .filter(e => e.isFile() && !e.isSymbolicLink() && e.name.endsWith('.md'))
353
+ .map(e => e.name);
354
+ const expectedSet = new Set(expectedFiles);
355
+ for (const file of existing) {
356
+ if (!expectedSet.has(file)) {
357
+ const filePath = path.join(dir, file);
358
+ const stat = fs.statSync(filePath);
359
+ if (stat.size > 1_000_000) continue; // skip unexpectedly large files
360
+ const content = fs.readFileSync(filePath, 'utf-8');
361
+ if (content.includes(MANAGED_MARKER)) {
362
+ fs.unlinkSync(filePath);
363
+ removed.push(file);
364
+ }
365
+ }
366
+ }
367
+ return removed;
275
368
  }
276
369
 
277
370
  function copyPromptLibrary(outputDir) {
package/src/cli.js CHANGED
@@ -5,7 +5,13 @@ import { log } from './utils.js';
5
5
 
6
6
  export async function parseCommand(args) {
7
7
  if (args.includes('--version') || args.includes('-v')) {
8
- const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
8
+ let pkg;
9
+ try {
10
+ pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
11
+ } catch (err) {
12
+ console.error(`Could not read package.json: ${err.message}`);
13
+ process.exit(1);
14
+ }
9
15
  console.log(pkg.version);
10
16
  process.exit(0);
11
17
  }
@@ -18,8 +24,10 @@ export async function parseCommand(args) {
18
24
  const command = args[0];
19
25
 
20
26
  if (!command) {
21
- showUsage();
22
- process.exit(0);
27
+ const { showInteractiveMenu, handleMenuSelection } = await import('./menu.js');
28
+ const selected = await showInteractiveMenu();
29
+ await handleMenuSelection(selected);
30
+ return;
23
31
  }
24
32
 
25
33
  if (command === 'new') {
@@ -46,6 +54,12 @@ export async function parseCommand(args) {
46
54
  return;
47
55
  }
48
56
 
57
+ if (command === 'ci') {
58
+ const { runCI } = await import('./ci-mode.js');
59
+ await runCI(process.cwd());
60
+ return;
61
+ }
62
+
49
63
  if (command === 'update') {
50
64
  const { runUpdate } = await import('./update.js');
51
65
  await runUpdate();
@@ -73,12 +87,13 @@ export async function parseCommand(args) {
73
87
 
74
88
  function showUsage() {
75
89
  console.log(`
76
- ${chalk.bold.cyan('DevForge')}AI-first project scaffolding
90
+ ${chalk.bold.cyan('DevForge')} AI-first project scaffolding
77
91
 
78
92
  ${chalk.bold('Usage:')}
79
93
  devforge new <name> Create a new project
80
94
  devforge init Add dev guardrails to current project
81
95
  devforge doctor Diagnose and optimize current project
96
+ devforge ci Run health checks for CI/CD (non-interactive)
82
97
  devforge update Check for newer version
83
98
  devforge <name> Shorthand for ${chalk.dim('devforge new <name>')}
84
99
 
@@ -92,14 +107,14 @@ function showUsage() {
92
107
 
93
108
  function showHelp() {
94
109
  console.log(`
95
- ${chalk.bold.cyan('DevForge')}Universal, AI-first project scaffolding
110
+ ${chalk.bold.cyan('DevForge')} Universal, AI-first project scaffolding
96
111
 
97
112
  ${chalk.bold('Commands:')}
98
113
 
99
114
  ${chalk.bold('devforge new <name>')}
100
115
  Create a new project. Choose between:
101
- ${chalk.dim('• Guided mode describe what you want in plain English')}
102
- ${chalk.dim('• Developer mode pick your stack directly')}
116
+ ${chalk.dim('• Guided mode: describe what you want in plain English')}
117
+ ${chalk.dim('• Developer mode: pick your stack directly')}
103
118
 
104
119
  ${chalk.bold('devforge init')}
105
120
  Add Claude Code infrastructure to an existing project.
@@ -112,6 +127,11 @@ function showHelp() {
112
127
  flaky tests, dead code, duplicate code, and more.
113
128
  Generates Claude Code prompts to fix each issue.
114
129
 
130
+ ${chalk.bold('devforge ci')}
131
+ Run project health checks non-interactively for CI/CD.
132
+ Exits with code 1 if critical issues found.
133
+ Saves report to docs/ci-report.md if docs/ exists.
134
+
115
135
  ${chalk.bold('devforge update')}
116
136
  Check if a newer version of DevForge is available.
117
137
  Shows upgrade instructions if an update exists.
@@ -120,6 +140,9 @@ function showHelp() {
120
140
  - Next.js full-stack (TypeScript + Prisma + PostgreSQL)
121
141
  - FastAPI backend (Python + SQLAlchemy + PostgreSQL)
122
142
  - Polyglot full-stack (Next.js + FastAPI monorepo)
143
+ - React + Express (Vite + Express + Prisma + PostgreSQL)
144
+ - Remix full-stack (Vite + Tailwind + Prisma + PostgreSQL)
145
+ - Hono API (TypeScript + Prisma + PostgreSQL)
123
146
 
124
147
  ${chalk.bold('Examples:')}
125
148
  devforge new my-app