magector 2.3.1 → 2.4.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 (2) hide show
  1. package/package.json +5 -5
  2. package/src/mcp-server.js +183 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magector",
3
- "version": "2.3.1",
3
+ "version": "2.4.0",
4
4
  "description": "Semantic code search for Magento 2 — index, search, MCP server",
5
5
  "type": "module",
6
6
  "main": "src/mcp-server.js",
@@ -33,10 +33,10 @@
33
33
  "ruvector": "^0.1.96"
34
34
  },
35
35
  "optionalDependencies": {
36
- "@magector/cli-darwin-arm64": "2.3.1",
37
- "@magector/cli-linux-x64": "2.3.1",
38
- "@magector/cli-linux-arm64": "2.3.1",
39
- "@magector/cli-win32-x64": "2.3.1"
36
+ "@magector/cli-darwin-arm64": "2.4.0",
37
+ "@magector/cli-linux-x64": "2.4.0",
38
+ "@magector/cli-linux-arm64": "2.4.0",
39
+ "@magector/cli-win32-x64": "2.4.0"
40
40
  },
41
41
  "keywords": [
42
42
  "magento",
package/src/mcp-server.js CHANGED
@@ -32,6 +32,8 @@ import {
32
32
  } from 'ruvector/dist/analysis/complexity.js';
33
33
  import { resolveBinary } from './binary.js';
34
34
  import { resolveModels } from './model.js';
35
+ import { createRequire } from 'module';
36
+ const __pkg = createRequire(import.meta.url)('../package.json');
35
37
 
36
38
  const config = {
37
39
  dbPath: process.env.MAGECTOR_DB || './.magector/index.db',
@@ -2816,7 +2818,7 @@ async function traceCallChain(startClass, startMethod, maxDepth = 3) {
2816
2818
  const server = new Server(
2817
2819
  {
2818
2820
  name: 'magector',
2819
- version: '2.1.1'
2821
+ version: __pkg.version
2820
2822
  },
2821
2823
  {
2822
2824
  capabilities: {
@@ -3086,7 +3088,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
3086
3088
  },
3087
3089
  {
3088
3090
  name: 'magento_find_db_schema',
3089
- description: 'Find database table definitions, columns, indexes, and constraints declared in db_schema.xml (Magento declarative schema). See also: magento_find_class (model/resource model for the table).',
3091
+ description: 'Find database table definitions, columns, indexes, and constraints declared in db_schema.xml (Magento declarative schema) AND legacy Setup scripts (InstallSchema, UpgradeSchema). Covers both modern declarative schema and legacy $setup->newTable() / addColumn() table definitions. See also: magento_find_trigger (DB triggers), magento_find_table_usage (cross-module table references).',
3090
3092
  inputSchema: {
3091
3093
  type: 'object',
3092
3094
  properties: {
@@ -3098,6 +3100,37 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
3098
3100
  required: ['tableName']
3099
3101
  }
3100
3102
  },
3103
+ {
3104
+ name: 'magento_find_trigger',
3105
+ description: 'Find MySQL database trigger definitions in Magento Setup scripts. Detects triggers created via TriggerFactory (setName, setTable, setEvent, setTime, addStatement, createTrigger). Returns trigger name, target table, event type (INSERT/UPDATE/DELETE), timing (BEFORE/AFTER), and SQL statements. Use when investigating DB-level automation, trigger chains, or performance issues caused by cascading triggers.',
3106
+ inputSchema: {
3107
+ type: 'object',
3108
+ properties: {
3109
+ triggerName: {
3110
+ type: 'string',
3111
+ description: 'Optional trigger name or pattern to search for. If omitted, finds all triggers in the codebase.'
3112
+ },
3113
+ tableName: {
3114
+ type: 'string',
3115
+ description: 'Optional table name to find triggers targeting this table.'
3116
+ }
3117
+ }
3118
+ }
3119
+ },
3120
+ {
3121
+ name: 'magento_find_table_usage',
3122
+ description: 'Find all code that references a database table — across db_schema.xml, Setup scripts (InstallSchema/UpgradeSchema), raw SQL (Zend_Db_Expr, $connection->query), getTable() calls, and resource model definitions. Builds a cross-module dependency map showing who reads/writes/creates a given table. Essential for impact analysis of schema changes.',
3123
+ inputSchema: {
3124
+ type: 'object',
3125
+ properties: {
3126
+ tableName: {
3127
+ type: 'string',
3128
+ description: 'Database table name to find all references for. Examples: "salesrule_ordered", "catalog_product_entity", "quote_item"'
3129
+ }
3130
+ },
3131
+ required: ['tableName']
3132
+ }
3133
+ },
3101
3134
  {
3102
3135
  name: 'magento_module_structure',
3103
3136
  description: 'Get the complete structure of a Magento module — lists all controllers, models, blocks, plugins, observers, API classes, XML configs, and templates. Provides an overview of module architecture.',
@@ -3807,17 +3840,160 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3807
3840
  }
3808
3841
 
3809
3842
  case 'magento_find_db_schema': {
3810
- const query = `db_schema.xml table ${args.tableName} column declarative schema`;
3811
- const raw = await rustSearchAsync(query, 40);
3812
- let results = raw.map(normalizeResult).filter(r =>
3843
+ // Search both declarative schema (db_schema.xml) and legacy Setup scripts
3844
+ const declQuery = `db_schema.xml table ${args.tableName} column declarative schema`;
3845
+ const legacyQuery = `create_table ${args.tableName} legacy_schema table_created ${args.tableName} setup install schema newTable addColumn`;
3846
+ const [declRaw, legacyRaw] = await Promise.all([
3847
+ rustSearchAsync(declQuery, 40),
3848
+ rustSearchAsync(legacyQuery, 30)
3849
+ ]);
3850
+
3851
+ let declResults = declRaw.map(normalizeResult).filter(r =>
3813
3852
  r.path?.includes('db_schema.xml')
3814
3853
  );
3815
- results = rerank(results, { fileType: 'xml', pathContains: ['db_schema.xml'] });
3854
+ declResults = rerank(declResults, { fileType: 'xml', pathContains: ['db_schema.xml'] });
3855
+
3856
+ let legacyResults = legacyRaw.map(normalizeResult).filter(r => {
3857
+ const p = r.path || '';
3858
+ return (p.includes('/Setup/') || p.includes('InstallSchema') ||
3859
+ p.includes('UpgradeSchema') || p.includes('/Patch/')) &&
3860
+ (r.snippet?.toLowerCase().includes(args.tableName.toLowerCase()) ||
3861
+ r.searchText?.toLowerCase().includes(args.tableName.toLowerCase()));
3862
+ });
3863
+
3864
+ // Deduplicate by path
3865
+ const seen = new Set(declResults.map(r => r.path));
3866
+ for (const r of legacyResults) {
3867
+ if (!seen.has(r.path)) {
3868
+ seen.add(r.path);
3869
+ declResults.push(r);
3870
+ }
3871
+ }
3872
+
3873
+ // Add section headers
3874
+ let output = '';
3875
+ const xmlResults = declResults.filter(r => r.path?.includes('db_schema.xml'));
3876
+ const setupResults = declResults.filter(r => !r.path?.includes('db_schema.xml'));
3877
+
3878
+ if (xmlResults.length > 0) {
3879
+ output += formatSearchResults(xmlResults.slice(0, 10));
3880
+ }
3881
+ if (setupResults.length > 0) {
3882
+ output += `\n\n### Legacy Setup Scripts (InstallSchema/UpgradeSchema)\n`;
3883
+ output += formatSearchResults(setupResults.slice(0, 10));
3884
+ }
3816
3885
 
3817
3886
  return {
3818
3887
  content: [{
3819
3888
  type: 'text',
3820
- text: formatSearchResults(results.slice(0, 15))
3889
+ text: output || formatSearchResults([])
3890
+ }]
3891
+ };
3892
+ }
3893
+
3894
+ case 'magento_find_trigger': {
3895
+ // Search for DB trigger definitions in Setup scripts
3896
+ const triggerTerm = args.triggerName || args.tableName || '';
3897
+ const query = `db_trigger create_trigger sql_trigger TriggerFactory createTrigger setName setEvent ${triggerTerm} setup database_trigger trigger`;
3898
+ const raw = await rustSearchAsync(query, 50);
3899
+ let results = raw.map(normalizeResult).filter(r => {
3900
+ const p = r.path || '';
3901
+ const s = (r.searchText || '') + ' ' + (r.snippet || '');
3902
+ // Must be a Setup file that contains trigger-related terms
3903
+ return (p.includes('/Setup/') || p.includes('InstallSchema') ||
3904
+ p.includes('UpgradeSchema') || p.includes('/Patch/')) &&
3905
+ (s.toLowerCase().includes('trigger') || s.includes('db_trigger') || s.includes('create_trigger'));
3906
+ });
3907
+
3908
+ // If searching for specific trigger/table, filter further
3909
+ if (triggerTerm) {
3910
+ const term = triggerTerm.toLowerCase();
3911
+ const filtered = results.filter(r => {
3912
+ const s = ((r.searchText || '') + ' ' + (r.snippet || '')).toLowerCase();
3913
+ return s.includes(term);
3914
+ });
3915
+ if (filtered.length > 0) results = filtered;
3916
+ }
3917
+
3918
+ results = rerank(results, { pathContains: ['/Setup/', 'UpgradeSchema', 'InstallSchema'] });
3919
+
3920
+ return {
3921
+ content: [{
3922
+ type: 'text',
3923
+ text: results.length > 0
3924
+ ? `### DB Trigger Definitions\n\n` + formatSearchResults(results.slice(0, 15)) +
3925
+ `\n\n**Tip:** Read the matched Setup files to see trigger names, target tables, events (INSERT/UPDATE/DELETE), timing (BEFORE/AFTER), and SQL statements.`
3926
+ : `No database triggers found${triggerTerm ? ` matching "${triggerTerm}"` : ''}. Triggers are defined in Setup scripts using TriggerFactory.`
3927
+ }]
3928
+ };
3929
+ }
3930
+
3931
+ case 'magento_find_table_usage': {
3932
+ const table = args.tableName;
3933
+ // Multi-query strategy: search declarative schema, setup scripts, and inline SQL references
3934
+ const queries = [
3935
+ `table ${table} db_schema.xml declarative schema column`,
3936
+ `sql_table ${table} table_reference ${table} Zend_Db_Expr getTable`,
3937
+ `create_table ${table} legacy_schema setup trigger ${table}`,
3938
+ `${table.replace(/_/g, ' ')} resource model collection`,
3939
+ ];
3940
+
3941
+ const rawResults = await Promise.all(queries.map(q => rustSearchAsync(q, 25)));
3942
+ const allResults = rawResults.flat().map(normalizeResult);
3943
+
3944
+ // Deduplicate by path
3945
+ const pathMap = new Map();
3946
+ for (const r of allResults) {
3947
+ if (!r.path) continue;
3948
+ const s = ((r.searchText || '') + ' ' + (r.snippet || '')).toLowerCase();
3949
+ if (s.includes(table.toLowerCase()) || r.path.includes('db_schema.xml')) {
3950
+ if (!pathMap.has(r.path) || (r.score || 0) > (pathMap.get(r.path).score || 0)) {
3951
+ pathMap.set(r.path, r);
3952
+ }
3953
+ }
3954
+ }
3955
+ const unique = Array.from(pathMap.values());
3956
+
3957
+ // Categorize results
3958
+ const categories = {
3959
+ 'Declarative Schema (db_schema.xml)': unique.filter(r => r.path?.includes('db_schema.xml')),
3960
+ 'Setup Scripts (InstallSchema/UpgradeSchema/Patch)': unique.filter(r => {
3961
+ const p = r.path || '';
3962
+ return !p.includes('db_schema.xml') &&
3963
+ (p.includes('/Setup/') || p.includes('InstallSchema') ||
3964
+ p.includes('UpgradeSchema') || p.includes('/Patch/'));
3965
+ }),
3966
+ 'PHP Code (raw SQL, getTable, Zend_Db_Expr)': unique.filter(r => {
3967
+ const p = r.path || '';
3968
+ return p.endsWith('.php') && !p.includes('db_schema.xml') &&
3969
+ !p.includes('/Setup/') && !p.includes('InstallSchema') &&
3970
+ !p.includes('UpgradeSchema') && !p.includes('/Patch/');
3971
+ }),
3972
+ 'XML Config': unique.filter(r => {
3973
+ const p = r.path || '';
3974
+ return p.endsWith('.xml') && !p.includes('db_schema.xml');
3975
+ }),
3976
+ };
3977
+
3978
+ let output = `### Table Usage: \`${table}\`\n\n`;
3979
+ output += `Found ${unique.length} file(s) referencing this table.\n\n`;
3980
+
3981
+ for (const [category, items] of Object.entries(categories)) {
3982
+ if (items.length > 0) {
3983
+ output += `#### ${category} (${items.length})\n`;
3984
+ output += formatSearchResults(items.slice(0, 8));
3985
+ output += '\n';
3986
+ }
3987
+ }
3988
+
3989
+ if (unique.length === 0) {
3990
+ output += `No references found for table "${table}". Try a broader search with magento_search.`;
3991
+ }
3992
+
3993
+ return {
3994
+ content: [{
3995
+ type: 'text',
3996
+ text: output
3821
3997
  }]
3822
3998
  };
3823
3999
  }