@atlashub/smartstack-cli 4.16.1 → 4.17.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/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +82 -35
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +1 -1
- package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +1 -1
- package/templates/skills/application/templates-frontend.md +3 -3
package/dist/mcp-entry.mjs
CHANGED
|
@@ -58448,6 +58448,8 @@ async function discoverPageFiles(webPath, routes) {
|
|
|
58448
58448
|
const entry = { importPath, componentName };
|
|
58449
58449
|
if (componentName.endsWith("CreatePage")) {
|
|
58450
58450
|
discovery.create = entry;
|
|
58451
|
+
} else if (componentName.startsWith("Create") && componentName.endsWith("Page")) {
|
|
58452
|
+
discovery.create = entry;
|
|
58451
58453
|
} else if (componentName.endsWith("EditPage")) {
|
|
58452
58454
|
discovery.edit = entry;
|
|
58453
58455
|
} else if (componentName.endsWith("DetailPage")) {
|
|
@@ -58505,17 +58507,29 @@ function generateApplicationRoutesConfig(routes, pageFiles, includeGuards) {
|
|
|
58505
58507
|
for (const route of routes) {
|
|
58506
58508
|
const discovery = pageFiles.get(route.navRoute);
|
|
58507
58509
|
const { entityPlural, entitySingular, basePath } = deriveEntityNames(route.navRoute);
|
|
58508
|
-
if (!discovery?.list) {
|
|
58509
|
-
|
|
58510
|
-
|
|
58511
|
-
|
|
58512
|
-
lines.push(
|
|
58513
|
-
}
|
|
58514
|
-
if (!discovery?.
|
|
58515
|
-
|
|
58516
|
-
|
|
58517
|
-
|
|
58518
|
-
lines.push(
|
|
58510
|
+
if (!discovery?.list && !importedComponents.has(`${entityPlural}Page`)) {
|
|
58511
|
+
importedComponents.add(`${entityPlural}Page`);
|
|
58512
|
+
lines.push(`const ${entityPlural}Page = lazy(() =>`);
|
|
58513
|
+
lines.push(` import('${basePath}/${entityPlural}Page').then(m => ({ default: m.${entityPlural}Page }))`);
|
|
58514
|
+
lines.push(");");
|
|
58515
|
+
}
|
|
58516
|
+
if (!discovery?.create && !importedComponents.has(`${entitySingular}CreatePage`)) {
|
|
58517
|
+
importedComponents.add(`${entitySingular}CreatePage`);
|
|
58518
|
+
lines.push(`const ${entitySingular}CreatePage = lazy(() =>`);
|
|
58519
|
+
lines.push(` import('${basePath}/${entitySingular}CreatePage').then(m => ({ default: m.${entitySingular}CreatePage }))`);
|
|
58520
|
+
lines.push(");");
|
|
58521
|
+
}
|
|
58522
|
+
if (!discovery?.detail && !importedComponents.has(`${entitySingular}DetailPage`)) {
|
|
58523
|
+
importedComponents.add(`${entitySingular}DetailPage`);
|
|
58524
|
+
lines.push(`const ${entitySingular}DetailPage = lazy(() =>`);
|
|
58525
|
+
lines.push(` import('${basePath}/${entitySingular}DetailPage').then(m => ({ default: m.${entitySingular}DetailPage }))`);
|
|
58526
|
+
lines.push(");");
|
|
58527
|
+
}
|
|
58528
|
+
if (!discovery?.edit && !importedComponents.has(`${entitySingular}EditPage`)) {
|
|
58529
|
+
importedComponents.add(`${entitySingular}EditPage`);
|
|
58530
|
+
lines.push(`const ${entitySingular}EditPage = lazy(() =>`);
|
|
58531
|
+
lines.push(` import('${basePath}/${entitySingular}EditPage').then(m => ({ default: m.${entitySingular}EditPage }))`);
|
|
58532
|
+
lines.push(");");
|
|
58519
58533
|
}
|
|
58520
58534
|
}
|
|
58521
58535
|
lines.push("");
|
|
@@ -58538,33 +58552,17 @@ function generateApplicationRoutesConfig(routes, pageFiles, includeGuards) {
|
|
|
58538
58552
|
const permGuardClose = permGuardOpen ? "</PermissionGuard>" : "";
|
|
58539
58553
|
lines.push(` // === ${entityPlural.toLowerCase()} (NavRoute: ${route.navRoute}) ===`);
|
|
58540
58554
|
const listComp = discovery?.list?.componentName || `${entityPlural}Page`;
|
|
58541
|
-
const listElement =
|
|
58542
|
-
|
|
58543
|
-
lines.push(` { path: '${modulePath}', element: ${listElement} },`);
|
|
58544
|
-
} else {
|
|
58545
|
-
lines.push(` // TODO: { path: '${modulePath}', element: <${listComp} /> },`);
|
|
58546
|
-
}
|
|
58555
|
+
const listElement = `<Suspense fallback={<PageLoader />}>${permGuardOpen}<${listComp} />${permGuardClose}</Suspense>`;
|
|
58556
|
+
lines.push(` { path: '${modulePath}', element: ${listElement} },`);
|
|
58547
58557
|
const createComp = discovery?.create?.componentName || `${entitySingular}CreatePage`;
|
|
58548
|
-
const createElement =
|
|
58549
|
-
|
|
58550
|
-
lines.push(` { path: '${modulePath}/create', element: ${createElement} },`);
|
|
58551
|
-
} else {
|
|
58552
|
-
lines.push(` // TODO: { path: '${modulePath}/create', element: <${createComp} /> },`);
|
|
58553
|
-
}
|
|
58558
|
+
const createElement = `<Suspense fallback={<PageLoader />}>${permGuardOpen}<${createComp} />${permGuardClose}</Suspense>`;
|
|
58559
|
+
lines.push(` { path: '${modulePath}/create', element: ${createElement} },`);
|
|
58554
58560
|
const detailComp = discovery?.detail?.componentName || `${entitySingular}DetailPage`;
|
|
58555
|
-
const detailElement =
|
|
58556
|
-
|
|
58557
|
-
lines.push(` { path: '${modulePath}/:id', element: ${detailElement} },`);
|
|
58558
|
-
} else {
|
|
58559
|
-
lines.push(` // TODO: { path: '${modulePath}/:id', element: <${detailComp} /> },`);
|
|
58560
|
-
}
|
|
58561
|
+
const detailElement = `<Suspense fallback={<PageLoader />}>${permGuardOpen}<${detailComp} />${permGuardClose}</Suspense>`;
|
|
58562
|
+
lines.push(` { path: '${modulePath}/:id', element: ${detailElement} },`);
|
|
58561
58563
|
const editComp = discovery?.edit?.componentName || `${entitySingular}EditPage`;
|
|
58562
|
-
const editElement =
|
|
58563
|
-
|
|
58564
|
-
lines.push(` { path: '${modulePath}/:id/edit', element: ${editElement} },`);
|
|
58565
|
-
} else {
|
|
58566
|
-
lines.push(` // TODO: { path: '${modulePath}/:id/edit', element: <${editComp} /> },`);
|
|
58567
|
-
}
|
|
58564
|
+
const editElement = `<Suspense fallback={<PageLoader />}>${permGuardOpen}<${editComp} />${permGuardClose}</Suspense>`;
|
|
58565
|
+
lines.push(` { path: '${modulePath}/:id/edit', element: ${editElement} },`);
|
|
58568
58566
|
}
|
|
58569
58567
|
}
|
|
58570
58568
|
lines.push("");
|
|
@@ -58795,6 +58793,9 @@ async function validateFrontendRoutes2(input, config2) {
|
|
|
58795
58793
|
if (scope === "all" || scope === "routes") {
|
|
58796
58794
|
await validateAppWiring(webPath, backendRoutes, result);
|
|
58797
58795
|
}
|
|
58796
|
+
if (scope === "all" || scope === "routes") {
|
|
58797
|
+
await validateCrudRoutes(webPath, backendRoutes, result);
|
|
58798
|
+
}
|
|
58798
58799
|
generateRecommendations2(result);
|
|
58799
58800
|
result.valid = result.apiClients.issues.filter((i) => i.severity === "error").length === 0 && result.routes.missing.length === 0 && result.registry.exists && result.appWiring.issues.length === 0;
|
|
58800
58801
|
return result;
|
|
@@ -59094,6 +59095,52 @@ async function validateAppWiring(webPath, backendRoutes, result) {
|
|
|
59094
59095
|
}
|
|
59095
59096
|
}
|
|
59096
59097
|
}
|
|
59098
|
+
async function validateCrudRoutes(webPath, backendRoutes, result) {
|
|
59099
|
+
const routeCandidates = ["applicationRoutes.generated.tsx", "clientRoutes.generated.tsx"];
|
|
59100
|
+
let routesContent = "";
|
|
59101
|
+
for (const candidate of routeCandidates) {
|
|
59102
|
+
const candidatePath = path20.join(webPath, "src", "routes", candidate);
|
|
59103
|
+
if (await fileExists(candidatePath)) {
|
|
59104
|
+
try {
|
|
59105
|
+
routesContent = await readText(candidatePath);
|
|
59106
|
+
} catch {
|
|
59107
|
+
logger.debug(`Failed to read ${candidatePath}`);
|
|
59108
|
+
}
|
|
59109
|
+
break;
|
|
59110
|
+
}
|
|
59111
|
+
}
|
|
59112
|
+
if (!routesContent) {
|
|
59113
|
+
return;
|
|
59114
|
+
}
|
|
59115
|
+
for (const route of backendRoutes) {
|
|
59116
|
+
const modulePath = route.navRoute.split(".").slice(1).map(toKebabCase).join("/");
|
|
59117
|
+
if (modulePath.length === 0) continue;
|
|
59118
|
+
const crudSuffixes = [
|
|
59119
|
+
{ suffix: "/create", label: "create" },
|
|
59120
|
+
{ suffix: "/:id", label: "detail" },
|
|
59121
|
+
{ suffix: "/:id/edit", label: "edit" }
|
|
59122
|
+
];
|
|
59123
|
+
for (const { suffix, label } of crudSuffixes) {
|
|
59124
|
+
const fullPath = `${modulePath}${suffix}`;
|
|
59125
|
+
const todoPattern = `// TODO:.*path:\\s*'${fullPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}'`;
|
|
59126
|
+
if (new RegExp(todoPattern).test(routesContent)) {
|
|
59127
|
+
result.appWiring.issues.push(
|
|
59128
|
+
`Route "${route.navRoute}" ${label} route is commented out (// TODO:). Run \`scaffold_routes\` to regenerate active routes.`
|
|
59129
|
+
);
|
|
59130
|
+
}
|
|
59131
|
+
if (label === "create") {
|
|
59132
|
+
const newPath = `${modulePath}/new`;
|
|
59133
|
+
const hasNewRoute = routesContent.includes(`path: '${newPath}'`) || routesContent.includes(`path="${newPath}"`);
|
|
59134
|
+
const hasCreateRoute = routesContent.includes(`path: '${modulePath}/create'`) || routesContent.includes(`path="${modulePath}/create"`);
|
|
59135
|
+
if (hasNewRoute && !hasCreateRoute) {
|
|
59136
|
+
result.appWiring.issues.push(
|
|
59137
|
+
`Route "${route.navRoute}" uses /new instead of /create. SmartStack convention is /create. Run \`scaffold_routes\` to fix.`
|
|
59138
|
+
);
|
|
59139
|
+
}
|
|
59140
|
+
}
|
|
59141
|
+
}
|
|
59142
|
+
}
|
|
59143
|
+
}
|
|
59097
59144
|
function generateRecommendations2(result) {
|
|
59098
59145
|
if (!result.registry.exists) {
|
|
59099
59146
|
result.recommendations.push('Run `scaffold_routes source="controllers"` to generate route registry');
|