@atlashub/smartstack-cli 4.75.0 → 4.79.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 (81) hide show
  1. package/dist/index.js +87 -41
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/templates/project/claude-md/root.CLAUDE.md.template +1 -1
  5. package/templates/skills/ai-prompt/SKILL.md +64 -0
  6. package/templates/skills/ai-prompt/references/ai-agent-modes.md +89 -0
  7. package/templates/skills/ai-prompt/references/eval-framework.md +129 -0
  8. package/templates/skills/apex/SKILL.md +2 -2
  9. package/templates/skills/apex/references/checks/frontend-checks.sh +123 -11
  10. package/templates/skills/apex/references/checks/seed-checks.sh +81 -7
  11. package/templates/skills/apex/references/core-seed-data.md +27 -22
  12. package/templates/skills/apex/references/domain-events-pattern.md +45 -0
  13. package/templates/skills/apex/references/entity-hooks-pattern.md +68 -0
  14. package/templates/skills/apex/references/licensing-enforcement.md +52 -0
  15. package/templates/skills/apex/references/post-checks.md +18 -1
  16. package/templates/skills/apex/references/smartstack-api.md +116 -5
  17. package/templates/skills/apex/references/smartstack-frontend.md +1 -1
  18. package/templates/skills/apex/references/smartstack-layers.md +6 -6
  19. package/templates/skills/apex/steps/step-00-init.md +1 -1
  20. package/templates/skills/apex/steps/step-03b-layer1-seed.md +26 -0
  21. package/templates/skills/apex/steps/step-03d-layer3-frontend.md +124 -2
  22. package/templates/skills/apex/steps/step-04-examine.md +163 -0
  23. package/templates/skills/apex-verify/SKILL.md +110 -0
  24. package/templates/skills/apex-verify/references/audit-rules.md +50 -0
  25. package/templates/skills/apex-verify/steps/step-00-init.md +119 -0
  26. package/templates/skills/apex-verify/steps/step-01-nav-audit.md +96 -0
  27. package/templates/skills/apex-verify/steps/step-02-crud-audit.md +127 -0
  28. package/templates/skills/apex-verify/steps/step-03-perm-audit.md +119 -0
  29. package/templates/skills/apex-verify/steps/step-04-route-audit.md +98 -0
  30. package/templates/skills/apex-verify/steps/step-05-report.md +110 -0
  31. package/templates/skills/application/references/contexts-cheatsheet.md +86 -0
  32. package/templates/skills/application/references/extensions-system.md +158 -0
  33. package/templates/skills/application/references/frontend-route-naming.md +7 -5
  34. package/templates/skills/application/references/frontend-verification.md +7 -5
  35. package/templates/skills/application/references/provider-template.md +4 -2
  36. package/templates/skills/application/references/smartstack-provider.md +118 -0
  37. package/templates/skills/application/references/themes-db-driven.md +484 -0
  38. package/templates/skills/application/templates-frontend.md +2 -2
  39. package/templates/skills/application/templates-seed.md +4 -2
  40. package/templates/skills/audit-route/references/routing-pattern.md +3 -1
  41. package/templates/skills/business-analyse/SKILL.md +3 -3
  42. package/templates/skills/business-analyse/_shared.md +37 -0
  43. package/templates/skills/business-analyse/react/components.md +30 -28
  44. package/templates/skills/business-analyse/references/03-json-schemas.md +11 -3
  45. package/templates/skills/business-analyse/references/03-post-check-validation.md +64 -0
  46. package/templates/skills/business-analyse/references/canonical-json-formats.md +7 -3
  47. package/templates/skills/business-analyse/references/robustness-checks.md +1 -1
  48. package/templates/skills/business-analyse/references/validation-checklist.md +5 -5
  49. package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +15 -4
  50. package/templates/skills/business-analyse/steps/step-03-specify.md +162 -4
  51. package/templates/skills/business-analyse/steps/step-04-consolidate.md +211 -1
  52. package/templates/skills/business-analyse/templates-react.md +15 -15
  53. package/templates/skills/business-analyse-handoff/references/agent-handoff-transform-prompt.md +3 -0
  54. package/templates/skills/business-analyse-html/html/ba-interactive.html +198 -16
  55. package/templates/skills/business-analyse-html/html/src/scripts/01-data-init.js +64 -0
  56. package/templates/skills/business-analyse-html/html/src/scripts/05-render-specs.js +80 -11
  57. package/templates/skills/business-analyse-html/html/src/scripts/06-render-consolidation.js +2 -2
  58. package/templates/skills/business-analyse-html/html/src/scripts/06-render-mockups.js +6 -3
  59. package/templates/skills/business-analyse-html/html/src/scripts/12-render-diagrams.js +46 -0
  60. package/templates/skills/business-analyse-html/references/02-feature-data-building.md +4 -2
  61. package/templates/skills/business-analyse-html/references/data-build.md +2 -0
  62. package/templates/skills/business-analyse-html/references/data-mapping.md +88 -21
  63. package/templates/skills/business-analyse-html/steps/step-02-build-data.md +6 -0
  64. package/templates/skills/business-analyse-html/steps/step-04-verify.md +92 -3
  65. package/templates/skills/business-analyse-quick/SKILL.md +807 -0
  66. package/templates/skills/{sketch → business-analyse-quick}/references/domain-heuristics.md +59 -3
  67. package/templates/skills/business-analyse-quick/references/prd-schema.md +268 -0
  68. package/templates/skills/business-analyse-review/references/review-data-mapping.md +6 -0
  69. package/templates/skills/cli-app-sync/SKILL.md +105 -4
  70. package/templates/skills/cli-app-sync/references/comparison-map.md +13 -0
  71. package/templates/skills/cli-app-sync/references/diff-entities.md +162 -0
  72. package/templates/skills/dev-start/SKILL.md +7 -7
  73. package/templates/skills/documentation/templates.md +16 -16
  74. package/templates/skills/migrate/SKILL.md +312 -0
  75. package/templates/skills/migrate/references/v3.34-to-v3.46.md +289 -0
  76. package/templates/skills/sketch/SKILL.md +15 -153
  77. package/templates/skills/smoke-generation/SKILL.md +313 -0
  78. package/templates/skills/ui-components/SKILL.md +11 -1
  79. package/templates/skills/ui-components/patterns/data-table.md +1 -1
  80. package/templates/skills/ui-components/references/component-catalog.md +82 -0
  81. package/templates/skills/workflow/SKILL.md +70 -1
package/dist/index.js CHANGED
@@ -128062,7 +128062,6 @@ var import_bcryptjs = __toESM(require_bcryptjs());
128062
128062
  var import_fs4 = require("fs");
128063
128063
  var import_path14 = require("path");
128064
128064
  var import_os6 = require("os");
128065
- var import_crypto8 = require("crypto");
128066
128065
  var import_child_process9 = require("child_process");
128067
128066
  function tryLoadNativeDriver() {
128068
128067
  try {
@@ -128079,25 +128078,11 @@ var DEFAULT_CONFIG = {
128079
128078
  var PASSWORD_CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789!@#$%&*";
128080
128079
  var PASSWORD_LENGTH = 16;
128081
128080
  function generatePassword() {
128082
- const bytes = (0, import_crypto8.randomBytes)(PASSWORD_LENGTH);
128083
- const chars = [];
128081
+ let password = "";
128084
128082
  for (let i = 0; i < PASSWORD_LENGTH; i++) {
128085
- chars.push(PASSWORD_CHARS.charAt(bytes[i] % PASSWORD_CHARS.length));
128086
- }
128087
- let hasLower = false, hasUpper = false, hasDigit = false, hasSpecial = false;
128088
- for (const c of chars) {
128089
- if (c >= "a" && c <= "z") hasLower = true;
128090
- else if (c >= "A" && c <= "Z") hasUpper = true;
128091
- else if (c >= "0" && c <= "9") hasDigit = true;
128092
- else hasSpecial = true;
128093
- }
128094
- const extra = (0, import_crypto8.randomBytes)(4);
128095
- let pos = 0;
128096
- if (!hasLower) chars[pos++] = "abcdefghjkmnpqrstuvwxyz"[extra[0] % 23];
128097
- if (!hasUpper) chars[pos++] = "ABCDEFGHJKLMNPQRSTUVWXYZ"[extra[1] % 24];
128098
- if (!hasDigit) chars[pos++] = "23456789"[extra[2] % 8];
128099
- if (!hasSpecial) chars[pos] = "!@#$%&*"[extra[3] % 7];
128100
- return chars.join("");
128083
+ password += PASSWORD_CHARS.charAt(Math.floor(Math.random() * PASSWORD_CHARS.length));
128084
+ }
128085
+ return password;
128101
128086
  }
128102
128087
  function findAppSettings(apiFolder) {
128103
128088
  if (!(0, import_fs4.existsSync)(apiFolder)) {
@@ -128275,8 +128260,10 @@ adminCommand.command("reset").description("Reset the localAdmin account password
128275
128260
  const resetViaSqlCmd = async (sqlAuth) => {
128276
128261
  const authLabel = sqlAuth ? "SQL Server Authentication" : "Windows Authentication";
128277
128262
  spinner.text = `Using ${authLabel} (sqlcmd)...`;
128278
- const checkQuery = `SELECT COUNT(*) FROM [core].[auth_Users] WHERE Email = '${adminEmail}'`;
128263
+ logger.debug(`[admin-reset] Using sqlcmd path (${authLabel})`);
128264
+ const checkQuery = `SET NOCOUNT ON; SELECT COUNT(*) FROM [core].[auth_Users] WHERE Email = '${adminEmail}'`;
128279
128265
  const countResult = executeSqlCmd(connInfo.server, connInfo.database, checkQuery, sqlAuth);
128266
+ logger.debug(`[admin-reset] COUNT result: "${countResult}"`);
128280
128267
  const exists = parseInt(countResult, 10) > 0;
128281
128268
  if (!exists) {
128282
128269
  spinner.fail(`Account ${source_default.yellow(adminEmail)} does not exist.`);
@@ -128287,23 +128274,50 @@ adminCommand.command("reset").description("Reset the localAdmin account password
128287
128274
  spinner.text = "Generating new password...";
128288
128275
  const newPassword = generatePassword();
128289
128276
  const passwordHash = await import_bcryptjs.default.hash(newPassword, 12);
128290
- spinner.text = "Updating password and unlocking account...";
128291
- const userId = executeSqlCmd(
128292
- connInfo.server,
128293
- connInfo.database,
128294
- `SELECT CAST(Id AS NVARCHAR(36)) FROM [core].[auth_Users] WHERE Email = '${adminEmail}'`,
128295
- sqlAuth
128296
- ).trim();
128297
- const updateQuery = `UPDATE [core].[auth_Users] SET PasswordHash = '${passwordHash}', MustChangePassword = 0, IsLocked = 0, LockoutEnd = NULL, UpdatedAt = GETUTCDATE() WHERE Email = '${adminEmail}'`;
128298
- executeSqlCmd(connInfo.server, connInfo.database, updateQuery, sqlAuth);
128299
- const deleteSessionsQuery = `DELETE FROM [core].[auth_Sessions] WHERE UserId = '${userId}' AND IsSuccessful = 0`;
128277
+ logger.debug(`[admin-reset] Password length: ${newPassword.length}, Hash prefix: ${passwordHash.substring(0, 7)}`);
128278
+ spinner.text = "Updating password...";
128279
+ const updateQuery = `SET NOCOUNT ON; UPDATE [core].[auth_Users] SET PasswordHash = '${passwordHash}', MustChangePassword = 0, UpdatedAt = GETUTCDATE() WHERE Email = '${adminEmail}'`;
128280
+ const updateResult = executeSqlCmd(connInfo.server, connInfo.database, updateQuery, sqlAuth);
128281
+ logger.debug(`[admin-reset] UPDATE result: "${updateResult}"`);
128300
128282
  try {
128301
- executeSqlCmd(connInfo.server, connInfo.database, deleteSessionsQuery, sqlAuth);
128302
- } catch {
128283
+ executeSqlCmd(
128284
+ connInfo.server,
128285
+ connInfo.database,
128286
+ `SET NOCOUNT ON; UPDATE [core].[auth_Users] SET IsLocked = 0, LockoutEnd = NULL WHERE Email = '${adminEmail}'`,
128287
+ sqlAuth
128288
+ );
128289
+ logger.debug("[admin-reset] Account unlocked (IsLocked = 0)");
128290
+ } catch (unlockErr) {
128291
+ logger.debug(`[admin-reset] Unlock skipped (columns may not exist): ${unlockErr instanceof Error ? unlockErr.message : unlockErr}`);
128303
128292
  }
128304
- spinner.succeed("Password reset and account unlocked!");
128293
+ try {
128294
+ executeSqlCmd(
128295
+ connInfo.server,
128296
+ connInfo.database,
128297
+ `SET NOCOUNT ON; DELETE FROM [core].[auth_Sessions] WHERE UserId = (SELECT Id FROM [core].[auth_Users] WHERE Email = '${adminEmail}') AND IsSuccessful = 0`,
128298
+ sqlAuth
128299
+ );
128300
+ logger.debug("[admin-reset] Failed login sessions cleared");
128301
+ } catch (sessionErr) {
128302
+ logger.debug(`[admin-reset] Session cleanup skipped: ${sessionErr instanceof Error ? sessionErr.message : sessionErr}`);
128303
+ }
128304
+ const verifyQuery = `SET NOCOUNT ON; SELECT PasswordHash FROM [core].[auth_Users] WHERE Email = '${adminEmail}'`;
128305
+ const storedHash = executeSqlCmd(connInfo.server, connInfo.database, verifyQuery, sqlAuth).trim();
128306
+ if (!storedHash) {
128307
+ spinner.fail("Password update failed: no hash found in database after UPDATE");
128308
+ process.exit(1);
128309
+ }
128310
+ const hashMatch = await import_bcryptjs.default.compare(newPassword, storedHash);
128311
+ if (!hashMatch) {
128312
+ spinner.fail("Password update failed: stored hash does not match generated password");
128313
+ logger.error(`Expected hash prefix: ${passwordHash.substring(0, 10)}`);
128314
+ logger.error(`Stored hash prefix: ${storedHash.substring(0, 10)}`);
128315
+ logger.error(`Hash lengths: expected=${passwordHash.length}, stored=${storedHash.length}`);
128316
+ process.exit(1);
128317
+ }
128318
+ logger.debug(`[admin-reset] Verification OK \u2014 hash matches password`);
128319
+ spinner.succeed("Password reset successfully!");
128305
128320
  displayPasswordResult(adminEmail, newPassword);
128306
- spinner.stop();
128307
128321
  };
128308
128322
  const displayPasswordResult = (email, password) => {
128309
128323
  if (options.json) {
@@ -128330,6 +128344,7 @@ adminCommand.command("reset").description("Reset the localAdmin account password
128330
128344
  console.log();
128331
128345
  };
128332
128346
  const resetViaMssql = async (sqlModule) => {
128347
+ logger.debug(`[admin-reset] Using mssql (node driver) path`);
128333
128348
  spinner.text = "Connected. Checking account...";
128334
128349
  const checkResult = await sqlModule.query`
128335
128350
  SELECT COUNT(*) as count
@@ -128347,28 +128362,57 @@ adminCommand.command("reset").description("Reset the localAdmin account password
128347
128362
  spinner.text = "Generating new password...";
128348
128363
  const newPassword = generatePassword();
128349
128364
  const passwordHash = await import_bcryptjs.default.hash(newPassword, 12);
128350
- spinner.text = "Updating password and unlocking account...";
128351
- await sqlModule.query`
128365
+ logger.debug(`[admin-reset] Password length: ${newPassword.length}, Hash prefix: ${passwordHash.substring(0, 7)}`);
128366
+ spinner.text = "Updating password...";
128367
+ const updateResult = await sqlModule.query`
128352
128368
  UPDATE [core].[auth_Users]
128353
128369
  SET PasswordHash = ${passwordHash},
128354
128370
  MustChangePassword = ${false},
128355
- IsLocked = ${false},
128356
- LockoutEnd = ${null},
128357
128371
  UpdatedAt = ${/* @__PURE__ */ new Date()}
128358
128372
  WHERE Email = ${adminEmail}
128359
128373
  `;
128374
+ logger.debug(`[admin-reset] UPDATE rowsAffected: ${JSON.stringify(updateResult.rowsAffected)}`);
128375
+ if (!updateResult.rowsAffected || updateResult.rowsAffected[0] === 0) {
128376
+ await sqlModule.close();
128377
+ spinner.fail("Password update failed: UPDATE affected 0 rows");
128378
+ process.exit(1);
128379
+ }
128380
+ try {
128381
+ await sqlModule.query`
128382
+ UPDATE [core].[auth_Users]
128383
+ SET IsLocked = ${false}, LockoutEnd = ${null}
128384
+ WHERE Email = ${adminEmail}
128385
+ `;
128386
+ logger.debug("[admin-reset] Account unlocked (IsLocked = 0)");
128387
+ } catch (unlockErr) {
128388
+ logger.debug(`[admin-reset] Unlock skipped (columns may not exist): ${unlockErr instanceof Error ? unlockErr.message : unlockErr}`);
128389
+ }
128360
128390
  try {
128361
128391
  await sqlModule.query`
128362
128392
  DELETE FROM [core].[auth_Sessions]
128363
128393
  WHERE UserId = (SELECT Id FROM [core].[auth_Users] WHERE Email = ${adminEmail})
128364
128394
  AND IsSuccessful = ${false}
128365
128395
  `;
128366
- } catch {
128396
+ logger.debug("[admin-reset] Failed login sessions cleared");
128397
+ } catch (sessionErr) {
128398
+ logger.debug(`[admin-reset] Session cleanup skipped: ${sessionErr instanceof Error ? sessionErr.message : sessionErr}`);
128399
+ }
128400
+ const verifyResult = await sqlModule.query`
128401
+ SELECT PasswordHash FROM [core].[auth_Users] WHERE Email = ${adminEmail}
128402
+ `;
128403
+ const storedHash = verifyResult.recordset[0]?.PasswordHash;
128404
+ const hashMatch = storedHash ? await import_bcryptjs.default.compare(newPassword, storedHash) : false;
128405
+ if (!hashMatch) {
128406
+ await sqlModule.close();
128407
+ spinner.fail("Password update failed: stored hash does not match generated password");
128408
+ logger.error(`Expected hash prefix: ${passwordHash.substring(0, 10)}`);
128409
+ logger.error(`Stored hash prefix: ${(storedHash || "(null)").substring(0, 10)}`);
128410
+ process.exit(1);
128367
128411
  }
128412
+ logger.debug(`[admin-reset] Verification OK \u2014 hash matches password`);
128368
128413
  await sqlModule.close();
128369
- spinner.succeed("Password reset and account unlocked!");
128414
+ spinner.succeed("Password reset successfully!");
128370
128415
  displayPasswordResult(adminEmail, newPassword);
128371
- spinner.stop();
128372
128416
  };
128373
128417
  const tryWithSqlCmd = async () => {
128374
128418
  try {
@@ -128389,8 +128433,10 @@ adminCommand.command("reset").description("Reset the localAdmin account password
128389
128433
  }
128390
128434
  };
128391
128435
  try {
128436
+ logger.debug(`[admin-reset] Windows Auth: ${connInfo.useWindowsAuth}, Server: ${connInfo.server}, Database: ${connInfo.database}`);
128392
128437
  if (connInfo.useWindowsAuth) {
128393
128438
  const nativeDriver = tryLoadNativeDriver();
128439
+ logger.debug(`[admin-reset] msnodesqlv8 available: ${!!nativeDriver}`);
128394
128440
  let nativeConnected = false;
128395
128441
  if (nativeDriver) {
128396
128442
  try {