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,189 +1,204 @@
1
- import { writeFile, ensureDir } from './utils.js';
2
- import path from 'node:path';
3
-
4
- export async function generateUAT(outputDir, stackConfig) {
5
- const scenarios = buildScenarios(stackConfig);
6
- generateUATTemplate(outputDir, stackConfig, scenarios);
7
- generateUATChecklist(outputDir, scenarios);
8
- }
9
-
10
- function buildScenarios(config) {
11
- const scenarios = [];
12
- let id = 1;
13
-
14
- // Health check — every project gets this
15
- scenarios.push({
16
- id: `UAT-${String(id++).padStart(3, '0')}`,
17
- feature: 'Health Check',
18
- priority: 'P0',
19
- preconditions: 'Application is running',
20
- steps: [
21
- 'Send GET request to the health endpoint',
22
- 'Verify response status is 200',
23
- 'Verify response body contains status: "ok"',
24
- ],
25
- expected: 'Health endpoint responds with 200 and status "ok"',
26
- });
27
-
28
- // Database connectivity
29
- if (config.database) {
30
- scenarios.push({
31
- id: `UAT-${String(id++).padStart(3, '0')}`,
32
- feature: 'Database Connectivity',
33
- priority: 'P0',
34
- preconditions: 'Application and database are running',
35
- steps: [
36
- 'Send GET request to deep health endpoint (/healthz)',
37
- 'Verify response includes database status',
38
- 'Verify database status is "connected"',
39
- ],
40
- expected: 'Deep health check confirms database connectivity',
41
- });
42
- }
43
-
44
- // Homepage (frontend projects)
45
- if (config.frontend) {
46
- scenarios.push({
47
- id: `UAT-${String(id++).padStart(3, '0')}`,
48
- feature: 'Home Page Load',
49
- priority: 'P0',
50
- preconditions: 'Application is running',
51
- steps: [
52
- 'Navigate to the application root URL',
53
- 'Verify the page loads without errors',
54
- 'Verify the page title is correct',
55
- ],
56
- expected: 'Home page loads successfully with correct title',
57
- });
58
- }
59
-
60
- // Authentication
61
- if (config.auth) {
62
- scenarios.push({
63
- id: `UAT-${String(id++).padStart(3, '0')}`,
64
- feature: 'User Registration',
65
- priority: 'P0',
66
- preconditions: 'Application is running, no existing test user',
67
- steps: [
68
- 'Navigate to registration page',
69
- 'Fill in valid email, password, and name',
70
- 'Submit the registration form',
71
- 'Verify account is created successfully',
72
- ],
73
- expected: 'User account is created and user is authenticated',
74
- });
75
-
76
- scenarios.push({
77
- id: `UAT-${String(id++).padStart(3, '0')}`,
78
- feature: 'User Login',
79
- priority: 'P0',
80
- preconditions: 'Test user account exists',
81
- steps: [
82
- 'Navigate to login page',
83
- 'Enter valid credentials',
84
- 'Submit the login form',
85
- 'Verify user is redirected to dashboard/home',
86
- ],
87
- expected: 'User is authenticated and redirected appropriately',
88
- });
89
-
90
- scenarios.push({
91
- id: `UAT-${String(id++).padStart(3, '0')}`,
92
- feature: 'Invalid Login',
93
- priority: 'P1',
94
- preconditions: 'Application is running',
95
- steps: [
96
- 'Navigate to login page',
97
- 'Enter invalid credentials',
98
- 'Submit the login form',
99
- 'Verify error message is displayed',
100
- ],
101
- expected: 'User sees a generic error message, no sensitive info leaked',
102
- });
103
-
104
- if (config.frontend) {
105
- scenarios.push({
106
- id: `UAT-${String(id++).padStart(3, '0')}`,
107
- feature: 'Protected Route Access',
108
- priority: 'P1',
109
- preconditions: 'User is not authenticated',
110
- steps: [
111
- 'Navigate to a protected route (e.g., /dashboard)',
112
- 'Verify redirect to login page',
113
- 'Log in with valid credentials',
114
- 'Verify redirect back to protected route',
115
- ],
116
- expected: 'Unauthenticated users are redirected to login, then back after auth',
117
- });
118
- }
119
- }
120
-
121
- // Error handling
122
- scenarios.push({
123
- id: `UAT-${String(id++).padStart(3, '0')}`,
124
- feature: 'Structured Error Response',
125
- priority: 'P1',
126
- preconditions: 'Application is running',
127
- steps: [
128
- 'Send a request to a non-existent endpoint',
129
- 'Verify response has structured error format',
130
- 'Verify no stack traces or internal details are leaked',
131
- ],
132
- expected: 'Error response follows format: { error: { code, message } }',
133
- });
134
-
135
- // Graceful shutdown
136
- scenarios.push({
137
- id: `UAT-${String(id++).padStart(3, '0')}`,
138
- feature: 'Graceful Shutdown',
139
- priority: 'P1',
140
- preconditions: 'Application is running with active connections',
141
- steps: [
142
- 'Send SIGTERM to the application process',
143
- 'Verify in-flight requests complete',
144
- 'Verify database connections are closed',
145
- 'Verify process exits with code 0',
146
- ],
147
- expected: 'Application shuts down gracefully without dropping requests',
148
- });
149
-
150
- return scenarios;
151
- }
152
-
153
- function generateUATTemplate(outputDir, config, scenarios) {
154
- let content = `# UAT Scenario Pack: ${config.projectName}\n\n`;
155
- content += `## Pre-Conditions\n`;
156
- content += `- [ ] Application is deployed to staging\n`;
157
- content += `- [ ] Test accounts are created\n`;
158
- content += `- [ ] Test data is seeded\n`;
159
- if (config.database) {
160
- content += `- [ ] Database is running and migrated\n`;
161
- }
162
- content += `\n## Scenarios\n`;
163
-
164
- for (const s of scenarios) {
165
- content += `\n### ${s.id}: ${s.feature}\n`;
166
- content += `**Priority:** ${s.priority}\n`;
167
- content += `**Preconditions:** ${s.preconditions}\n`;
168
- content += `**Steps:**\n`;
169
- s.steps.forEach((step, i) => {
170
- content += `${i + 1}. ${step}\n`;
171
- });
172
- content += `**Expected Result:** ${s.expected}\n`;
173
- content += `**Actual Result:** ___\n`;
174
- content += `**Status:** NOT RUN\n`;
175
- content += `**Tester:** ___\n`;
176
- content += `**Date:** ___\n`;
177
- content += `**Notes:** ___\n`;
178
- }
179
-
180
- writeFile(path.join(outputDir, 'docs', 'uat', 'UAT_TEMPLATE.md'), content);
181
- }
182
-
183
- function generateUATChecklist(outputDir, scenarios) {
184
- let csv = 'UAT_ID,Feature,Priority,Status,Tester,Date,Defect_ID,Notes\n';
185
- for (const s of scenarios) {
186
- csv += `${s.id},${s.feature},${s.priority},NOT RUN,,,,\n`;
187
- }
188
- writeFile(path.join(outputDir, 'docs', 'uat', 'UAT_CHECKLIST.csv'), csv);
189
- }
1
+ import { writeFile } from './utils.js';
2
+ import path from 'node:path';
3
+
4
+ export async function generateUAT(outputDir, stackConfig) {
5
+ const scenarios = buildScenarios(stackConfig);
6
+ generateUATTemplate(outputDir, stackConfig, scenarios);
7
+ generateUATChecklist(outputDir, scenarios);
8
+ generateBusinessRulesPlaceholder(outputDir, stackConfig);
9
+ }
10
+
11
+ function buildScenarios(config) {
12
+ const scenarios = [];
13
+ let id = 1;
14
+
15
+ // Health check: every project gets this
16
+ scenarios.push({
17
+ id: `UAT-${String(id++).padStart(3, '0')}`,
18
+ feature: 'Health Check',
19
+ priority: 'P0',
20
+ preconditions: 'Application is running',
21
+ steps: [
22
+ 'Send GET request to the health endpoint',
23
+ 'Verify response status is 200',
24
+ 'Verify response body contains status: "ok"',
25
+ ],
26
+ expected: 'Health endpoint responds with 200 and status "ok"',
27
+ });
28
+
29
+ // Database connectivity
30
+ if (config.database) {
31
+ scenarios.push({
32
+ id: `UAT-${String(id++).padStart(3, '0')}`,
33
+ feature: 'Database Connectivity',
34
+ priority: 'P0',
35
+ preconditions: 'Application and database are running',
36
+ steps: [
37
+ 'Send GET request to deep health endpoint (/healthz)',
38
+ 'Verify response includes database status',
39
+ 'Verify database status is "connected"',
40
+ ],
41
+ expected: 'Deep health check confirms database connectivity',
42
+ });
43
+ }
44
+
45
+ // Homepage (frontend projects)
46
+ if (config.frontend) {
47
+ scenarios.push({
48
+ id: `UAT-${String(id++).padStart(3, '0')}`,
49
+ feature: 'Home Page Load',
50
+ priority: 'P0',
51
+ preconditions: 'Application is running',
52
+ steps: [
53
+ 'Navigate to the application root URL',
54
+ 'Verify the page loads without errors',
55
+ 'Verify the page title is correct',
56
+ ],
57
+ expected: 'Home page loads successfully with correct title',
58
+ });
59
+ }
60
+
61
+ // Authentication
62
+ if (config.auth) {
63
+ scenarios.push({
64
+ id: `UAT-${String(id++).padStart(3, '0')}`,
65
+ feature: 'User Registration',
66
+ priority: 'P0',
67
+ preconditions: 'Application is running, no existing test user',
68
+ steps: [
69
+ 'Navigate to registration page',
70
+ 'Fill in valid email, password, and name',
71
+ 'Submit the registration form',
72
+ 'Verify account is created successfully',
73
+ ],
74
+ expected: 'User account is created and user is authenticated',
75
+ });
76
+
77
+ scenarios.push({
78
+ id: `UAT-${String(id++).padStart(3, '0')}`,
79
+ feature: 'User Login',
80
+ priority: 'P0',
81
+ preconditions: 'Test user account exists',
82
+ steps: [
83
+ 'Navigate to login page',
84
+ 'Enter valid credentials',
85
+ 'Submit the login form',
86
+ 'Verify user is redirected to dashboard/home',
87
+ ],
88
+ expected: 'User is authenticated and redirected appropriately',
89
+ });
90
+
91
+ scenarios.push({
92
+ id: `UAT-${String(id++).padStart(3, '0')}`,
93
+ feature: 'Invalid Login',
94
+ priority: 'P1',
95
+ preconditions: 'Application is running',
96
+ steps: [
97
+ 'Navigate to login page',
98
+ 'Enter invalid credentials',
99
+ 'Submit the login form',
100
+ 'Verify error message is displayed',
101
+ ],
102
+ expected: 'User sees a generic error message, no sensitive info leaked',
103
+ });
104
+
105
+ if (config.frontend) {
106
+ scenarios.push({
107
+ id: `UAT-${String(id++).padStart(3, '0')}`,
108
+ feature: 'Protected Route Access',
109
+ priority: 'P1',
110
+ preconditions: 'User is not authenticated',
111
+ steps: [
112
+ 'Navigate to a protected route (e.g., /dashboard)',
113
+ 'Verify redirect to login page',
114
+ 'Log in with valid credentials',
115
+ 'Verify redirect back to protected route',
116
+ ],
117
+ expected: 'Unauthenticated users are redirected to login, then back after auth',
118
+ });
119
+ }
120
+ }
121
+
122
+ // Error handling
123
+ scenarios.push({
124
+ id: `UAT-${String(id++).padStart(3, '0')}`,
125
+ feature: 'Structured Error Response',
126
+ priority: 'P1',
127
+ preconditions: 'Application is running',
128
+ steps: [
129
+ 'Send a request to a non-existent endpoint',
130
+ 'Verify response has structured error format',
131
+ 'Verify no stack traces or internal details are leaked',
132
+ ],
133
+ expected: 'Error response follows format: { error: { code, message } }',
134
+ });
135
+
136
+ // Graceful shutdown
137
+ scenarios.push({
138
+ id: `UAT-${String(id).padStart(3, '0')}`,
139
+ feature: 'Graceful Shutdown',
140
+ priority: 'P1',
141
+ preconditions: 'Application is running with active connections',
142
+ steps: [
143
+ 'Send SIGTERM to the application process',
144
+ 'Verify in-flight requests complete',
145
+ 'Verify database connections are closed',
146
+ 'Verify process exits with code 0',
147
+ ],
148
+ expected: 'Application shuts down gracefully without dropping requests',
149
+ });
150
+
151
+ return scenarios;
152
+ }
153
+
154
+ function generateUATTemplate(outputDir, config, scenarios) {
155
+ let content = `# UAT Scenario Pack: ${config.projectName}\n\n`;
156
+ content += `## Pre-Conditions\n`;
157
+ content += `- [ ] Application is deployed to staging\n`;
158
+ content += `- [ ] Test accounts are created\n`;
159
+ content += `- [ ] Test data is seeded\n`;
160
+ if (config.database) {
161
+ content += `- [ ] Database is running and migrated\n`;
162
+ }
163
+ content += `\n## Scenarios\n`;
164
+
165
+ for (const s of scenarios) {
166
+ content += `\n### ${s.id}: ${s.feature}\n`;
167
+ content += `**Priority:** ${s.priority}\n`;
168
+ content += `**Preconditions:** ${s.preconditions}\n`;
169
+ content += `**Steps:**\n`;
170
+ s.steps.forEach((step, i) => {
171
+ content += `${i + 1}. ${step}\n`;
172
+ });
173
+ content += `**Expected Result:** ${s.expected}\n`;
174
+ content += `**Actual Result:** ___\n`;
175
+ content += `**Status:** NOT RUN\n`;
176
+ content += `**Tester:** ___\n`;
177
+ content += `**Date:** ___\n`;
178
+ content += `**Notes:** ___\n`;
179
+ }
180
+
181
+ writeFile(path.join(outputDir, 'docs', 'uat', 'UAT_TEMPLATE.md'), content);
182
+ }
183
+
184
+ function generateUATChecklist(outputDir, scenarios) {
185
+ let csv = 'UAT_ID,Feature,Priority,Status,Tester,Date,Defect_ID,Notes\n';
186
+ for (const s of scenarios) {
187
+ csv += `${s.id},${s.feature},${s.priority},NOT RUN,,,,\n`;
188
+ }
189
+ writeFile(path.join(outputDir, 'docs', 'uat', 'UAT_CHECKLIST.csv'), csv);
190
+ }
191
+
192
+ function generateBusinessRulesPlaceholder(outputDir, config) {
193
+ let content = `# Business Rules: ${config.projectName}\n\n`;
194
+ content += `Run \`/generate-uat\` inside Claude Code to populate this file with extracted business rules from your codebase.\n\n`;
195
+ content += `## How It Works\n`;
196
+ content += `The /generate-uat command reads your source code, extracts conditional logic and business rules,\n`;
197
+ content += `and generates testable assertions with boundary values.\n\n`;
198
+ content += `## Format\n`;
199
+ content += `Each rule will include:\n`;
200
+ content += `- **Source**: file path and line number\n`;
201
+ content += `- **Logic**: what the rule does\n`;
202
+ content += `- **Test cases**: input/output pairs with boundary values\n`;
203
+ writeFile(path.join(outputDir, 'docs', 'uat', 'BUSINESS_RULES.md'), content);
204
+ }
@@ -21,9 +21,14 @@ export function compareVersions(a, b) {
21
21
  * Returns { current, latest, updateAvailable } or null on failure.
22
22
  */
23
23
  export async function checkForUpdate() {
24
- const pkg = JSON.parse(
25
- fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
26
- );
24
+ let pkg;
25
+ try {
26
+ pkg = JSON.parse(
27
+ fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
28
+ );
29
+ } catch {
30
+ return null;
31
+ }
27
32
  const currentVersion = pkg.version;
28
33
 
29
34
  try {
@@ -43,7 +48,7 @@ export async function checkForUpdate() {
43
48
  latest: latestVersion,
44
49
  updateAvailable: compareVersions(latestVersion, currentVersion) > 0,
45
50
  };
46
- } catch {
51
+ } catch { // Network or parse failure, skip update check silently
47
52
  return null;
48
53
  }
49
54
  }
package/src/update.js CHANGED
@@ -1,10 +1,44 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
1
3
  import chalk from 'chalk';
2
- import { log } from './utils.js';
3
- import { checkForUpdate } from './update-check.js';
4
+ import { log, ROOT_DIR } from './utils.js';
5
+ import { checkForUpdate, compareVersions } from './update-check.js';
6
+
7
+ /**
8
+ * Check if the current directory has stale DevForge infrastructure.
9
+ * Returns { stale, installedVersion, cliVersion } or null if no infrastructure found.
10
+ */
11
+ function checkInfrastructure(projectDir) {
12
+ const versionFile = path.join(projectDir, '.claude', '.devforge-version');
13
+ if (!fs.existsSync(versionFile)) {
14
+ return null;
15
+ }
16
+
17
+ let pkg;
18
+ try {
19
+ pkg = JSON.parse(fs.readFileSync(path.join(ROOT_DIR, 'package.json'), 'utf-8'));
20
+ } catch {
21
+ return null;
22
+ }
23
+
24
+ try {
25
+ const installed = JSON.parse(fs.readFileSync(versionFile, 'utf-8'));
26
+ if (typeof installed.version !== 'string') return null;
27
+ const stale = compareVersions(pkg.version, installed.version) > 0;
28
+ return {
29
+ stale,
30
+ installedVersion: installed.version,
31
+ cliVersion: pkg.version,
32
+ };
33
+ } catch {
34
+ // Corrupted version file — treat as stale
35
+ return { stale: true, installedVersion: 'unknown', cliVersion: pkg.version };
36
+ }
37
+ }
4
38
 
5
39
  export async function runUpdate() {
6
40
  console.log('');
7
- console.log(chalk.bold.cyan(' DevForge') + chalk.dim('Checking for updates...'));
41
+ console.log(chalk.bold.cyan(' DevForge') + chalk.dim(' Checking for updates...'));
8
42
  console.log('');
9
43
 
10
44
  const result = await checkForUpdate();
@@ -18,16 +52,26 @@ export async function runUpdate() {
18
52
  if (!result.updateAvailable) {
19
53
  log.success(` ✓ You're on the latest version (${result.current})`);
20
54
  console.log('');
21
- return;
55
+ } else {
56
+ log.warn(` Update available: ${result.current} → ${result.latest}`);
57
+ console.log('');
58
+ console.log(' To update:');
59
+ console.log(` ${chalk.bold('npm install -g forgedev@latest')} ${chalk.dim('(if installed globally)')}`);
60
+ console.log(` ${chalk.bold('npx forgedev@latest new my-app')} ${chalk.dim('(one-time use)')}`);
61
+ console.log('');
22
62
  }
23
63
 
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('');
64
+ // Check if current directory has stale DevForge infrastructure
65
+ const infra = checkInfrastructure(process.cwd());
66
+ if (infra && infra.stale) {
67
+ console.log(chalk.yellow(' ') + chalk.bold('Project infrastructure is outdated'));
68
+ console.log(chalk.dim(` Installed: v${infra.installedVersion} → CLI: v${infra.cliVersion}`));
69
+ console.log('');
70
+ console.log(' New commands, agents, and hooks are available but not deployed here.');
71
+ console.log(` Run ${chalk.bold.cyan('npx forgedev init')} to sync this project's .claude/ infrastructure.`);
72
+ console.log('');
73
+ } else if (infra && !infra.stale) {
74
+ log.success(` ✓ Project infrastructure is up to date (v${infra.installedVersion})`);
75
+ console.log('');
76
+ }
33
77
  }