@atlashub/smartstack-mcp 1.2.0 → 1.2.2

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 CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- #!/usr/bin/env node
3
2
 
4
3
  // src/server.ts
5
4
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -149,7 +148,7 @@ var defaultConfig = {
149
148
  "loc_",
150
149
  "lic_"
151
150
  ],
152
- migrationFormat: "YYYYMMDD_NNN_{Description}",
151
+ migrationFormat: "{context}_v{version}_{sequence}_{Description}",
153
152
  namespaces: {
154
153
  domain: "SmartStack.Domain",
155
154
  application: "SmartStack.Application",
@@ -281,7 +280,7 @@ var ConventionsConfigSchema = z.object({
281
280
  "loc_",
282
281
  "lic_"
283
282
  ]),
284
- migrationFormat: z.string().default("YYYYMMDD_NNN_{Description}"),
283
+ migrationFormat: z.string().default("{context}_v{version}_{sequence}_{Description}"),
285
284
  namespaces: z.object({
286
285
  domain: z.string(),
287
286
  application: z.string(),
@@ -533,7 +532,7 @@ async function findControllerFiles(apiPath) {
533
532
  import path5 from "path";
534
533
  var validateConventionsTool = {
535
534
  name: "validate_conventions",
536
- description: "Validate AtlasHub/SmartStack conventions: SQL schemas (core/extensions), domain table prefixes (auth_, nav_, ai_, etc.), migration naming (YYYYMMDD_NNN_*), service interfaces (I*Service), namespace structure",
535
+ description: "Validate AtlasHub/SmartStack conventions: SQL schemas (core/extensions), domain table prefixes (auth_, nav_, ai_, etc.), migration naming ({context}_v{version}_{sequence}_*), service interfaces (I*Service), namespace structure",
537
536
  inputSchema: {
538
537
  type: "object",
539
538
  properties: {
@@ -675,7 +674,7 @@ async function validateMigrationNaming(structure, _config, result) {
675
674
  return;
676
675
  }
677
676
  const migrationFiles = await findFiles("*.cs", { cwd: structure.migrations });
678
- const migrationPattern = /^(\d{8})_(\d{3})_(.+)\.cs$/;
677
+ const migrationPattern = /^(\w+)_v(\d+\.\d+\.\d+)_(\d{3})_(.+)\.cs$/;
679
678
  const designerPattern = /\.Designer\.cs$/;
680
679
  for (const file of migrationFiles) {
681
680
  const fileName = path5.basename(file);
@@ -688,7 +687,7 @@ async function validateMigrationNaming(structure, _config, result) {
688
687
  category: "migrations",
689
688
  message: `Migration "${fileName}" does not follow naming convention`,
690
689
  file: path5.relative(structure.root, file),
691
- suggestion: `Expected format: YYYYMMDD_NNN_Description.cs (e.g., 20260115_001_InitialCreate.cs)`
690
+ suggestion: `Expected format: {context}_v{version}_{sequence}_{Description}.cs (e.g., core_v1.0.0_001_CreateAuthUsers.cs)`
692
691
  });
693
692
  }
694
693
  }
@@ -696,14 +695,18 @@ async function validateMigrationNaming(structure, _config, result) {
696
695
  for (let i = 1; i < orderedMigrations.length; i++) {
697
696
  const prev = orderedMigrations[i - 1];
698
697
  const curr = orderedMigrations[i];
699
- const prevDate = prev.substring(0, 8);
700
- const currDate = curr.substring(0, 8);
701
- if (currDate < prevDate) {
702
- result.warnings.push({
703
- type: "warning",
704
- category: "migrations",
705
- message: `Migration order issue: "${curr}" dated before "${prev}"`
706
- });
698
+ const prevMatch = migrationPattern.exec(prev);
699
+ const currMatch = migrationPattern.exec(curr);
700
+ if (prevMatch && currMatch) {
701
+ const prevVersion = prevMatch[2];
702
+ const currVersion = currMatch[2];
703
+ if (currVersion < prevVersion) {
704
+ result.warnings.push({
705
+ type: "warning",
706
+ category: "migrations",
707
+ message: `Migration order issue: "${curr}" (v${currVersion}) comes before "${prev}" (v${prevVersion})`
708
+ });
709
+ }
707
710
  }
708
711
  }
709
712
  }
@@ -871,7 +874,7 @@ async function handleCheckMigrations(args, config) {
871
874
  async function parseMigrations(migrationsPath, rootPath) {
872
875
  const files = await findFiles("*.cs", { cwd: migrationsPath });
873
876
  const migrations = [];
874
- const pattern = /^(\d{8})_(\d{3})_(.+)\.cs$/;
877
+ const pattern = /^(\w+)_v(\d+\.\d+\.\d+)_(\d{3})_(.+)\.cs$/;
875
878
  for (const file of files) {
876
879
  const fileName = path6.basename(file);
877
880
  if (fileName.includes(".Designer.") || fileName.includes("ModelSnapshot")) {
@@ -881,10 +884,13 @@ async function parseMigrations(migrationsPath, rootPath) {
881
884
  if (match) {
882
885
  migrations.push({
883
886
  name: fileName.replace(".cs", ""),
884
- timestamp: match[1],
885
- prefix: match[2],
886
- // Now this is the sequence number (NNN)
887
- description: match[3],
887
+ context: match[1],
888
+ // DbContext (core, extensions, etc.)
889
+ version: match[2],
890
+ // Semver version (1.0.0, 1.2.0, etc.)
891
+ sequence: match[3],
892
+ // Sequence number (001, 002, etc.)
893
+ description: match[4],
888
894
  file: path6.relative(rootPath, file),
889
895
  applied: true
890
896
  // We'd need DB connection to check this
@@ -892,8 +898,9 @@ async function parseMigrations(migrationsPath, rootPath) {
892
898
  } else {
893
899
  migrations.push({
894
900
  name: fileName.replace(".cs", ""),
895
- timestamp: "",
896
- prefix: "Unknown",
901
+ context: "Unknown",
902
+ version: "0.0.0",
903
+ sequence: "000",
897
904
  description: fileName.replace(".cs", ""),
898
905
  file: path6.relative(rootPath, file),
899
906
  applied: true
@@ -901,51 +908,63 @@ async function parseMigrations(migrationsPath, rootPath) {
901
908
  }
902
909
  }
903
910
  return migrations.sort((a, b) => {
904
- const dateCompare = a.timestamp.localeCompare(b.timestamp);
905
- if (dateCompare !== 0) return dateCompare;
906
- return a.prefix.localeCompare(b.prefix);
911
+ const versionCompare = compareVersions(a.version, b.version);
912
+ if (versionCompare !== 0) return versionCompare;
913
+ return a.sequence.localeCompare(b.sequence);
907
914
  });
908
915
  }
916
+ function compareVersions(a, b) {
917
+ const partsA = a.split(".").map(Number);
918
+ const partsB = b.split(".").map(Number);
919
+ for (let i = 0; i < 3; i++) {
920
+ if (partsA[i] > partsB[i]) return 1;
921
+ if (partsA[i] < partsB[i]) return -1;
922
+ }
923
+ return 0;
924
+ }
909
925
  function checkNamingConventions(result, _config) {
910
926
  for (const migration of result.migrations) {
911
- if (!migration.timestamp) {
927
+ if (migration.context === "Unknown") {
912
928
  result.conflicts.push({
913
929
  type: "naming",
914
930
  description: `Migration "${migration.name}" does not follow naming convention`,
915
931
  files: [migration.file],
916
- resolution: `Rename to format: YYYYMMDD_NNN_Description (e.g., 20260115_001_InitialCreate)`
932
+ resolution: `Rename to format: {context}_v{version}_{sequence}_{Description} (e.g., core_v1.0.0_001_CreateAuthUsers)`
917
933
  });
918
934
  }
919
- if (migration.prefix === "Unknown") {
935
+ if (migration.version === "0.0.0") {
920
936
  result.conflicts.push({
921
937
  type: "naming",
922
- description: `Migration "${migration.name}" missing sequence number`,
938
+ description: `Migration "${migration.name}" missing version number`,
923
939
  files: [migration.file],
924
- resolution: `Use format: YYYYMMDD_NNN_Description where NNN is a 3-digit sequence (001, 002, etc.)`
940
+ resolution: `Use format: {context}_v{version}_{sequence}_{Description} where version is semver (1.0.0, 1.2.0, etc.)`
925
941
  });
926
942
  }
927
943
  }
928
944
  }
929
945
  function checkChronologicalOrder(result) {
930
- const migrations = result.migrations.filter((m) => m.timestamp);
946
+ const migrations = result.migrations.filter((m) => m.context !== "Unknown");
931
947
  for (let i = 1; i < migrations.length; i++) {
932
948
  const prev = migrations[i - 1];
933
949
  const curr = migrations[i];
934
- if (curr.timestamp < prev.timestamp) {
935
- result.conflicts.push({
936
- type: "order",
937
- description: `Migration "${curr.name}" (${curr.timestamp}) is dated before "${prev.name}" (${prev.timestamp})`,
938
- files: [curr.file, prev.file],
939
- resolution: "Reorder migrations or update timestamps"
940
- });
941
- }
942
- if (curr.timestamp === prev.timestamp && curr.prefix === prev.prefix) {
943
- result.conflicts.push({
944
- type: "order",
945
- description: `Migrations "${curr.name}" and "${prev.name}" have same timestamp`,
946
- files: [curr.file, prev.file],
947
- resolution: "Use different sequence numbers (NNN) or different dates"
948
- });
950
+ if (curr.context === prev.context) {
951
+ const versionCompare = compareVersions(curr.version, prev.version);
952
+ if (versionCompare < 0) {
953
+ result.conflicts.push({
954
+ type: "order",
955
+ description: `Migration "${curr.name}" (v${curr.version}) is versioned before "${prev.name}" (v${prev.version})`,
956
+ files: [curr.file, prev.file],
957
+ resolution: "Reorder migrations or update version numbers"
958
+ });
959
+ }
960
+ if (curr.version === prev.version && curr.sequence === prev.sequence) {
961
+ result.conflicts.push({
962
+ type: "order",
963
+ description: `Migrations "${curr.name}" and "${prev.name}" have same version and sequence`,
964
+ files: [curr.file, prev.file],
965
+ resolution: "Use different sequence numbers (001, 002, etc.) for migrations in the same version"
966
+ });
967
+ }
949
968
  }
950
969
  }
951
970
  }
@@ -1000,7 +1019,7 @@ async function checkModelSnapshot(result, structure) {
1000
1019
  }
1001
1020
  const snapshotContent = await readText(snapshotFiles[0]);
1002
1021
  for (const migration of result.migrations) {
1003
- if (migration.timestamp && !snapshotContent.includes(migration.name)) {
1022
+ if (migration.context !== "Unknown" && !snapshotContent.includes(migration.name)) {
1004
1023
  result.conflicts.push({
1005
1024
  type: "dependency",
1006
1025
  description: `Migration "${migration.name}" not referenced in ModelSnapshot`,
@@ -1018,12 +1037,12 @@ function generateSuggestions(result) {
1018
1037
  }
1019
1038
  if (result.conflicts.some((c) => c.type === "naming")) {
1020
1039
  result.suggestions.push(
1021
- "Use convention: YYYYMMDD_NNN_Description for migration naming (e.g., 20260115_001_InitialCreate)"
1040
+ "Use convention: {context}_v{version}_{sequence}_{Description} for migration naming (e.g., core_v1.0.0_001_CreateAuthUsers)"
1022
1041
  );
1023
1042
  }
1024
1043
  if (result.conflicts.some((c) => c.type === "order")) {
1025
1044
  result.suggestions.push(
1026
- "Ensure migrations are created in chronological order to avoid conflicts"
1045
+ "Ensure migrations are created in version order to avoid conflicts"
1027
1046
  );
1028
1047
  }
1029
1048
  if (result.migrations.length > 20) {
@@ -1047,11 +1066,11 @@ function formatResult2(result, currentBranch, compareBranch) {
1047
1066
  lines.push("");
1048
1067
  lines.push("## Migrations");
1049
1068
  lines.push("");
1050
- lines.push("| Name | Timestamp | Prefix | Description |");
1051
- lines.push("|------|-----------|--------|-------------|");
1069
+ lines.push("| Name | Context | Version | Sequence | Description |");
1070
+ lines.push("|------|---------|---------|----------|-------------|");
1052
1071
  for (const migration of result.migrations) {
1053
1072
  lines.push(
1054
- `| ${migration.name} | ${migration.timestamp || "N/A"} | ${migration.prefix} | ${migration.description} |`
1073
+ `| ${migration.name} | ${migration.context} | ${migration.version} | ${migration.sequence} | ${migration.description} |`
1055
1074
  );
1056
1075
  }
1057
1076
  lines.push("");
@@ -1978,28 +1997,37 @@ Migrations MUST follow this naming pattern:
1978
1997
  ${migrationFormat}
1979
1998
  \`\`\`
1980
1999
 
2000
+ | Part | Description | Example |
2001
+ |------|-------------|---------|
2002
+ | \`{context}\` | DbContext name | \`core\`, \`extensions\` |
2003
+ | \`{version}\` | Semver version | \`v1.0.0\`, \`v1.2.0\` |
2004
+ | \`{sequence}\` | Order in version | \`001\`, \`002\` |
2005
+ | \`{Description}\` | Action (PascalCase) | \`CreateAuthUsers\` |
2006
+
1981
2007
  **Examples:**
1982
- - \`20260115_001_InitialSchema.cs\`
1983
- - \`20260120_002_AddUserProfiles.cs\`
1984
- - \`20260125_003_AddSupportTickets.cs\`
2008
+ - \`core_v1.0.0_001_InitialSchema.cs\`
2009
+ - \`core_v1.0.0_002_CreateAuthUsers.cs\`
2010
+ - \`core_v1.2.0_001_AddUserProfiles.cs\`
2011
+ - \`extensions_v1.0.0_001_AddClientFeatures.cs\`
1985
2012
 
1986
2013
  ### Creating Migrations
1987
2014
 
1988
2015
  \`\`\`bash
1989
2016
  # Create a new migration
1990
- dotnet ef migrations add 20260115_001_InitialSchema
2017
+ dotnet ef migrations add core_v1.0.0_001_InitialSchema
1991
2018
 
1992
2019
  # With context specified
1993
- dotnet ef migrations add 20260115_001_InitialSchema --context ApplicationDbContext
2020
+ dotnet ef migrations add core_v1.2.0_001_AddUserProfiles --context ApplicationDbContext
1994
2021
  \`\`\`
1995
2022
 
1996
2023
  ### Migration Rules
1997
2024
 
1998
2025
  1. **One migration per feature** - Group related changes in a single migration
1999
- 2. **Timestamps ensure order** - Use YYYYMMDD format for chronological sorting
2000
- 3. **Sequence numbers** - Use NNN (001, 002, etc.) for migrations on the same day
2001
- 4. **Descriptive names** - Use clear descriptions (InitialSchema, AddUserProfiles, etc.)
2002
- 5. **Schema must be specified** - All tables must specify their schema in ToTable()
2026
+ 2. **Version-based naming** - Use semver (v1.0.0, v1.2.0) to link migrations to releases
2027
+ 3. **Sequence numbers** - Use NNN (001, 002, etc.) for migrations in the same version
2028
+ 4. **Context prefix** - Use \`core_\` for platform tables, \`extensions_\` for client extensions
2029
+ 5. **Descriptive names** - Use clear PascalCase descriptions (CreateAuthUsers, AddUserProfiles, etc.)
2030
+ 6. **Schema must be specified** - All tables must specify their schema in ToTable()
2003
2031
 
2004
2032
  ---
2005
2033
 
@@ -2166,7 +2194,7 @@ public interface IUserServiceHooks
2166
2194
  | Platform schema | \`${schemas.platform}\` | \`.ToTable("auth_Users", "${schemas.platform}")\` |
2167
2195
  | Extensions schema | \`${schemas.extensions}\` | \`.ToTable("client_Custom", "${schemas.extensions}")\` |
2168
2196
  | Table prefixes | \`${tablePrefixes.slice(0, 5).join(", ")}\`, etc. | \`auth_Users\`, \`nav_Modules\` |
2169
- | Migration | \`YYYYMMDD_NNN_Description\` | \`20260115_001_InitialCreate\` |
2197
+ | Migration | \`{context}_v{version}_{seq}_{Desc}\` | \`core_v1.0.0_001_CreateAuthUsers\` |
2170
2198
  | Interface | \`I<Name>Service\` | \`IUserService\` |
2171
2199
  | Implementation | \`<Name>Service\` | \`UserService\` |
2172
2200
  | Domain namespace | \`${namespaces.domain}\` | - |