@specverse/engines 4.1.25 → 4.1.26

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.
@@ -54,9 +54,9 @@ function generateBackendPackageJson(context) {
54
54
  "prisma": "^5.7.0",
55
55
  "vitest": "^3.0.0",
56
56
  "@vitest/coverage-v8": "^3.0.0",
57
- "eslint": "^8.55.0",
58
- "@typescript-eslint/eslint-plugin": "^6.15.0",
59
- "@typescript-eslint/parser": "^6.15.0"
57
+ "eslint": "^9.0.0",
58
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
59
+ "@typescript-eslint/parser": "^8.0.0"
60
60
  },
61
61
  engines: {
62
62
  node: ">=20.0.0"
@@ -99,6 +99,9 @@ ${serviceMap}
99
99
  credentials: true
100
100
  });
101
101
 
102
+ // Health check \u2014 used by smoke tests, container probes, monitors
103
+ app.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
104
+
102
105
  // Spec endpoint \u2014 serves the specification for the runtime frontend
103
106
  app.get('/api/spec', async () => spec);
104
107
 
@@ -35,10 +35,10 @@ function generatePackageJson(context) {
35
35
  "tailwindcss": "^3.4.13",
36
36
  "typescript": "^5.2.0",
37
37
  "vite": "^6.0.0",
38
- "eslint": "^8.53.0",
39
- "@typescript-eslint/eslint-plugin": "^6.10.0",
40
- "@typescript-eslint/parser": "^6.10.0",
41
- "eslint-plugin-react-hooks": "^4.6.0",
38
+ "eslint": "^9.0.0",
39
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
40
+ "@typescript-eslint/parser": "^8.0.0",
41
+ "eslint-plugin-react-hooks": "^5.0.0",
42
42
  "eslint-plugin-react-refresh": "^0.4.4"
43
43
  }
44
44
  };
@@ -37,10 +37,10 @@ function generateRuntimePackageJson(context) {
37
37
  "tailwindcss": "^3.4.13",
38
38
  "typescript": "^5.2.0",
39
39
  "vite": "^6.0.0",
40
- "eslint": "^8.53.0",
41
- "@typescript-eslint/eslint-plugin": "^6.10.0",
42
- "@typescript-eslint/parser": "^6.10.0",
43
- "eslint-plugin-react-hooks": "^4.6.0",
40
+ "eslint": "^9.0.0",
41
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
42
+ "@typescript-eslint/parser": "^8.0.0",
43
+ "eslint-plugin-react-hooks": "^5.0.0",
44
44
  "eslint-plugin-react-refresh": "^0.4.4"
45
45
  }
46
46
  };
@@ -424,7 +424,10 @@ import { fileURLToPath } from 'url';`,
424
424
  }
425
425
 
426
426
  const projectName = name || 'my-project';
427
- const templateName = options.template || 'default';
427
+ // Commander applies the --template default ("full-stack"); the
428
+ // fallback here only fires if a caller invoked the action handler
429
+ // directly without going through commander.
430
+ const templateName = options.template || 'full-stack';
428
431
  const templateDir = join(templatesDir, templateName);
429
432
 
430
433
  if (!existsSync(templateDir)) {
@@ -443,7 +446,13 @@ import { fileURLToPath } from 'url';`,
443
446
 
444
447
  // Copy template with variable substitution
445
448
  const kebab = projectName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
446
- const component = projectName.charAt(0).toUpperCase() + projectName.slice(1);
449
+ // PascalCase: split on hyphens / underscores / spaces, capitalize each segment, join.
450
+ // 'audit-backend-only' -> 'AuditBackendOnly', 'my_app' -> 'MyApp', 'foo' -> 'Foo'.
451
+ const component = projectName
452
+ .split(/[-_s]+/)
453
+ .filter(Boolean)
454
+ .map((s: string) => s.charAt(0).toUpperCase() + s.slice(1))
455
+ .join('');
447
456
  const vars: Record<string, string> = {
448
457
  '{{PROJECT_NAME}}': projectName,
449
458
  '{{projectName}}': projectName,
@@ -478,11 +487,29 @@ import { fileURLToPath } from 'url';`,
478
487
  console.log('Project created: ' + destDir);
479
488
  console.log('Template: ' + templateName);
480
489
  console.log('');
490
+
491
+ // Build the "Next steps" hint from the actual scripts the
492
+ // chosen template ships, so we never tell the user to run a
493
+ // command that doesn't exist in their package.json.
494
+ const destPkgPath = join(destDir, 'package.json');
495
+ const destPkg = existsSync(destPkgPath)
496
+ ? JSON.parse(readFileSync(destPkgPath, 'utf8'))
497
+ : { scripts: {} };
498
+ const scripts = destPkg.scripts || {};
481
499
  console.log('Next steps:');
482
500
  console.log(' cd ' + projectName);
483
- console.log(' npm run setup # validate, generate code, install deps, setup db');
484
- console.log(' npm run dev:backend # start backend (terminal 1)');
485
- console.log(' npm run dev:frontend # start frontend (terminal 2)');`
501
+ if (scripts.setup) {
502
+ console.log(' npm run setup # validate, generate code, install deps, setup db');
503
+ }
504
+ if (scripts['dev:backend'] && scripts['dev:frontend']) {
505
+ console.log(' npm run dev:backend # start backend (terminal 1)');
506
+ console.log(' npm run dev:frontend # start frontend (terminal 2)');
507
+ } else if (scripts.dev) {
508
+ console.log(' npm run dev # start dev server');
509
+ }
510
+ if (scripts['test:e2e']) {
511
+ console.log(' npm run test:e2e # run end-to-end tests (after starting dev servers)');
512
+ }`
486
513
  },
487
514
  // === gen subcommands ===
488
515
  "gen.diagrams": {
@@ -73,9 +73,9 @@ export default function generateBackendPackageJson(context: TemplateContext): st
73
73
  'prisma': '^5.7.0',
74
74
  'vitest': '^3.0.0',
75
75
  '@vitest/coverage-v8': '^3.0.0',
76
- 'eslint': '^8.55.0',
77
- '@typescript-eslint/eslint-plugin': '^6.15.0',
78
- '@typescript-eslint/parser': '^6.15.0'
76
+ 'eslint': '^9.0.0',
77
+ '@typescript-eslint/eslint-plugin': '^8.0.0',
78
+ '@typescript-eslint/parser': '^8.0.0'
79
79
  },
80
80
 
81
81
  engines: {
@@ -132,6 +132,9 @@ ${serviceMap}
132
132
  credentials: true
133
133
  });
134
134
 
135
+ // Health check — used by smoke tests, container probes, monitors
136
+ app.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
137
+
135
138
  // Spec endpoint — serves the specification for the runtime frontend
136
139
  app.get('/api/spec', async () => spec);
137
140
 
@@ -45,10 +45,10 @@ export default function generatePackageJson(context: TemplateContext): string {
45
45
  "tailwindcss": "^3.4.13",
46
46
  "typescript": "^5.2.0",
47
47
  "vite": "^6.0.0",
48
- "eslint": "^8.53.0",
49
- "@typescript-eslint/eslint-plugin": "^6.10.0",
50
- "@typescript-eslint/parser": "^6.10.0",
51
- "eslint-plugin-react-hooks": "^4.6.0",
48
+ "eslint": "^9.0.0",
49
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
50
+ "@typescript-eslint/parser": "^8.0.0",
51
+ "eslint-plugin-react-hooks": "^5.0.0",
52
52
  "eslint-plugin-react-refresh": "^0.4.4"
53
53
  }
54
54
  };
@@ -54,10 +54,10 @@ export default function generateRuntimePackageJson(context: TemplateContext): st
54
54
  "tailwindcss": "^3.4.13",
55
55
  "typescript": "^5.2.0",
56
56
  "vite": "^6.0.0",
57
- "eslint": "^8.53.0",
58
- "@typescript-eslint/eslint-plugin": "^6.10.0",
59
- "@typescript-eslint/parser": "^6.10.0",
60
- "eslint-plugin-react-hooks": "^4.6.0",
57
+ "eslint": "^9.0.0",
58
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
59
+ "@typescript-eslint/parser": "^8.0.0",
60
+ "eslint-plugin-react-hooks": "^5.0.0",
61
61
  "eslint-plugin-react-refresh": "^0.4.4"
62
62
  }
63
63
  };
@@ -479,7 +479,10 @@ import { fileURLToPath } from 'url';`,
479
479
  }
480
480
 
481
481
  const projectName = name || 'my-project';
482
- const templateName = options.template || 'default';
482
+ // Commander applies the --template default ("full-stack"); the
483
+ // fallback here only fires if a caller invoked the action handler
484
+ // directly without going through commander.
485
+ const templateName = options.template || 'full-stack';
483
486
  const templateDir = join(templatesDir, templateName);
484
487
 
485
488
  if (!existsSync(templateDir)) {
@@ -498,7 +501,13 @@ import { fileURLToPath } from 'url';`,
498
501
 
499
502
  // Copy template with variable substitution
500
503
  const kebab = projectName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
501
- const component = projectName.charAt(0).toUpperCase() + projectName.slice(1);
504
+ // PascalCase: split on hyphens / underscores / spaces, capitalize each segment, join.
505
+ // 'audit-backend-only' -> 'AuditBackendOnly', 'my_app' -> 'MyApp', 'foo' -> 'Foo'.
506
+ const component = projectName
507
+ .split(/[-_\s]+/)
508
+ .filter(Boolean)
509
+ .map((s: string) => s.charAt(0).toUpperCase() + s.slice(1))
510
+ .join('');
502
511
  const vars: Record<string, string> = {
503
512
  '{{PROJECT_NAME}}': projectName,
504
513
  '{{projectName}}': projectName,
@@ -533,11 +542,29 @@ import { fileURLToPath } from 'url';`,
533
542
  console.log('Project created: ' + destDir);
534
543
  console.log('Template: ' + templateName);
535
544
  console.log('');
545
+
546
+ // Build the "Next steps" hint from the actual scripts the
547
+ // chosen template ships, so we never tell the user to run a
548
+ // command that doesn't exist in their package.json.
549
+ const destPkgPath = join(destDir, 'package.json');
550
+ const destPkg = existsSync(destPkgPath)
551
+ ? JSON.parse(readFileSync(destPkgPath, 'utf8'))
552
+ : { scripts: {} };
553
+ const scripts = destPkg.scripts || {};
536
554
  console.log('Next steps:');
537
555
  console.log(' cd ' + projectName);
538
- console.log(' npm run setup # validate, generate code, install deps, setup db');
539
- console.log(' npm run dev:backend # start backend (terminal 1)');
540
- console.log(' npm run dev:frontend # start frontend (terminal 2)');`
556
+ if (scripts.setup) {
557
+ console.log(' npm run setup # validate, generate code, install deps, setup db');
558
+ }
559
+ if (scripts['dev:backend'] && scripts['dev:frontend']) {
560
+ console.log(' npm run dev:backend # start backend (terminal 1)');
561
+ console.log(' npm run dev:frontend # start frontend (terminal 2)');
562
+ } else if (scripts.dev) {
563
+ console.log(' npm run dev # start dev server');
564
+ }
565
+ if (scripts['test:e2e']) {
566
+ console.log(' npm run test:e2e # run end-to-end tests (after starting dev servers)');
567
+ }`
541
568
  },
542
569
  // === gen subcommands ===
543
570
  'gen.diagrams': {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@specverse/engines",
3
- "version": "4.1.25",
4
- "description": "SpecVerse toolchain parser, inference, realize, generators, AI, registry",
3
+ "version": "4.1.26",
4
+ "description": "SpecVerse toolchain \u2014 parser, inference, realize, generators, AI, registry",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -65,4 +65,4 @@
65
65
  "access": "public"
66
66
  },
67
67
  "license": "MIT"
68
- }
68
+ }