mage-remote-run 0.27.0 → 0.29.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/bin/mage-remote-run.js +4 -2
- package/lib/api/spec-loader.js +13 -1
- package/lib/commands/company.js +5 -26
- package/lib/commands/connections.js +14 -87
- package/lib/commands/plugins.js +46 -9
- package/lib/config.js +4 -2
- package/lib/logos.js +80 -0
- package/lib/mcp.js +43 -1
- package/lib/prompts/company.js +33 -0
- package/lib/utils.js +6 -2
- package/package.json +2 -2
package/bin/mage-remote-run.js
CHANGED
|
@@ -46,6 +46,7 @@ import { getActiveProfile } from '../lib/config.js';
|
|
|
46
46
|
import { startMcpServer } from '../lib/mcp.js';
|
|
47
47
|
import { PluginLoader } from '../lib/plugin-loader.js';
|
|
48
48
|
import { eventBus, EVENTS } from '../lib/events.js';
|
|
49
|
+
import { createClient } from '../lib/api/factory.js';
|
|
49
50
|
|
|
50
51
|
// Connection commands are registered dynamically via registerCommands
|
|
51
52
|
// But we need them registered early if we want them to show up in help even if config fails?
|
|
@@ -56,6 +57,7 @@ program.command('mcp [args...]')
|
|
|
56
57
|
.option('--transport <type>', 'Transport type (stdio, http)', 'stdio')
|
|
57
58
|
.option('--host <host>', 'HTTP Host', '127.0.0.1')
|
|
58
59
|
.option('--port <port>', 'HTTP Port', '18098')
|
|
60
|
+
.option('--token <token>', 'Authentication token')
|
|
59
61
|
.allowExcessArguments(true)
|
|
60
62
|
.allowUnknownOption(true)
|
|
61
63
|
.action(async (args, options) => {
|
|
@@ -78,8 +80,8 @@ const appContext = {
|
|
|
78
80
|
config: await loadConfig(), // Re-load or reuse config
|
|
79
81
|
profile,
|
|
80
82
|
eventBus,
|
|
81
|
-
EVENTS
|
|
82
|
-
|
|
83
|
+
EVENTS,
|
|
84
|
+
createClient
|
|
83
85
|
};
|
|
84
86
|
|
|
85
87
|
const pluginLoader = new PluginLoader(appContext);
|
package/lib/api/spec-loader.js
CHANGED
|
@@ -7,6 +7,10 @@ import { fileURLToPath } from 'url';
|
|
|
7
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
const SPEC_DIR = path.resolve(__dirname, '../../api-specs/2.4.8');
|
|
9
9
|
|
|
10
|
+
// Simple in-memory cache for parsed specs
|
|
11
|
+
const specCache = {};
|
|
12
|
+
const shouldUseCache = process.env.NODE_ENV !== 'test';
|
|
13
|
+
|
|
10
14
|
export function loadSpec(type) {
|
|
11
15
|
let specFile;
|
|
12
16
|
if (type === 'ac-saas' || type === 'saas') {
|
|
@@ -16,10 +20,18 @@ export function loadSpec(type) {
|
|
|
16
20
|
specFile = 'swagger-paas.json';
|
|
17
21
|
}
|
|
18
22
|
|
|
23
|
+
if (shouldUseCache && specCache[specFile]) {
|
|
24
|
+
return specCache[specFile];
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
const filePath = path.join(SPEC_DIR, specFile);
|
|
20
28
|
if (!fs.existsSync(filePath)) {
|
|
21
29
|
throw new Error(`OpenAPI spec not found at: ${filePath}`);
|
|
22
30
|
}
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
const spec = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
33
|
+
if (shouldUseCache) {
|
|
34
|
+
specCache[specFile] = spec;
|
|
35
|
+
}
|
|
36
|
+
return spec;
|
|
25
37
|
}
|
package/lib/commands/company.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createClient } from '../api/factory.js';
|
|
2
2
|
import { printTable, handleError } from '../utils.js';
|
|
3
|
+
import { COMPANY_CREATE_QUESTIONS, getAddressQuestions, getCompanyUpdateQuestions } from '../prompts/company.js';
|
|
3
4
|
import chalk from 'chalk';
|
|
4
5
|
|
|
5
6
|
export function registerCompanyCommands(program) {
|
|
@@ -148,28 +149,11 @@ Examples:
|
|
|
148
149
|
const { default: inquirer } = await import('inquirer');
|
|
149
150
|
|
|
150
151
|
// Prompt for basic info
|
|
151
|
-
const answers = await inquirer.prompt(
|
|
152
|
-
{ name: 'company_name', message: 'Company Name:' },
|
|
153
|
-
{ name: 'company_email', message: 'Company Email:' },
|
|
154
|
-
{ name: 'legal_name', message: 'Legal Name (optional):' },
|
|
155
|
-
{ name: 'vat_tax_id', message: 'VAT/Tax ID (optional):' },
|
|
156
|
-
{ name: 'reseller_id', message: 'Reseller ID (optional):' },
|
|
157
|
-
{ name: 'customer_group_id', message: 'Customer Group ID:', default: '1' },
|
|
158
|
-
{ name: 'sales_representative_id', message: 'Sales Representative ID (Admin User ID):', default: '1' },
|
|
159
|
-
{ name: 'email', message: 'Super Admin Email:' },
|
|
160
|
-
{ name: 'firstname', message: 'Super Admin First Name:' },
|
|
161
|
-
{ name: 'lastname', message: 'Super Admin Last Name:' }
|
|
162
|
-
]);
|
|
152
|
+
const answers = await inquirer.prompt(COMPANY_CREATE_QUESTIONS);
|
|
163
153
|
|
|
164
154
|
// Address is required usually
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
{ name: 'city', message: 'City:' },
|
|
168
|
-
{ name: 'country_id', message: 'Country ID:', default: 'US' },
|
|
169
|
-
{ name: 'region', message: 'Region/State:' },
|
|
170
|
-
{ name: 'postcode', message: 'Postcode:' },
|
|
171
|
-
{ name: 'telephone', message: 'Telephone:' }
|
|
172
|
-
]);
|
|
155
|
+
const defaultCountry = process.env.MAGE_REMOTE_RUN_DEFAULT_COUNTRY || 'US';
|
|
156
|
+
const address = await inquirer.prompt(getAddressQuestions(defaultCountry));
|
|
173
157
|
|
|
174
158
|
const payload = {
|
|
175
159
|
company: {
|
|
@@ -223,12 +207,7 @@ Examples:
|
|
|
223
207
|
throw new Error(`Company ${companyId} not found.`);
|
|
224
208
|
}
|
|
225
209
|
|
|
226
|
-
const answers = await inquirer.prompt(
|
|
227
|
-
{ name: 'company_name', message: 'Company Name:', default: current.company_name },
|
|
228
|
-
{ name: 'company_email', message: 'Company Email:', default: current.company_email },
|
|
229
|
-
{ name: 'sales_representative_id', message: 'Sales Rep ID:', default: String(current.sales_representative_id) },
|
|
230
|
-
{ name: 'customer_group_id', message: 'Customer Group ID:', default: String(current.customer_group_id) }
|
|
231
|
-
]);
|
|
210
|
+
const answers = await inquirer.prompt(getCompanyUpdateQuestions(current));
|
|
232
211
|
|
|
233
212
|
// Merge
|
|
234
213
|
const payload = {
|
|
@@ -6,6 +6,7 @@ import { input, confirm, select } from '@inquirer/prompts';
|
|
|
6
6
|
import inquirer from 'inquirer';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import { getMissingB2BModules } from '../b2b.js';
|
|
9
|
+
import { getLogoForType } from '../logos.js';
|
|
9
10
|
|
|
10
11
|
// Helper to test connection (non-interactive or one-shot)
|
|
11
12
|
async function testConnection(name, settings) {
|
|
@@ -222,84 +223,7 @@ async function printConnectionStatus(config, options = {}) {
|
|
|
222
223
|
return;
|
|
223
224
|
}
|
|
224
225
|
|
|
225
|
-
|
|
226
|
-
const logos = {
|
|
227
|
-
adobe: chalk.red(`
|
|
228
|
-
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@
|
|
229
|
-
@@@@@@@@@@@@@@ @@@@@@@@@@@@@@
|
|
230
|
-
@@@@@@@@@@@@@ @@@@@@@@@@@@@
|
|
231
|
-
@@@@@@@@@@@@@ @@@@@@@@@@@@
|
|
232
|
-
@@@@@@@@@@@@ @@@@@@@@@@@@
|
|
233
|
-
@@@@@@@@@@@ @@@@@@@@@@@
|
|
234
|
-
@@@@@@@@@@ @@@@@@@@@@
|
|
235
|
-
@@@@@@@@@ @@@ @@@@@@@@@
|
|
236
|
-
@@@@@@@@@ @@@ @@@@@@@@@
|
|
237
|
-
@@@@@@@@ @@@@@ @@@@@@@@
|
|
238
|
-
@@@@@@@ @@@@@@@ @@@@@@@
|
|
239
|
-
@@@@@@ @@@@@@@@@ @@@@@@
|
|
240
|
-
@@@@@@ @@@@@@@@@@@ @@@@@@
|
|
241
|
-
@@@@@ @@@@@@@@@@@@ @@@@@
|
|
242
|
-
@@@@ @@@@@@@@@@@@@ @@@@
|
|
243
|
-
@@@ @@@@@@@ @@@
|
|
244
|
-
@@ @@@@@@@ @@
|
|
245
|
-
@@ @@@@@@ @@
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
`),
|
|
249
|
-
magento: chalk.hex('#FFA500')(`
|
|
250
|
-
@@
|
|
251
|
-
@@@@@@@@
|
|
252
|
-
@@@@@@@@@@@@@@
|
|
253
|
-
@@@@@@@@@@@@@@@@@@@@
|
|
254
|
-
@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
255
|
-
@@@@@@@@@@@@@@ @@@@@@@@@@@@@@
|
|
256
|
-
@@@@@@@@@@@@@@ @@@@@@@@@@@@@@
|
|
257
|
-
@@@@@@@@@@@@@ @@@@@@@@@@@@@
|
|
258
|
-
@@@@@@@@@@ @@@@@@@@@@
|
|
259
|
-
@@@@@@@ @@@@ @@@@ @@@@@@@
|
|
260
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
261
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
262
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
263
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
264
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
265
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
266
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
267
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
268
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
269
|
-
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
270
|
-
@@@@@ @@@@@@@ @@@@@@@ @@@@@
|
|
271
|
-
@@@ @@@@@@@ @@@@@@@ @@@
|
|
272
|
-
@@@@@@@@@@@@@@@@@@
|
|
273
|
-
@@@@@@@@@@@@@@@@@@
|
|
274
|
-
@@@@@@@@@@@@@@
|
|
275
|
-
@@@@@@@@
|
|
276
|
-
@@ `),
|
|
277
|
-
mageos: chalk.hex('#FFA500')(`
|
|
278
|
-
====== ======
|
|
279
|
-
============ ============
|
|
280
|
-
====================================
|
|
281
|
-
==========================================
|
|
282
|
-
================================================
|
|
283
|
-
================================-===============--
|
|
284
|
-
=============----============----============-----
|
|
285
|
-
=========--------=========-------=========--------
|
|
286
|
-
========---------========--------========---------
|
|
287
|
-
========---------========--------========---------
|
|
288
|
-
========---------========--------========---------
|
|
289
|
-
=====------ ======------ =====------
|
|
290
|
-
==--- ===--- ==---
|
|
291
|
-
`)
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
let logo = '';
|
|
295
|
-
if (profile.type && profile.type.startsWith('ac-')) {
|
|
296
|
-
logo = logos.adobe;
|
|
297
|
-
} else if (profile.type === 'mage-os') {
|
|
298
|
-
logo = logos.mageos;
|
|
299
|
-
} else if (profile.type === 'magento-os') {
|
|
300
|
-
logo = logos.magento;
|
|
301
|
-
}
|
|
302
|
-
|
|
226
|
+
const logo = getLogoForType(profile.type);
|
|
303
227
|
if (logo) {
|
|
304
228
|
console.log(logo);
|
|
305
229
|
}
|
|
@@ -542,10 +466,12 @@ Examples:
|
|
|
542
466
|
.action(async (options) => {
|
|
543
467
|
try {
|
|
544
468
|
const config = await loadConfig();
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
469
|
+
const results = await Promise.all(
|
|
470
|
+
Object.entries(config.profiles || {}).map(([name, profile]) =>
|
|
471
|
+
ensureProfileCapabilities(name, profile, config)
|
|
472
|
+
)
|
|
473
|
+
);
|
|
474
|
+
const updated = results.some(result => result);
|
|
549
475
|
if (updated) {
|
|
550
476
|
await saveConfig(config);
|
|
551
477
|
}
|
|
@@ -765,8 +691,7 @@ Examples:
|
|
|
765
691
|
}
|
|
766
692
|
console.log(chalk.blue(`Testing ${profiles.length} connections...\n`));
|
|
767
693
|
|
|
768
|
-
const
|
|
769
|
-
for (const name of profiles) {
|
|
694
|
+
const promises = profiles.map(async (name) => {
|
|
770
695
|
try {
|
|
771
696
|
const profileConfig = config.profiles[name];
|
|
772
697
|
const client = await createClient(profileConfig);
|
|
@@ -775,11 +700,13 @@ Examples:
|
|
|
775
700
|
await client.get('V1/store/storeViews');
|
|
776
701
|
const duration = Date.now() - start;
|
|
777
702
|
|
|
778
|
-
|
|
703
|
+
return [name, chalk.green('SUCCESS'), `${duration}ms`];
|
|
779
704
|
} catch (e) {
|
|
780
|
-
|
|
705
|
+
return [name, chalk.red('FAILED'), e.message];
|
|
781
706
|
}
|
|
782
|
-
}
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
const results = await Promise.all(promises);
|
|
783
710
|
|
|
784
711
|
console.log(chalk.bold('Connection Test Results:'));
|
|
785
712
|
printTable(['Profile', 'Status', 'Details'], results);
|
package/lib/commands/plugins.js
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { loadConfig, saveConfig } from '../config.js';
|
|
3
|
-
import
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { realpath } from 'node:fs/promises';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
function isFilesystemPath(pluginRef) {
|
|
8
|
+
const isScopedPackageName = /^@[^/\\]+\/[^/\\]+$/.test(pluginRef);
|
|
9
|
+
const hasPathSeparator = pluginRef.includes('/') || pluginRef.includes('\\');
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
path.isAbsolute(pluginRef)
|
|
13
|
+
|| pluginRef.startsWith('./')
|
|
14
|
+
|| pluginRef.startsWith('../')
|
|
15
|
+
|| pluginRef.startsWith('.\\')
|
|
16
|
+
|| pluginRef.startsWith('..\\')
|
|
17
|
+
|| pluginRef.startsWith('~/')
|
|
18
|
+
|| pluginRef.startsWith('~\\')
|
|
19
|
+
|| pluginRef.startsWith('file:')
|
|
20
|
+
|| (hasPathSeparator && !isScopedPackageName)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function resolvePluginReference(pluginRef) {
|
|
25
|
+
if (!isFilesystemPath(pluginRef)) {
|
|
26
|
+
return pluginRef;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (pluginRef.startsWith('~/') || pluginRef.startsWith('~\\')) {
|
|
30
|
+
return realpath(path.join(process.env.HOME || process.env.USERPROFILE || '', pluginRef.slice(2)));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (pluginRef.startsWith('file:')) {
|
|
34
|
+
return realpath(new URL(pluginRef));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return realpath(pluginRef);
|
|
38
|
+
}
|
|
4
39
|
|
|
5
40
|
|
|
6
41
|
export function registerPluginsCommands(program) {
|
|
@@ -11,19 +46,20 @@ export function registerPluginsCommands(program) {
|
|
|
11
46
|
.description('Register an installed plugin in the configuration')
|
|
12
47
|
.action(async (packageName) => {
|
|
13
48
|
try {
|
|
49
|
+
const pluginRef = await resolvePluginReference(packageName);
|
|
14
50
|
const config = await loadConfig();
|
|
15
51
|
if (!config.plugins) {
|
|
16
52
|
config.plugins = [];
|
|
17
53
|
}
|
|
18
54
|
|
|
19
|
-
if (config.plugins.includes(
|
|
20
|
-
console.log(chalk.yellow(`Plugin "${
|
|
55
|
+
if (config.plugins.includes(pluginRef)) {
|
|
56
|
+
console.log(chalk.yellow(`Plugin "${pluginRef}" is already registered.`));
|
|
21
57
|
return;
|
|
22
58
|
}
|
|
23
59
|
|
|
24
|
-
config.plugins.push(
|
|
60
|
+
config.plugins.push(pluginRef);
|
|
25
61
|
await saveConfig(config);
|
|
26
|
-
console.log(chalk.green(`Plugin "${
|
|
62
|
+
console.log(chalk.green(`Plugin "${pluginRef}" successfully registered.`));
|
|
27
63
|
console.log(chalk.gray(`Make sure the package is installed globally or in the local project.`));
|
|
28
64
|
|
|
29
65
|
} catch (error) {
|
|
@@ -35,15 +71,16 @@ export function registerPluginsCommands(program) {
|
|
|
35
71
|
.description('Unregister a plugin from the configuration')
|
|
36
72
|
.action(async (packageName) => {
|
|
37
73
|
try {
|
|
74
|
+
const pluginRef = await resolvePluginReference(packageName);
|
|
38
75
|
const config = await loadConfig();
|
|
39
|
-
if (!config.plugins || !config.plugins.includes(
|
|
40
|
-
console.log(chalk.yellow(`Plugin "${
|
|
76
|
+
if (!config.plugins || !config.plugins.includes(pluginRef)) {
|
|
77
|
+
console.log(chalk.yellow(`Plugin "${pluginRef}" is not registered.`));
|
|
41
78
|
return;
|
|
42
79
|
}
|
|
43
80
|
|
|
44
|
-
config.plugins = config.plugins.filter(p => p !==
|
|
81
|
+
config.plugins = config.plugins.filter(p => p !== pluginRef);
|
|
45
82
|
await saveConfig(config);
|
|
46
|
-
console.log(chalk.green(`Plugin "${
|
|
83
|
+
console.log(chalk.green(`Plugin "${pluginRef}" successfully unregistered.`));
|
|
47
84
|
|
|
48
85
|
} catch (error) {
|
|
49
86
|
console.error(chalk.red(`Error unregistering plugin: ${error.message}`));
|
package/lib/config.js
CHANGED
|
@@ -59,7 +59,8 @@ export async function loadConfig() {
|
|
|
59
59
|
export async function saveConfig(config) {
|
|
60
60
|
try {
|
|
61
61
|
await mkdirp(CONFIG_DIR);
|
|
62
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
62
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
63
|
+
fs.chmodSync(CONFIG_FILE, 0o600);
|
|
63
64
|
if (process.env.DEBUG) {
|
|
64
65
|
console.log(`Configuration saved to ${CONFIG_FILE}`);
|
|
65
66
|
}
|
|
@@ -108,7 +109,8 @@ export async function loadTokenCache() {
|
|
|
108
109
|
export async function saveTokenCache(cache) {
|
|
109
110
|
try {
|
|
110
111
|
await mkdirp(CACHE_DIR);
|
|
111
|
-
fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
112
|
+
fs.writeFileSync(TOKEN_CACHE_FILE, JSON.stringify(cache, null, 2), { mode: 0o600 });
|
|
113
|
+
fs.chmodSync(TOKEN_CACHE_FILE, 0o600);
|
|
112
114
|
} catch (e) {
|
|
113
115
|
console.error("Error saving token cache:", e.message);
|
|
114
116
|
throw e;
|
package/lib/logos.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
// ASCII Logos
|
|
4
|
+
const logos = {
|
|
5
|
+
adobe: chalk.red(`
|
|
6
|
+
@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@
|
|
7
|
+
@@@@@@@@@@@@@@ @@@@@@@@@@@@@@
|
|
8
|
+
@@@@@@@@@@@@@ @@@@@@@@@@@@@
|
|
9
|
+
@@@@@@@@@@@@@ @@@@@@@@@@@@
|
|
10
|
+
@@@@@@@@@@@@ @@@@@@@@@@@@
|
|
11
|
+
@@@@@@@@@@@ @@@@@@@@@@@
|
|
12
|
+
@@@@@@@@@@ @@@@@@@@@@
|
|
13
|
+
@@@@@@@@@ @@@ @@@@@@@@@
|
|
14
|
+
@@@@@@@@@ @@@ @@@@@@@@@
|
|
15
|
+
@@@@@@@@ @@@@@ @@@@@@@@
|
|
16
|
+
@@@@@@@ @@@@@@@ @@@@@@@
|
|
17
|
+
@@@@@@ @@@@@@@@@ @@@@@@
|
|
18
|
+
@@@@@@ @@@@@@@@@@@ @@@@@@
|
|
19
|
+
@@@@@ @@@@@@@@@@@@ @@@@@
|
|
20
|
+
@@@@ @@@@@@@@@@@@@ @@@@
|
|
21
|
+
@@@ @@@@@@@ @@@
|
|
22
|
+
@@ @@@@@@@ @@
|
|
23
|
+
@@ @@@@@@ @@
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
`),
|
|
27
|
+
magento: chalk.hex('#FFA500')(`
|
|
28
|
+
@@
|
|
29
|
+
@@@@@@@@
|
|
30
|
+
@@@@@@@@@@@@@@
|
|
31
|
+
@@@@@@@@@@@@@@@@@@@@
|
|
32
|
+
@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
33
|
+
@@@@@@@@@@@@@@ @@@@@@@@@@@@@@
|
|
34
|
+
@@@@@@@@@@@@@@ @@@@@@@@@@@@@@
|
|
35
|
+
@@@@@@@@@@@@@ @@@@@@@@@@@@@
|
|
36
|
+
@@@@@@@@@@ @@@@@@@@@@
|
|
37
|
+
@@@@@@@ @@@@ @@@@ @@@@@@@
|
|
38
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
39
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
40
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
41
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
42
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
43
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
44
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
45
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
46
|
+
@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@
|
|
47
|
+
@@@@@ @@@@@@@ @@@@@@@ @@@@@
|
|
48
|
+
@@@ @@@@@@@ @@@@@@@ @@@
|
|
49
|
+
@@@@@@@@@@@@@@@@@@
|
|
50
|
+
@@@@@@@@@@@@@@@@@@
|
|
51
|
+
@@@@@@@@@@@@@@
|
|
52
|
+
@@@@@@@@
|
|
53
|
+
@@ `),
|
|
54
|
+
mageos: chalk.hex('#FFA500')(`
|
|
55
|
+
====== ======
|
|
56
|
+
============ ============
|
|
57
|
+
====================================
|
|
58
|
+
==========================================
|
|
59
|
+
================================================
|
|
60
|
+
================================-===============--
|
|
61
|
+
=============----============----============-----
|
|
62
|
+
=========--------=========-------=========--------
|
|
63
|
+
========---------========--------========---------
|
|
64
|
+
========---------========--------========---------
|
|
65
|
+
========---------========--------========---------
|
|
66
|
+
=====------ ======------ =====------
|
|
67
|
+
==--- ===--- ==---
|
|
68
|
+
`)
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export function getLogoForType(type) {
|
|
72
|
+
if (type && type.startsWith('ac-')) {
|
|
73
|
+
return logos.adobe;
|
|
74
|
+
} else if (type === 'mage-os') {
|
|
75
|
+
return logos.mageos;
|
|
76
|
+
} else if (type === 'magento-os') {
|
|
77
|
+
return logos.magento;
|
|
78
|
+
}
|
|
79
|
+
return '';
|
|
80
|
+
}
|
package/lib/mcp.js
CHANGED
|
@@ -3,6 +3,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
3
3
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import http from "http";
|
|
6
|
+
import crypto from "crypto";
|
|
6
7
|
import chalk from "chalk";
|
|
7
8
|
import { Command } from "commander";
|
|
8
9
|
import { readFileSync } from "fs";
|
|
@@ -46,10 +47,51 @@ export async function startMcpServer(options) {
|
|
|
46
47
|
const host = options.host || '127.0.0.1';
|
|
47
48
|
const port = options.port || 18098;
|
|
48
49
|
|
|
50
|
+
// Authentication logic
|
|
51
|
+
let token = options.token || process.env.MAGE_REMOTE_RUN_MCP_TOKEN;
|
|
52
|
+
|
|
53
|
+
if (!token) {
|
|
54
|
+
token = crypto.randomBytes(16).toString('hex');
|
|
55
|
+
console.error(chalk.yellow(`--------------------------------------------------------------------------------`));
|
|
56
|
+
console.error(chalk.yellow(`MCP Server Authentication Token: `) + chalk.green.bold(token));
|
|
57
|
+
console.error(chalk.yellow(`Use this token to connect to the MCP server via ?token=${token}`));
|
|
58
|
+
console.error(chalk.yellow(`--------------------------------------------------------------------------------`));
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
const transport = new StreamableHTTPServerTransport();
|
|
50
62
|
|
|
51
63
|
const httpServer = http.createServer(async (req, res) => {
|
|
52
|
-
|
|
64
|
+
const requestUrl = new URL(req.url, `http://${req.headers.host || 'localhost'}`);
|
|
65
|
+
const pathname = requestUrl.pathname;
|
|
66
|
+
|
|
67
|
+
// Check authentication
|
|
68
|
+
const queryToken = requestUrl.searchParams.get('token');
|
|
69
|
+
const authHeader = req.headers.authorization;
|
|
70
|
+
|
|
71
|
+
let authenticated = false;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
if (queryToken && queryToken.length === token.length && crypto.timingSafeEqual(Buffer.from(queryToken), Buffer.from(token))) {
|
|
75
|
+
authenticated = true;
|
|
76
|
+
} else if (authHeader && authHeader.startsWith('Bearer ')) {
|
|
77
|
+
const headerToken = authHeader.substring(7);
|
|
78
|
+
if (headerToken.length === token.length && crypto.timingSafeEqual(Buffer.from(headerToken), Buffer.from(token))) {
|
|
79
|
+
authenticated = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch (e) {
|
|
83
|
+
// Ignore crypto errors (e.g. encoding issues)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!authenticated) {
|
|
87
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
88
|
+
res.end(JSON.stringify({ error: 'Unauthorized', message: 'Invalid or missing authentication token' }));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (pathname === '/sse' || (pathname === '/messages' && req.method === 'POST')) {
|
|
93
|
+
// Ensure query parameters don't interfere with transport handling if it expects exact path
|
|
94
|
+
req.url = pathname;
|
|
53
95
|
await transport.handleRequest(req, res);
|
|
54
96
|
} else {
|
|
55
97
|
res.writeHead(404);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
export const COMPANY_CREATE_QUESTIONS = [
|
|
3
|
+
{ name: 'company_name', message: 'Company Name:' },
|
|
4
|
+
{ name: 'company_email', message: 'Company Email:' },
|
|
5
|
+
{ name: 'legal_name', message: 'Legal Name (optional):' },
|
|
6
|
+
{ name: 'vat_tax_id', message: 'VAT/Tax ID (optional):' },
|
|
7
|
+
{ name: 'reseller_id', message: 'Reseller ID (optional):' },
|
|
8
|
+
{ name: 'customer_group_id', message: 'Customer Group ID:', default: '1' },
|
|
9
|
+
{ name: 'sales_representative_id', message: 'Sales Representative ID (Admin User ID):', default: '1' },
|
|
10
|
+
{ name: 'email', message: 'Super Admin Email:' },
|
|
11
|
+
{ name: 'firstname', message: 'Super Admin First Name:' },
|
|
12
|
+
{ name: 'lastname', message: 'Super Admin Last Name:' }
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export function getAddressQuestions(defaultCountry = 'US') {
|
|
16
|
+
return [
|
|
17
|
+
{ name: 'street', message: 'Street:' },
|
|
18
|
+
{ name: 'city', message: 'City:' },
|
|
19
|
+
{ name: 'country_id', message: 'Country ID:', default: defaultCountry },
|
|
20
|
+
{ name: 'region', message: 'Region/State:' },
|
|
21
|
+
{ name: 'postcode', message: 'Postcode:' },
|
|
22
|
+
{ name: 'telephone', message: 'Telephone:' }
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getCompanyUpdateQuestions(current) {
|
|
27
|
+
return [
|
|
28
|
+
{ name: 'company_name', message: 'Company Name:', default: current.company_name },
|
|
29
|
+
{ name: 'company_email', message: 'Company Email:', default: current.company_email },
|
|
30
|
+
{ name: 'sales_representative_id', message: 'Sales Rep ID:', default: String(current.sales_representative_id) },
|
|
31
|
+
{ name: 'customer_group_id', message: 'Customer Group ID:', default: String(current.customer_group_id) }
|
|
32
|
+
];
|
|
33
|
+
}
|
package/lib/utils.js
CHANGED
|
@@ -4,12 +4,16 @@ import fs from 'fs';
|
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import { loadConfig } from './config.js';
|
|
6
6
|
|
|
7
|
+
const TABLE_OPTIONS = {
|
|
8
|
+
style: { head: [] }
|
|
9
|
+
};
|
|
10
|
+
|
|
7
11
|
export function printTable(headers, data) {
|
|
8
12
|
const table = new Table({
|
|
13
|
+
...TABLE_OPTIONS,
|
|
9
14
|
head: headers.map(h => chalk.cyan(h)),
|
|
10
|
-
style: { head: [] }
|
|
11
15
|
});
|
|
12
|
-
|
|
16
|
+
table.push(...data);
|
|
13
17
|
console.log(table.toString());
|
|
14
18
|
}
|
|
15
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mage-remote-run",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "The remote swiss army knife for Magento Open Source, Mage-OS, Adobe Commerce",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"commander": "^14.0.2",
|
|
41
41
|
"csv-parse": "^6.1.0",
|
|
42
42
|
"csv-stringify": "^6.6.0",
|
|
43
|
-
"env-paths": "^
|
|
43
|
+
"env-paths": "^4.0.0",
|
|
44
44
|
"global-dirs": "^3.0.1",
|
|
45
45
|
"html-to-text": "^9.0.5",
|
|
46
46
|
"inquirer": "^13.1.0",
|