@atlashub/smartstack-cli 3.24.0 → 3.26.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 +5 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +51 -14
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/skills/apex/SKILL.md +26 -5
- package/templates/skills/apex/_shared.md +3 -3
- package/templates/skills/apex/references/agent-teams-protocol.md +8 -8
- package/templates/skills/apex/references/challenge-questions.md +165 -0
- package/templates/skills/apex/references/post-checks.md +457 -0
- package/templates/skills/apex/references/smartstack-api.md +234 -14
- package/templates/skills/apex/references/smartstack-frontend.md +20 -0
- package/templates/skills/apex/references/smartstack-layers.md +16 -4
- package/templates/skills/apex/steps/step-00-init.md +84 -56
- package/templates/skills/apex/steps/step-01-analyze.md +73 -87
- package/templates/skills/apex/steps/step-03-execute.md +6 -4
- package/templates/skills/apex/steps/step-04-examine.md +198 -0
- package/templates/skills/apex/steps/{step-05-examine.md → step-05-deep-review.md} +6 -6
- package/templates/skills/apex/steps/step-06-resolve.md +2 -2
- package/templates/skills/business-analyse/SKILL.md +28 -0
- package/templates/skills/business-analyse/references/agent-module-prompt.md +255 -0
- package/templates/skills/business-analyse/references/agent-pooling-best-practices.md +26 -10
- package/templates/skills/business-analyse/references/team-orchestration.md +437 -0
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +31 -4
- package/templates/skills/business-analyse/steps/step-03a1-setup.md +21 -0
- package/templates/skills/business-analyse/steps/step-03d-validate.md +84 -0
- package/templates/skills/efcore/steps/migration/step-02-create.md +14 -1
- package/templates/skills/ralph-loop/references/category-rules.md +26 -2
- package/templates/skills/ralph-loop/references/compact-loop.md +1 -1
- package/templates/skills/ralph-loop/references/core-seed-data.md +45 -10
- package/templates/skills/ralph-loop/steps/step-02-execute.md +128 -1
- package/templates/skills/validate-feature/steps/step-01-compile.md +4 -1
- package/templates/skills/apex/steps/step-04-validate.md +0 -448
package/dist/mcp-entry.mjs
CHANGED
|
@@ -34504,28 +34504,32 @@ using System.Linq;
|
|
|
34504
34504
|
using Microsoft.EntityFrameworkCore;
|
|
34505
34505
|
using Microsoft.Extensions.Logging;
|
|
34506
34506
|
using SmartStack.Application.Common.Interfaces.Identity;
|
|
34507
|
+
using SmartStack.Application.Common.Interfaces.Tenants;
|
|
34507
34508
|
using SmartStack.Application.Common.Interfaces.Persistence;
|
|
34508
34509
|
|
|
34509
34510
|
namespace {{implNamespace}};
|
|
34510
34511
|
|
|
34511
34512
|
/// <summary>
|
|
34512
34513
|
/// Service implementation for {{name}} operations.
|
|
34513
|
-
/// IMPORTANT: All queries MUST filter by
|
|
34514
|
+
/// IMPORTANT: All queries MUST filter by tenant ID for multi-tenant isolation.
|
|
34514
34515
|
/// IMPORTANT: GetAllAsync MUST support search parameter for frontend EntityLookup component.
|
|
34515
34516
|
/// </summary>
|
|
34516
34517
|
public class {{name}}Service : I{{name}}Service
|
|
34517
34518
|
{
|
|
34518
34519
|
private readonly IExtensionsDbContext _db;
|
|
34519
|
-
private readonly
|
|
34520
|
+
private readonly ICurrentUserService _currentUser;
|
|
34521
|
+
private readonly ICurrentTenantService _currentTenant;
|
|
34520
34522
|
private readonly ILogger<{{name}}Service> _logger;
|
|
34521
34523
|
|
|
34522
34524
|
public {{name}}Service(
|
|
34523
34525
|
IExtensionsDbContext db,
|
|
34524
|
-
|
|
34526
|
+
ICurrentUserService currentUser,
|
|
34527
|
+
ICurrentTenantService currentTenant,
|
|
34525
34528
|
ILogger<{{name}}Service> logger)
|
|
34526
34529
|
{
|
|
34527
34530
|
_db = db;
|
|
34528
34531
|
_currentUser = currentUser;
|
|
34532
|
+
_currentTenant = currentTenant;
|
|
34529
34533
|
_logger = logger;
|
|
34530
34534
|
}
|
|
34531
34535
|
|
|
@@ -34533,8 +34537,10 @@ public class {{name}}Service : I{{name}}Service
|
|
|
34533
34537
|
/// <inheritdoc />
|
|
34534
34538
|
public async Task<object> {{this}}(CancellationToken cancellationToken = default)
|
|
34535
34539
|
{
|
|
34536
|
-
|
|
34537
|
-
|
|
34540
|
+
var tenantId = _currentTenant.TenantId
|
|
34541
|
+
?? throw new UnauthorizedAccessException("Tenant context is required");
|
|
34542
|
+
_logger.LogInformation("Executing {{this}} for tenant {TenantId}", tenantId);
|
|
34543
|
+
// TODO: Implement {{this}} \u2014 ALL queries must filter by tenantId
|
|
34538
34544
|
// IMPORTANT: GetAllAsync MUST accept (string? search, int page, int pageSize) parameters
|
|
34539
34545
|
// to enable EntityLookup search on the frontend. Example:
|
|
34540
34546
|
// if (!string.IsNullOrWhiteSpace(search))
|
|
@@ -57016,12 +57022,37 @@ async function scaffoldRoutes(input, config2) {
|
|
|
57016
57022
|
result.instructions.push("import { lazy, Suspense } from 'react';");
|
|
57017
57023
|
result.instructions.push("import { PageLoader } from '@/components/ui/PageLoader';");
|
|
57018
57024
|
result.instructions.push("");
|
|
57025
|
+
const importedComponents = /* @__PURE__ */ new Set();
|
|
57026
|
+
for (const [context, applications] of Object.entries(routeTree)) {
|
|
57027
|
+
for (const [, modules] of Object.entries(applications)) {
|
|
57028
|
+
for (const route of modules) {
|
|
57029
|
+
const pageEntry = pageFiles.get(route.navRoute);
|
|
57030
|
+
if (pageEntry) {
|
|
57031
|
+
for (const entry of pageEntry) {
|
|
57032
|
+
if (!importedComponents.has(entry.componentName)) {
|
|
57033
|
+
importedComponents.add(entry.componentName);
|
|
57034
|
+
result.instructions.push(`const ${entry.componentName} = lazy(() =>`);
|
|
57035
|
+
result.instructions.push(` import('${entry.importPath}').then(m => ({ default: m.${entry.componentName} }))`);
|
|
57036
|
+
result.instructions.push(");");
|
|
57037
|
+
}
|
|
57038
|
+
}
|
|
57039
|
+
} else {
|
|
57040
|
+
const component = route.navRoute.split(".").map(capitalize).join("") + "Page";
|
|
57041
|
+
if (!importedComponents.has(component)) {
|
|
57042
|
+
importedComponents.add(component);
|
|
57043
|
+
result.instructions.push(`// TODO: const ${component} = lazy(() => import('@/pages/...'));`);
|
|
57044
|
+
}
|
|
57045
|
+
}
|
|
57046
|
+
}
|
|
57047
|
+
}
|
|
57048
|
+
}
|
|
57049
|
+
result.instructions.push("");
|
|
57019
57050
|
result.instructions.push("const contextRoutes: ContextRouteExtensions = {");
|
|
57020
57051
|
for (const [context, applications] of Object.entries(routeTree)) {
|
|
57021
57052
|
result.instructions.push(` ${context}: [`);
|
|
57022
57053
|
for (const [, modules] of Object.entries(applications)) {
|
|
57023
57054
|
for (const route of modules) {
|
|
57024
|
-
const modulePath = route.navRoute.split(".").slice(1).join("/");
|
|
57055
|
+
const modulePath = route.navRoute.split(".").slice(1).map(toKebabCase).join("/");
|
|
57025
57056
|
const pageEntry = pageFiles.get(route.navRoute);
|
|
57026
57057
|
const component = pageEntry?.[0]?.componentName || `${route.navRoute.split(".").map(capitalize).join("")}Page`;
|
|
57027
57058
|
result.instructions.push(` { path: '${modulePath}', element: <Suspense fallback={<PageLoader />}><${component} /></Suspense> },`);
|
|
@@ -57047,7 +57078,7 @@ async function scaffoldRoutes(input, config2) {
|
|
|
57047
57078
|
result.instructions.push("```tsx");
|
|
57048
57079
|
for (const [, modules] of Object.entries(applications)) {
|
|
57049
57080
|
for (const route of modules) {
|
|
57050
|
-
const modulePath = route.navRoute.split(".").slice(1).join("/");
|
|
57081
|
+
const modulePath = route.navRoute.split(".").slice(1).map(toKebabCase).join("/");
|
|
57051
57082
|
const pageEntry = pageFiles.get(route.navRoute);
|
|
57052
57083
|
const component = pageEntry?.[0]?.componentName || `${route.navRoute.split(".").map(capitalize).join("")}Page`;
|
|
57053
57084
|
result.instructions.push(`<Route path="${modulePath}" element={<Suspense fallback={<PageLoader />}><${component} /></Suspense>} />`);
|
|
@@ -57150,11 +57181,11 @@ async function discoverNavRoutes(structure, scope, warnings) {
|
|
|
57150
57181
|
permissions.push(match2[1]);
|
|
57151
57182
|
}
|
|
57152
57183
|
const fullNavRoute = suffix ? `${navRoute}.${suffix}` : navRoute;
|
|
57153
|
-
const expectedRoute = `api/${navRoute
|
|
57184
|
+
const expectedRoute = `api/${navRouteToUrlPath(navRoute)}${suffix ? `/${toKebabCase(suffix)}` : ""}`;
|
|
57154
57185
|
routes.push({
|
|
57155
57186
|
navRoute: fullNavRoute,
|
|
57156
|
-
apiPath: `/api/${navRoute
|
|
57157
|
-
webPath: `/${navRoute
|
|
57187
|
+
apiPath: `/api/${navRouteToUrlPath(navRoute)}${suffix ? `/${toKebabCase(suffix)}` : ""}`,
|
|
57188
|
+
webPath: `/${navRouteToUrlPath(navRoute)}${suffix ? `/${toKebabCase(suffix)}` : ""}`,
|
|
57158
57189
|
permissions,
|
|
57159
57190
|
controller: controllerName,
|
|
57160
57191
|
methods
|
|
@@ -57319,7 +57350,7 @@ function generateRouterConfig(routes, includeGuards) {
|
|
|
57319
57350
|
lines.push(` path: '${app}',`);
|
|
57320
57351
|
lines.push(" children: [");
|
|
57321
57352
|
for (const route of modules) {
|
|
57322
|
-
const modulePath = route.navRoute.split(".").slice(2).join("/");
|
|
57353
|
+
const modulePath = route.navRoute.split(".").slice(2).map(toKebabCase).join("/");
|
|
57323
57354
|
const pageName = route.navRoute.split(".").map(capitalize).join("");
|
|
57324
57355
|
if (includeGuards && route.permissions.length > 0) {
|
|
57325
57356
|
lines.push(" {");
|
|
@@ -57583,10 +57614,10 @@ function generateClientRoutesConfig(routes, pageFiles, includeGuards) {
|
|
|
57583
57614
|
lines.push(" {");
|
|
57584
57615
|
lines.push(` path: '${app}',`);
|
|
57585
57616
|
lines.push(" children: [");
|
|
57586
|
-
const firstModulePath = modules[0].navRoute.split(".").slice(2).join("/");
|
|
57617
|
+
const firstModulePath = modules[0].navRoute.split(".").slice(2).map(toKebabCase).join("/");
|
|
57587
57618
|
lines.push(` { index: true, element: <Navigate to="${firstModulePath}" replace /> },`);
|
|
57588
57619
|
for (const route of modules) {
|
|
57589
|
-
const modulePath = route.navRoute.split(".").slice(2).join("/");
|
|
57620
|
+
const modulePath = route.navRoute.split(".").slice(2).map(toKebabCase).join("/");
|
|
57590
57621
|
const pageName = route.navRoute.split(".").map(capitalize).join("") + "Page";
|
|
57591
57622
|
const pageEntry = pageFiles.get(route.navRoute);
|
|
57592
57623
|
const component = pageEntry?.[0]?.componentName || pageName;
|
|
@@ -57611,7 +57642,7 @@ function generateClientRoutesConfig(routes, pageFiles, includeGuards) {
|
|
|
57611
57642
|
lines.push(" },");
|
|
57612
57643
|
} else {
|
|
57613
57644
|
for (const route of modules) {
|
|
57614
|
-
const fullPath = route.navRoute.split(".").slice(1).join("/");
|
|
57645
|
+
const fullPath = route.navRoute.split(".").slice(1).map(toKebabCase).join("/");
|
|
57615
57646
|
const pageName = route.navRoute.split(".").map(capitalize).join("") + "Page";
|
|
57616
57647
|
const pageEntry = pageFiles.get(route.navRoute);
|
|
57617
57648
|
const component = pageEntry?.[0]?.componentName || pageName;
|
|
@@ -57673,6 +57704,12 @@ function getLayoutName(context) {
|
|
|
57673
57704
|
};
|
|
57674
57705
|
return layoutMap[context] || `${capitalize(context)}Layout`;
|
|
57675
57706
|
}
|
|
57707
|
+
function toKebabCase(segment) {
|
|
57708
|
+
return segment.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
57709
|
+
}
|
|
57710
|
+
function navRouteToUrlPath(navRoute) {
|
|
57711
|
+
return navRoute.split(".").map(toKebabCase).join("/");
|
|
57712
|
+
}
|
|
57676
57713
|
function capitalize(str) {
|
|
57677
57714
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
57678
57715
|
}
|