@atlashub/smartstack-cli 4.56.0 → 4.58.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 (23) hide show
  1. package/dist/index.js +62 -13
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/templates/project/Dockerfile.frontend.template +3 -3
  5. package/templates/skills/business-analyse/_shared.md +69 -21
  6. package/templates/skills/business-analyse/references/canonical-json-formats.md +1 -1
  7. package/templates/skills/business-analyse/references/naming-conventions.md +12 -2
  8. package/templates/skills/business-analyse/steps/step-00-init.md +54 -21
  9. package/templates/skills/business-analyse/steps/step-01-cadrage.md +6 -2
  10. package/templates/skills/business-analyse/steps/step-02-structure.md +13 -3
  11. package/templates/skills/business-analyse/steps/step-03-specify.md +14 -1
  12. package/templates/skills/business-analyse/steps/step-04-consolidate.md +3 -1
  13. package/templates/skills/business-analyse-design/steps/step-01-screens.md +12 -1
  14. package/templates/skills/business-analyse-design/steps/step-03-navigation.md +4 -3
  15. package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +2 -2
  16. package/templates/skills/business-analyse-handoff/steps/step-02-export.md +15 -13
  17. package/templates/skills/business-analyse-html/SKILL.md +14 -0
  18. package/templates/skills/business-analyse-html/steps/step-01-collect.md +12 -6
  19. package/templates/skills/business-analyse-html/steps/step-03-render.md +7 -4
  20. package/templates/skills/business-analyse-html/steps/step-04-verify.md +3 -3
  21. package/templates/skills/business-analyse-review/steps/step-00-init.md +7 -2
  22. package/templates/skills/business-analyse-review/steps/step-01-apply.md +6 -7
  23. package/templates/skills/business-analyse-status/SKILL.md +19 -8
package/dist/index.js CHANGED
@@ -116339,6 +116339,12 @@ async function setupMailPitContainer() {
116339
116339
  logger.info(`SMTP server: ${source_default.cyan("localhost:1025")}`);
116340
116340
  logger.info(`Web interface: ${source_default.cyan("http://localhost:8025")}`);
116341
116341
  }
116342
+ function toPascalCase(name) {
116343
+ return name.split(/[-_.\s]+/).filter(Boolean).map((part) => {
116344
+ if (/^\d+$/.test(part)) return part;
116345
+ return part.charAt(0).toUpperCase() + part.slice(1);
116346
+ }).join("");
116347
+ }
116342
116348
  function validateCSharpNamespace(name) {
116343
116349
  if (!name || name.trim().length === 0) {
116344
116350
  return { valid: false, error: "Project name cannot be empty" };
@@ -116349,13 +116355,13 @@ function validateCSharpNamespace(name) {
116349
116355
  return {
116350
116356
  valid: false,
116351
116357
  error: `Project name cannot start with a digit: '${firstChar}'`,
116352
- suggestion: `_${name.replace(/[^a-zA-Z0-9_]/g, "_")}`
116358
+ suggestion: toPascalCase("_" + name)
116353
116359
  };
116354
116360
  }
116355
116361
  return {
116356
116362
  valid: false,
116357
116363
  error: `Project name cannot start with '${firstChar}'`,
116358
- suggestion: name.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^[^a-zA-Z_]+/, "")
116364
+ suggestion: toPascalCase(name)
116359
116365
  };
116360
116366
  }
116361
116367
  const invalidChars = name.match(/[^a-zA-Z0-9_]/g);
@@ -116364,7 +116370,7 @@ function validateCSharpNamespace(name) {
116364
116370
  return {
116365
116371
  valid: false,
116366
116372
  error: `Project name contains invalid characters for C# namespace: ${uniqueInvalid.map((c) => `'${c}'`).join(", ")}`,
116367
- suggestion: name.replace(/[^a-zA-Z0-9_]/g, "_")
116373
+ suggestion: toPascalCase(name)
116368
116374
  };
116369
116375
  }
116370
116376
  const csharpKeywords = [
@@ -116453,6 +116459,14 @@ function validateCSharpNamespace(name) {
116453
116459
  suggestion: `${name}_Project`
116454
116460
  };
116455
116461
  }
116462
+ const pascalVersion = toPascalCase(name);
116463
+ if (pascalVersion !== name) {
116464
+ return {
116465
+ valid: false,
116466
+ error: `Project name "${name}" is not PascalCase`,
116467
+ suggestion: pascalVersion
116468
+ };
116469
+ }
116456
116470
  return { valid: true };
116457
116471
  }
116458
116472
  async function detectProjectContext(name, here) {
@@ -116742,7 +116756,8 @@ EndGlobal
116742
116756
  "Program.cs",
116743
116757
  "appsettings.json",
116744
116758
  "appsettings.Development.json",
116745
- (0, import_path7.join)("Properties", "launchSettings.json")
116759
+ (0, import_path7.join)("Properties", "launchSettings.json"),
116760
+ `${projectName}.Api.http`
116746
116761
  ];
116747
116762
  for (const placeholder of apiPlaceholders) {
116748
116763
  const placeholderPath = (0, import_path7.join)(apiDir, placeholder);
@@ -117184,6 +117199,7 @@ ${projectName}/
117184
117199
  \u2502 \u2514\u2500\u2500 ${projectName}.Api/ # Web API controllers and configuration
117185
117200
  \u251C\u2500\u2500 web/
117186
117201
  \u2502 \u2514\u2500\u2500 ${projectName.toLowerCase()}-web/ # React frontend (Vite + TypeScript + Tailwind)
117202
+ \u251C\u2500\u2500 docker-images/ # Dockerfiles (backend + frontend)
117187
117203
  \u2514\u2500\u2500 tests/ # Unit and integration tests
117188
117204
  \`\`\`
117189
117205
 
@@ -117640,14 +117656,47 @@ Thumbs.db
117640
117656
  logSafeWriteResult(webClaudeMd_relPath, webClaudeMd_result);
117641
117657
  recordFile(state, "frontend", webClaudeMd_relPath, webClaudeMd_result.hash);
117642
117658
  }
117659
+ const testFrontendDir = (0, import_path7.join)(TEMPLATES_DIR2, "test-frontend");
117660
+ if (await import_fs_extra6.default.pathExists(testFrontendDir)) {
117661
+ await import_fs_extra6.default.ensureDir((0, import_path7.join)(webDir, "src", "test", "msw"));
117662
+ const vitestContent = await import_fs_extra6.default.readFile((0, import_path7.join)(testFrontendDir, "vitest.config.ts"), "utf-8");
117663
+ const vitest_relPath = `${webRelPrefix}/vitest.config.ts`;
117664
+ const vitest_result = await safeWriteFile(
117665
+ (0, import_path7.join)(webDir, "vitest.config.ts"),
117666
+ vitestContent,
117667
+ findKnownHash(state, "frontend", vitest_relPath)
117668
+ );
117669
+ logSafeWriteResult(vitest_relPath, vitest_result);
117670
+ recordFile(state, "frontend", vitest_relPath, vitest_result.hash);
117671
+ const testFiles = [
117672
+ { src: "setup.ts", dest: "src/test/setup.ts" },
117673
+ { src: "test-utils.tsx", dest: "src/test/test-utils.tsx" },
117674
+ { src: "msw/handlers.ts", dest: "src/test/msw/handlers.ts" },
117675
+ { src: "msw/server.ts", dest: "src/test/msw/server.ts" }
117676
+ ];
117677
+ for (const { src, dest } of testFiles) {
117678
+ const content = await import_fs_extra6.default.readFile((0, import_path7.join)(testFrontendDir, src), "utf-8");
117679
+ const relPath = `${webRelPrefix}/${dest}`;
117680
+ const result = await safeWriteFile(
117681
+ (0, import_path7.join)(webDir, dest),
117682
+ content,
117683
+ findKnownHash(state, "frontend", relPath)
117684
+ );
117685
+ logSafeWriteResult(relPath, result);
117686
+ recordFile(state, "frontend", relPath, result.hash);
117687
+ }
117688
+ }
117643
117689
  logger.success("React frontend created at: " + webDir);
117644
117690
  }
117645
117691
  async function createDockerFiles(config, state, dryRun) {
117646
- const projectDir = config.name;
117647
- const projectName = config.name;
117648
- const projectNameLower = projectName.toLowerCase();
117692
+ const { name } = config;
117693
+ const projectDir = config.projectDir ?? ((0, import_path7.isAbsolute)(name) ? name : (0, import_path7.join)(process.cwd(), name));
117694
+ const projectName = (0, import_path7.basename)(name);
117695
+ if (!dryRun) {
117696
+ await import_fs_extra6.default.ensureDir((0, import_path7.join)(projectDir, "docker-images"));
117697
+ }
117649
117698
  const backendDockerfile = await loadTemplate("Dockerfile.backend.template", projectName);
117650
- const backendRelPath = `src/${projectName}.Api/Dockerfile`;
117699
+ const backendRelPath = "docker-images/Dockerfile.backend";
117651
117700
  if (dryRun) {
117652
117701
  logger.info(`Would create ${backendRelPath}`);
117653
117702
  } else {
@@ -117660,7 +117709,7 @@ async function createDockerFiles(config, state, dryRun) {
117660
117709
  recordFile(state, "docker", backendRelPath, backendResult.hash);
117661
117710
  }
117662
117711
  const frontendDockerfile = await loadTemplate("Dockerfile.frontend.template", projectName);
117663
- const frontendRelPath = `web/${projectNameLower}-web/Dockerfile`;
117712
+ const frontendRelPath = "docker-images/Dockerfile.frontend";
117664
117713
  if (dryRun) {
117665
117714
  logger.info(`Would create ${frontendRelPath}`);
117666
117715
  } else {
@@ -118054,7 +118103,7 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
118054
118103
  try {
118055
118104
  let cliVersion = "0.0.0";
118056
118105
  try {
118057
- const pkgPath = (0, import_path7.join)((0, import_path7.dirname)((0, import_path7.dirname)(__dirname)), "package.json");
118106
+ const pkgPath = (0, import_path7.join)((0, import_path7.dirname)(__dirname), "package.json");
118058
118107
  const pkg2 = JSON.parse(await import_fs_extra6.default.readFile(pkgPath, "utf-8"));
118059
118108
  cliVersion = pkg2.version || "0.0.0";
118060
118109
  } catch {
@@ -118119,8 +118168,8 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
118119
118168
  ` 3. Start dev server: ${source_default.cyan("npm run dev")}`,
118120
118169
  "",
118121
118170
  source_default.yellow("Docker:"),
118122
- ` Build backend: ${source_default.cyan(`docker build -t smartstack-${projectNameLower}-backend:latest -f src/${finalProjectName}.Api/Dockerfile .`)}`,
118123
- ` Build frontend: ${source_default.cyan(`docker build -t smartstack-${projectNameLower}-frontend:latest web/${projectNameLower}-web/`)}`,
118171
+ ` Build backend: ${source_default.cyan(`docker build -t smartstack-${projectNameLower}-backend:latest -f docker-images/Dockerfile.backend .`)}`,
118172
+ ` Build frontend: ${source_default.cyan(`docker build -t smartstack-${projectNameLower}-frontend:latest -f docker-images/Dockerfile.frontend .`)}`,
118124
118173
  "",
118125
118174
  source_default.yellow("Ralph (AI Automation):"),
118126
118175
  ` 1. Check MCP servers: ${source_default.cyan("smartstack check-mcp")}`,
@@ -129076,7 +129125,7 @@ Processing module: ${source_default.bold(moduleName)}`));
129076
129125
  }
129077
129126
  let cliVersion = "unknown";
129078
129127
  try {
129079
- const pkg2 = import_fs_extra15.default.readJsonSync((0, import_path16.join)(__dirname, "..", "..", "package.json"));
129128
+ const pkg2 = import_fs_extra15.default.readJsonSync((0, import_path16.join)(__dirname, "..", "package.json"));
129080
129129
  cliVersion = pkg2.version ?? "unknown";
129081
129130
  } catch {
129082
129131
  }