@atlashub/smartstack-cli 4.35.0 → 4.37.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 (49) hide show
  1. package/dist/index.js +54 -100
  2. package/dist/index.js.map +1 -1
  3. package/dist/mcp-entry.mjs +54 -11
  4. package/dist/mcp-entry.mjs.map +1 -1
  5. package/package.json +1 -1
  6. package/templates/agents/efcore/migration.md +43 -0
  7. package/templates/agents/efcore/rebase-snapshot.md +36 -0
  8. package/templates/agents/efcore/squash.md +36 -0
  9. package/templates/skills/apex/references/checks/seed-checks.sh +1 -1
  10. package/templates/skills/apex/references/core-seed-data.md +39 -21
  11. package/templates/skills/application/references/application-roles-template.md +14 -8
  12. package/templates/skills/application/references/provider-template.md +32 -20
  13. package/templates/skills/application/templates-frontend.md +294 -2
  14. package/templates/skills/application/templates-seed.md +23 -11
  15. package/templates/skills/audit-route/SKILL.md +107 -0
  16. package/templates/skills/audit-route/references/routing-pattern.md +129 -0
  17. package/templates/skills/audit-route/steps/step-00-init.md +128 -0
  18. package/templates/skills/audit-route/steps/step-01-inventory.md +157 -0
  19. package/templates/skills/audit-route/steps/step-02-conformity.md +193 -0
  20. package/templates/skills/audit-route/steps/step-03-report.md +201 -0
  21. package/templates/skills/dev-start/SKILL.md +12 -2
  22. package/templates/skills/efcore/SKILL.md +219 -67
  23. package/templates/agents/efcore/conflicts.md +0 -114
  24. package/templates/agents/efcore/db-deploy.md +0 -86
  25. package/templates/agents/efcore/db-reset.md +0 -98
  26. package/templates/agents/efcore/db-seed.md +0 -73
  27. package/templates/agents/efcore/db-status.md +0 -97
  28. package/templates/agents/efcore/scan.md +0 -124
  29. package/templates/skills/efcore/references/both-contexts.md +0 -32
  30. package/templates/skills/efcore/references/destructive-operations.md +0 -38
  31. package/templates/skills/efcore/steps/db/step-deploy.md +0 -217
  32. package/templates/skills/efcore/steps/db/step-reset.md +0 -186
  33. package/templates/skills/efcore/steps/db/step-seed.md +0 -166
  34. package/templates/skills/efcore/steps/db/step-status.md +0 -173
  35. package/templates/skills/efcore/steps/migration/step-00-init.md +0 -102
  36. package/templates/skills/efcore/steps/migration/step-01-check.md +0 -164
  37. package/templates/skills/efcore/steps/migration/step-02-create.md +0 -160
  38. package/templates/skills/efcore/steps/migration/step-03-validate.md +0 -168
  39. package/templates/skills/efcore/steps/rebase-snapshot/step-00-init.md +0 -173
  40. package/templates/skills/efcore/steps/rebase-snapshot/step-01-backup.md +0 -100
  41. package/templates/skills/efcore/steps/rebase-snapshot/step-02-fetch.md +0 -115
  42. package/templates/skills/efcore/steps/rebase-snapshot/step-03-create.md +0 -112
  43. package/templates/skills/efcore/steps/rebase-snapshot/step-04-validate.md +0 -157
  44. package/templates/skills/efcore/steps/shared/step-00-init.md +0 -131
  45. package/templates/skills/efcore/steps/squash/step-00-init.md +0 -141
  46. package/templates/skills/efcore/steps/squash/step-01-backup.md +0 -120
  47. package/templates/skills/efcore/steps/squash/step-02-fetch.md +0 -168
  48. package/templates/skills/efcore/steps/squash/step-03-create.md +0 -184
  49. package/templates/skills/efcore/steps/squash/step-04-validate.md +0 -174
@@ -28009,7 +28009,7 @@ async function validateFrontendRoutes(structure, _config, result) {
28009
28009
  const missingRoutes2 = [];
28010
28010
  for (const nav of seedNavRoutes2) {
28011
28011
  const segments = nav.route.split("/").filter(Boolean);
28012
- const componentKey = segments.join(".");
28012
+ const componentKey = segments.map((s) => s.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()).join(".");
28013
28013
  if (!registeredKeys.has(componentKey)) {
28014
28014
  missingRoutes2.push(nav);
28015
28015
  }
@@ -28039,15 +28039,24 @@ async function validateFrontendRoutes(structure, _config, result) {
28039
28039
  });
28040
28040
  return;
28041
28041
  }
28042
+ const hasDynamicRouter = appContent.includes("DynamicRouter") || appContent.includes("<DynamicRouter");
28043
+ if (hasDynamicRouter) {
28044
+ result.warnings.push({
28045
+ type: "warning",
28046
+ category: "frontend-routes",
28047
+ message: "App.tsx uses DynamicRouter but componentRegistry.generated.ts was not found. Run scaffold_routes to generate it."
28048
+ });
28049
+ return;
28050
+ }
28042
28051
  const hasApplicationRoutes = appContent.includes("applicationRoutes") || appContent.includes("clientRoutes");
28043
28052
  const hasRouteComponents = /<Route\s/.test(appContent);
28044
28053
  if (!hasApplicationRoutes && !hasRouteComponents) {
28045
28054
  result.errors.push({
28046
28055
  type: "error",
28047
28056
  category: "frontend-routes",
28048
- message: "App.tsx has no route definitions (neither applicationRoutes import nor <Route> components)",
28057
+ message: "App.tsx has no route definitions (neither DynamicRouter, applicationRoutes import, nor <Route> components)",
28049
28058
  file: path8.relative(structure.root, appFiles[0]),
28050
- suggestion: "Wire generated routes to App.tsx. Import applicationRouteExtensions from the generated file and render them."
28059
+ suggestion: 'For v3.7+: Use DynamicRouter with componentRegistry.generated.ts (run scaffold_routes outputFormat="componentRegistry"). For legacy: Import route configuration from generated routes file.'
28051
28060
  });
28052
28061
  return;
28053
28062
  }
@@ -28576,6 +28585,7 @@ async function handleCheckMigrations(args, config2) {
28576
28585
  );
28577
28586
  }
28578
28587
  await checkModelSnapshot(result, structure);
28588
+ await checkSqlObjectsInjection(result, structure);
28579
28589
  result.hasConflicts = result.conflicts.length > 0;
28580
28590
  generateSuggestions(result);
28581
28591
  return formatResult2(result, currentBranch, input.compareBranch);
@@ -28745,6 +28755,24 @@ async function checkModelSnapshot(result, structure) {
28745
28755
  }
28746
28756
  }
28747
28757
  }
28758
+ async function checkSqlObjectsInjection(result, structure) {
28759
+ if (!structure.migrations || !structure.infrastructure) return;
28760
+ const sqlObjectsPath = path9.join(structure.infrastructure, "Persistence", "SqlObjects");
28761
+ const sqlFiles = await findFiles("**/*.sql", { cwd: sqlObjectsPath }).catch(() => []);
28762
+ if (sqlFiles.length === 0) return;
28763
+ for (const migration of result.migrations) {
28764
+ const migrationPath = path9.join(structure.root, migration.file);
28765
+ const content = await readText(migrationPath).catch(() => "");
28766
+ if (content && !content.includes("SqlObjectHelper.ApplyAll")) {
28767
+ result.conflicts.push({
28768
+ type: "sql_objects",
28769
+ description: `Migration "${migration.name}" is MISSING SqlObjectHelper.ApplyAll(migrationBuilder) \u2014 ${sqlFiles.length} SQL object(s) found in SqlObjects/ will NOT be deployed`,
28770
+ files: [migration.file, ...sqlFiles.map((f) => path9.relative(structure.root, f))],
28771
+ resolution: 'Add "using SmartStack.Infrastructure.Persistence.SqlObjects;" at top and "SqlObjectHelper.ApplyAll(migrationBuilder);" at end of Up() method. Without this, TVFs/views/SPs will not exist in the database and cause runtime 500 errors.'
28772
+ });
28773
+ }
28774
+ }
28775
+ }
28748
28776
  function generateSuggestions(result) {
28749
28777
  if (result.conflicts.some((c) => c.type === "snapshot")) {
28750
28778
  result.suggestions.push(
@@ -28761,6 +28789,11 @@ function generateSuggestions(result) {
28761
28789
  "Ensure migrations are created in version order to avoid conflicts"
28762
28790
  );
28763
28791
  }
28792
+ if (result.conflicts.some((c) => c.type === "sql_objects")) {
28793
+ result.suggestions.push(
28794
+ "CRITICAL: Migrations missing SqlObjectHelper.ApplyAll(migrationBuilder) will cause ALL API endpoints to return 500 at runtime. Fix immediately."
28795
+ );
28796
+ }
28764
28797
  if (result.migrations.length > 20) {
28765
28798
  result.suggestions.push(
28766
28799
  "Consider squashing old migrations to reduce complexity. Use: /efcore squash"
@@ -28794,7 +28827,7 @@ function formatResult2(result, currentBranch, compareBranch) {
28794
28827
  lines.push("## Conflicts");
28795
28828
  lines.push("");
28796
28829
  for (const conflict of result.conflicts) {
28797
- const icon = conflict.type === "snapshot" ? "\u{1F504}" : conflict.type === "order" ? "\u{1F4C5}" : conflict.type === "naming" ? "\u{1F4DD}" : "\u26A0\uFE0F";
28830
+ const icon = conflict.type === "snapshot" ? "\u{1F504}" : conflict.type === "order" ? "\u{1F4C5}" : conflict.type === "naming" ? "\u{1F4DD}" : conflict.type === "sql_objects" ? "\u{1F6A8}" : "\u26A0\uFE0F";
28798
28831
  lines.push(`### ${icon} ${conflict.type.toUpperCase()}: ${conflict.description}`);
28799
28832
  if (conflict.files.length > 0) {
28800
28833
  lines.push(`- **Files**: ${conflict.files.map((f) => `\`${f}\``).join(", ")}`);
@@ -58588,12 +58621,16 @@ var init_scaffold_routes = __esm({
58588
58621
  init_navroute_parser();
58589
58622
  scaffoldRoutesTool = {
58590
58623
  name: "scaffold_routes",
58591
- description: `Generate React Router configuration from backend NavRoute attributes.
58624
+ description: `Generate frontend routing infrastructure from backend NavRoute attributes.
58592
58625
 
58593
- Creates:
58626
+ Creates (v3.7+ DynamicRouter, default):
58627
+ - componentRegistry.generated.ts: PageRegistry.register() calls with lazy imports for DynamicRouter
58594
58628
  - navRoutes.generated.ts: Registry of all routes with API paths and permissions
58595
- - routes.tsx: React Router configuration with nested routes
58596
- - Layout components (optional)
58629
+
58630
+ Creates (standalone, for non-SmartStack projects):
58631
+ - routes/index.tsx: createBrowserRouter() configuration with nested routes
58632
+ - navRoutes.generated.ts: Registry of all routes
58633
+ - Layout components and route guards (optional)
58597
58634
 
58598
58635
  Example:
58599
58636
  scaffold_routes source="controllers" scope="all"
@@ -59251,11 +59288,17 @@ var init_validate_frontend_routes = __esm({
59251
59288
  name: "validate_frontend_routes",
59252
59289
  description: `Validate frontend routes against backend NavRoute attributes.
59253
59290
 
59254
- Checks:
59291
+ Checks (v3.7+ DynamicRouter pattern):
59292
+ - componentRegistry.generated.ts exists with all PageRegistry.register() entries
59293
+ - main.tsx imports componentRegistry.generated
59294
+ - Backend NavRoutes have matching component keys
59295
+ - API clients use getRoute() instead of hardcoded paths
59296
+ - No hardcoded navigate()/Link paths in page components
59297
+
59298
+ Checks (legacy pattern):
59255
59299
  - navRoutes.generated.ts exists and is up-to-date
59256
- - API clients use correct NavRoute paths
59257
59300
  - React Router configuration matches backend routes
59258
- - Permission configurations are synchronized
59301
+ - App.tsx wiring is complete
59259
59302
 
59260
59303
  Example:
59261
59304
  validate_frontend_routes scope="all"