@mcpc-tech/unplugin-dev-inspector-mcp 0.0.18 → 0.0.20

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/cli.js CHANGED
@@ -1,6 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { i as setupMcpMiddleware, n as setupAcpMiddleware, r as setupInspectorMiddleware, t as updateMcpConfigs } from "./config-updater.js";
3
3
  import http from "node:http";
4
+ import { copyFileSync, existsSync, readFileSync, writeFileSync } from "fs";
5
+ import { resolve } from "path";
6
+ import { parse } from "@babel/parser";
7
+ import traverseModule from "@babel/traverse";
8
+ import MagicString from "magic-string";
4
9
 
5
10
  //#region src/utils/standalone-server.ts
6
11
  var StandaloneServer = class {
@@ -59,10 +64,10 @@ var StandaloneServer = class {
59
64
  const startPort = options.port || 8888;
60
65
  this.host = options.host || "localhost";
61
66
  for (let port = startPort; port < startPort + 100; port++) try {
62
- await new Promise((resolve, reject) => {
67
+ await new Promise((resolve$1, reject) => {
63
68
  this.server.listen(port, this.host, () => {
64
69
  this.port = port;
65
- resolve();
70
+ resolve$1();
66
71
  });
67
72
  this.server.on("error", (err) => {
68
73
  if (err.code === "EADDRINUSE") {
@@ -100,16 +105,447 @@ async function startStandaloneServer(options = {}) {
100
105
  };
101
106
  }
102
107
 
108
+ //#endregion
109
+ //#region src/utils/config-detector.ts
110
+ const CONFIG_PATTERNS = {
111
+ vite: [
112
+ "vite.config.ts",
113
+ "vite.config.js",
114
+ "vite.config.mjs"
115
+ ],
116
+ webpack: ["webpack.config.ts", "webpack.config.js"],
117
+ nextjs: [
118
+ "next.config.ts",
119
+ "next.config.js",
120
+ "next.config.mjs"
121
+ ]
122
+ };
123
+ /**
124
+ * Auto-detect bundler configuration files in the given directory
125
+ * @param cwd - Current working directory (defaults to process.cwd())
126
+ * @returns Array of detected configurations
127
+ */
128
+ function detectConfigs(cwd = process.cwd()) {
129
+ const detected = [];
130
+ for (const [bundler, patterns] of Object.entries(CONFIG_PATTERNS)) for (const pattern of patterns) {
131
+ const configPath = resolve(cwd, pattern);
132
+ if (existsSync(configPath)) {
133
+ detected.push({
134
+ path: configPath,
135
+ bundler,
136
+ exists: true
137
+ });
138
+ break;
139
+ }
140
+ }
141
+ return detected;
142
+ }
143
+ /**
144
+ * Detect a specific bundler configuration
145
+ * @param bundler - Bundler type to detect
146
+ * @param cwd - Current working directory
147
+ * @returns Detected config or null
148
+ */
149
+ function detectConfig(bundler, cwd = process.cwd()) {
150
+ const patterns = CONFIG_PATTERNS[bundler];
151
+ for (const pattern of patterns) {
152
+ const configPath = resolve(cwd, pattern);
153
+ if (existsSync(configPath)) return {
154
+ path: configPath,
155
+ bundler,
156
+ exists: true
157
+ };
158
+ }
159
+ return null;
160
+ }
161
+ /**
162
+ * Find config file by explicit path
163
+ * @param configPath - Explicit path to config file
164
+ * @returns Detected config or null
165
+ */
166
+ function detectConfigByPath(configPath) {
167
+ if (!existsSync(configPath)) return null;
168
+ const fileName = configPath.split("/").pop() || "";
169
+ for (const [bundler, patterns] of Object.entries(CONFIG_PATTERNS)) if (patterns.some((pattern) => fileName.includes(pattern.split(".")[0]))) return {
170
+ path: configPath,
171
+ bundler,
172
+ exists: true
173
+ };
174
+ return null;
175
+ }
176
+
177
+ //#endregion
178
+ //#region src/utils/codemod-transformer.ts
179
+ const traverse = traverseModule.default || traverseModule;
180
+ const PLUGIN_IMPORT = "@mcpc-tech/unplugin-dev-inspector-mcp";
181
+ const PLUGIN_VAR_NAME = "DevInspector";
182
+ /**
183
+ * Check if DevInspector is already imported in the code
184
+ */
185
+ function hasDevInspectorImport(code) {
186
+ return code.includes(PLUGIN_IMPORT);
187
+ }
188
+ /**
189
+ * Transform Vite configuration to add DevInspector
190
+ */
191
+ function transformViteConfig(options) {
192
+ const { configPath } = options;
193
+ try {
194
+ const code = readFileSync(configPath, "utf-8");
195
+ if (hasDevInspectorImport(code)) return {
196
+ success: true,
197
+ modified: false,
198
+ message: "DevInspector is already configured in this file"
199
+ };
200
+ const s = new MagicString(code);
201
+ const ast = parse(code, {
202
+ sourceType: "module",
203
+ plugins: ["typescript", "jsx"]
204
+ });
205
+ let lastImportEnd = 0;
206
+ let pluginsArrayStart = -1;
207
+ let firstPluginStart = -1;
208
+ let hasPluginsArray = false;
209
+ traverse(ast, {
210
+ ImportDeclaration(path$1) {
211
+ if (path$1.node.loc) lastImportEnd = Math.max(lastImportEnd, path$1.node.loc.end.line);
212
+ },
213
+ ObjectProperty(path$1) {
214
+ if (path$1.node.key.type === "Identifier" && path$1.node.key.name === "plugins" && path$1.node.value.type === "ArrayExpression") {
215
+ hasPluginsArray = true;
216
+ if (path$1.node.value.start !== null && path$1.node.value.start !== void 0) {
217
+ pluginsArrayStart = path$1.node.value.start;
218
+ const elements = path$1.node.value.elements;
219
+ if (elements.length > 0 && elements[0]?.start !== null && elements[0]?.start !== void 0) firstPluginStart = elements[0].start;
220
+ }
221
+ }
222
+ }
223
+ });
224
+ const lines = code.split("\n");
225
+ const importLine = `import ${PLUGIN_VAR_NAME} from '${PLUGIN_IMPORT}';\n`;
226
+ if (lastImportEnd > 0) {
227
+ let insertPos = 0;
228
+ for (let i = 0; i < lastImportEnd; i++) insertPos += lines[i].length + 1;
229
+ s.appendLeft(insertPos, importLine);
230
+ } else s.prepend(importLine);
231
+ if (hasPluginsArray && firstPluginStart > -1) {
232
+ const pluginCall = `${PLUGIN_VAR_NAME}.vite({\n enabled: true,\n }),\n `;
233
+ s.appendLeft(firstPluginStart, pluginCall);
234
+ } else if (hasPluginsArray && pluginsArrayStart > -1) {
235
+ const pluginCall = `\n ${PLUGIN_VAR_NAME}.vite({\n enabled: true,\n }),\n `;
236
+ s.appendLeft(pluginsArrayStart + 1, pluginCall);
237
+ } else return {
238
+ success: false,
239
+ modified: false,
240
+ error: "Could not find plugins array in config",
241
+ message: "Please add DevInspector manually to your plugins array"
242
+ };
243
+ return {
244
+ success: true,
245
+ modified: true,
246
+ code: s.toString(),
247
+ message: "Successfully added DevInspector to Vite config"
248
+ };
249
+ } catch (error) {
250
+ return {
251
+ success: false,
252
+ modified: false,
253
+ error: error instanceof Error ? error.message : String(error),
254
+ message: "Failed to transform Vite config"
255
+ };
256
+ }
257
+ }
258
+ /**
259
+ * Transform Webpack configuration to add DevInspector
260
+ */
261
+ function transformWebpackConfig(options) {
262
+ const { configPath } = options;
263
+ try {
264
+ const code = readFileSync(configPath, "utf-8");
265
+ if (hasDevInspectorImport(code)) return {
266
+ success: true,
267
+ modified: false,
268
+ message: "DevInspector is already configured in this file"
269
+ };
270
+ const s = new MagicString(code);
271
+ const isESM = code.includes("import ") && !code.includes("require(");
272
+ const ast = parse(code, {
273
+ sourceType: "module",
274
+ plugins: ["typescript"]
275
+ });
276
+ let lastImportEnd = 0;
277
+ let pluginsArrayStart = -1;
278
+ traverse(ast, {
279
+ ImportDeclaration(path$1) {
280
+ if (path$1.node.loc) lastImportEnd = Math.max(lastImportEnd, path$1.node.loc.end.line);
281
+ },
282
+ VariableDeclaration(path$1) {
283
+ if (path$1.node.loc && !isESM) lastImportEnd = Math.max(lastImportEnd, path$1.node.loc.end.line);
284
+ },
285
+ ObjectProperty(path$1) {
286
+ if (path$1.node.key.type === "Identifier" && path$1.node.key.name === "plugins" && path$1.node.value.type === "ArrayExpression") {
287
+ if (path$1.node.value.start !== null && path$1.node.value.start !== void 0) pluginsArrayStart = path$1.node.value.start;
288
+ }
289
+ }
290
+ });
291
+ const lines = code.split("\n");
292
+ const importLine = isESM ? `import ${PLUGIN_VAR_NAME} from '${PLUGIN_IMPORT}';\n` : `const ${PLUGIN_VAR_NAME} = require('${PLUGIN_IMPORT}');\n`;
293
+ if (lastImportEnd > 0) {
294
+ let insertPos = 0;
295
+ for (let i = 0; i < lastImportEnd; i++) insertPos += lines[i].length + 1;
296
+ s.appendLeft(insertPos, importLine);
297
+ } else s.prepend(importLine);
298
+ if (pluginsArrayStart > -1) {
299
+ const pluginCall = `\n ${PLUGIN_VAR_NAME}.webpack({\n enabled: true,\n }),`;
300
+ s.appendLeft(pluginsArrayStart + 1, pluginCall);
301
+ } else return {
302
+ success: false,
303
+ modified: false,
304
+ error: "Could not find plugins array in config",
305
+ message: "Please add DevInspector manually to your plugins array"
306
+ };
307
+ return {
308
+ success: true,
309
+ modified: true,
310
+ code: s.toString(),
311
+ message: "Successfully added DevInspector to Webpack config"
312
+ };
313
+ } catch (error) {
314
+ return {
315
+ success: false,
316
+ modified: false,
317
+ error: error instanceof Error ? error.message : String(error),
318
+ message: "Failed to transform Webpack config"
319
+ };
320
+ }
321
+ }
322
+ /**
323
+ * Transform Next.js configuration to add DevInspector
324
+ */
325
+ function transformNextConfig(options) {
326
+ const { configPath } = options;
327
+ try {
328
+ const code = readFileSync(configPath, "utf-8");
329
+ if (hasDevInspectorImport(code)) return {
330
+ success: true,
331
+ modified: false,
332
+ message: "DevInspector is already configured in this file"
333
+ };
334
+ const s = new MagicString(code);
335
+ const ast = parse(code, {
336
+ sourceType: "module",
337
+ plugins: ["typescript"]
338
+ });
339
+ let lastImportEnd = 0;
340
+ let nextConfigStart = -1;
341
+ let hasWebpackProperty = false;
342
+ traverse(ast, {
343
+ ImportDeclaration(path$1) {
344
+ if (path$1.node.loc) lastImportEnd = Math.max(lastImportEnd, path$1.node.loc.end.line);
345
+ },
346
+ VariableDeclarator(path$1) {
347
+ if (path$1.node.id.type === "Identifier" && path$1.node.id.name === "nextConfig" && path$1.node.init?.type === "ObjectExpression") {
348
+ if (path$1.node.init.start !== null && path$1.node.init.start !== void 0) nextConfigStart = path$1.node.init.start;
349
+ path$1.node.init.properties.forEach((prop) => {
350
+ if (prop.type === "ObjectProperty" && prop.key.type === "Identifier" && prop.key.name === "webpack") hasWebpackProperty = true;
351
+ });
352
+ }
353
+ }
354
+ });
355
+ const lines = code.split("\n");
356
+ const importLine = `import ${PLUGIN_VAR_NAME} from '${PLUGIN_IMPORT}';\n`;
357
+ if (lastImportEnd > 0) {
358
+ let insertPos = 0;
359
+ for (let i = 0; i < lastImportEnd; i++) insertPos += lines[i].length + 1;
360
+ s.appendLeft(insertPos, importLine);
361
+ } else s.prepend(importLine);
362
+ if (nextConfigStart > -1 && !hasWebpackProperty) {
363
+ const webpackConfig = `\n webpack: (config) => {\n config.plugins.push(\n ${PLUGIN_VAR_NAME}.webpack({\n enabled: true,\n })\n );\n return config;\n },`;
364
+ s.appendLeft(nextConfigStart + 1, webpackConfig);
365
+ } else if (hasWebpackProperty) return {
366
+ success: false,
367
+ modified: false,
368
+ message: "Webpack property already exists. Please add DevInspector manually to avoid conflicts"
369
+ };
370
+ else return {
371
+ success: false,
372
+ modified: false,
373
+ error: "Could not find nextConfig object",
374
+ message: "Please add DevInspector manually to your Next.js config"
375
+ };
376
+ return {
377
+ success: true,
378
+ modified: true,
379
+ code: s.toString(),
380
+ message: "Successfully added DevInspector to Next.js config"
381
+ };
382
+ } catch (error) {
383
+ return {
384
+ success: false,
385
+ modified: false,
386
+ error: error instanceof Error ? error.message : String(error),
387
+ message: "Failed to transform Next.js config"
388
+ };
389
+ }
390
+ }
391
+ /**
392
+ * Main transform function that routes to the appropriate transformer
393
+ */
394
+ function transformConfig(options) {
395
+ switch (options.bundler) {
396
+ case "vite": return transformViteConfig(options);
397
+ case "webpack": return transformWebpackConfig(options);
398
+ case "nextjs": return transformNextConfig(options);
399
+ default: return {
400
+ success: false,
401
+ modified: false,
402
+ error: `Unknown bundler type: ${options.bundler}`,
403
+ message: "Unsupported bundler type"
404
+ };
405
+ }
406
+ }
407
+
103
408
  //#endregion
104
409
  //#region src/cli.ts
105
410
  /**
106
- * Standalone dev-inspector server for Turbopack/other non-webpack builds
411
+ * CLI for dev-inspector
107
412
  *
108
- * Usage:
109
- * npx dev-inspector-server
110
- * npx dev-inspector-server --port 8888 --host localhost
413
+ * Commands:
414
+ * setup - Add DevInspector to your bundler config
415
+ * server - Start standalone MCP server (default)
111
416
  */
112
- async function main() {
417
+ async function runSetupCommand() {
418
+ const args = process.argv.slice(3);
419
+ let dryRun = false;
420
+ let noBackup = false;
421
+ let configPath;
422
+ let bundlerType;
423
+ for (let i = 0; i < args.length; i++) if (args[i] === "--dry-run") dryRun = true;
424
+ else if (args[i] === "--no-backup") noBackup = true;
425
+ else if (args[i] === "--config" && args[i + 1]) {
426
+ configPath = args[i + 1];
427
+ i++;
428
+ } else if (args[i] === "--bundler" && args[i + 1]) {
429
+ bundlerType = args[i + 1];
430
+ i++;
431
+ } else if (args[i] === "--help" || args[i] === "-h") {
432
+ console.log(`
433
+ ╔══════════════════════════════════════════════════════════╗
434
+ ║ 🔧 DevInspector Setup Command ║
435
+ ╠══════════════════════════════════════════════════════════╣
436
+ ║ ║
437
+ ║ Automatically add DevInspector to your bundler config ║
438
+ ║ ║
439
+ ╚══════════════════════════════════════════════════════════╝
440
+
441
+ Usage:
442
+ npx @mcpc-tech/unplugin-dev-inspector-mcp setup [options]
443
+
444
+ Options:
445
+ --config <path> Specify config file path (auto-detect by default)
446
+ --bundler <type> Specify bundler type: vite, webpack, nextjs
447
+ --dry-run Preview changes without applying them
448
+ --no-backup Skip creating backup files
449
+ --help, -h Show this help message
450
+
451
+ Examples:
452
+ # Auto-detect and setup
453
+ npx @mcpc-tech/unplugin-dev-inspector-mcp setup
454
+
455
+ # Preview changes without applying
456
+ npx @mcpc-tech/unplugin-dev-inspector-mcp setup --dry-run
457
+
458
+ # Setup specific config
459
+ npx @mcpc-tech/unplugin-dev-inspector-mcp setup --config vite.config.ts
460
+
461
+ # Setup for specific bundler
462
+ npx @mcpc-tech/unplugin-dev-inspector-mcp setup --bundler vite
463
+ `);
464
+ process.exit(0);
465
+ }
466
+ console.log(`
467
+ ╔══════════════════════════════════════════════════════════╗
468
+ ║ 🔧 DevInspector Setup ║
469
+ ╚══════════════════════════════════════════════════════════╝
470
+ `);
471
+ try {
472
+ let targetConfig;
473
+ if (configPath) {
474
+ targetConfig = detectConfigByPath(configPath);
475
+ if (!targetConfig) {
476
+ console.error(`❌ Config file not found: ${configPath}`);
477
+ process.exit(1);
478
+ }
479
+ } else if (bundlerType) {
480
+ targetConfig = detectConfig(bundlerType);
481
+ if (!targetConfig) {
482
+ console.error(`❌ No ${bundlerType} config file found in current directory`);
483
+ process.exit(1);
484
+ }
485
+ } else {
486
+ const detected = detectConfigs();
487
+ if (detected.length === 0) {
488
+ console.error("❌ No bundler config files found in current directory");
489
+ console.log("\nSupported configs: vite.config.{ts,js,mjs}, webpack.config.{ts,js}, next.config.{ts,js,mjs}");
490
+ process.exit(1);
491
+ }
492
+ if (detected.length > 1) {
493
+ console.log("📦 Multiple configs detected:");
494
+ detected.forEach((config, i) => {
495
+ console.log(` ${i + 1}. ${config.bundler}: ${config.path}`);
496
+ });
497
+ console.log("\n💡 Tip: Use --bundler or --config to specify which one to transform");
498
+ targetConfig = detected[0];
499
+ console.log(`\n🎯 Using: ${targetConfig.bundler} (${targetConfig.path})`);
500
+ } else {
501
+ targetConfig = detected[0];
502
+ console.log(`🎯 Detected: ${targetConfig.bundler} config at ${targetConfig.path}`);
503
+ }
504
+ }
505
+ console.log(`\n${dryRun ? "🔍 Previewing" : "🔧 Transforming"} ${targetConfig.bundler} config...`);
506
+ const result = transformConfig({
507
+ configPath: targetConfig.path,
508
+ bundler: targetConfig.bundler,
509
+ dryRun
510
+ });
511
+ if (!result.success) {
512
+ console.error(`\n❌ ${result.message}`);
513
+ if (result.error) console.error(` Error: ${result.error}`);
514
+ process.exit(1);
515
+ }
516
+ if (!result.modified) {
517
+ console.log(`\n✅ ${result.message}`);
518
+ process.exit(0);
519
+ }
520
+ if (dryRun) {
521
+ console.log("\n📄 Preview of changes:");
522
+ console.log("─".repeat(60));
523
+ console.log(result.code);
524
+ console.log("─".repeat(60));
525
+ console.log("\n💡 Run without --dry-run to apply these changes");
526
+ process.exit(0);
527
+ }
528
+ if (!noBackup) {
529
+ const backupPath = `${targetConfig.path}.bak`;
530
+ copyFileSync(targetConfig.path, backupPath);
531
+ console.log(`📦 Backup created: ${backupPath}`);
532
+ }
533
+ writeFileSync(targetConfig.path, result.code, "utf-8");
534
+ console.log(`\n✅ ${result.message}`);
535
+ console.log(`\n📝 Next steps:`);
536
+ console.log(` 1. Review the changes in ${targetConfig.path}`);
537
+ console.log(` 2. Install the package: npm i -D @mcpc-tech/unplugin-dev-inspector-mcp`);
538
+ console.log(` 3. Start your dev server`);
539
+ if (targetConfig.bundler === "vite") {
540
+ console.log(`\n⚠️ Important: DevInspector should be placed BEFORE framework plugins (react/vue/svelte)`);
541
+ console.log(` Please verify the plugin order in your config.`);
542
+ }
543
+ } catch (error) {
544
+ console.error("❌ Setup failed:", error instanceof Error ? error.message : error);
545
+ process.exit(1);
546
+ }
547
+ }
548
+ async function runServerCommand() {
113
549
  const args = process.argv.slice(2);
114
550
  let port = 8888;
115
551
  let host = "localhost";
@@ -121,7 +557,14 @@ async function main() {
121
557
  i++;
122
558
  } else if (args[i] === "--help" || args[i] === "-h") {
123
559
  console.log(`
124
- dev-inspector-server - Standalone MCP server for dev-inspector
560
+ ╔══════════════════════════════════════════════════════════╗
561
+ ║ 🔍 DevInspector MCP Server ║
562
+ ╠══════════════════════════════════════════════════════════╣
563
+ ║ ║
564
+ ║ Standalone MCP server for dev-inspector ║
565
+ ║ (for Turbopack and other non-webpack builds) ║
566
+ ║ ║
567
+ ╚══════════════════════════════════════════════════════════╝
125
568
 
126
569
  Usage:
127
570
  npx dev-inspector-server [options]
@@ -171,6 +614,25 @@ Example:
171
614
  process.exit(1);
172
615
  }
173
616
  }
617
+ async function main() {
618
+ const command = process.argv[2];
619
+ if (command === "setup") await runSetupCommand();
620
+ else if (command === "server" || !command) await runServerCommand();
621
+ else {
622
+ console.log(`
623
+ Unknown command: ${command}
624
+
625
+ Available commands:
626
+ setup - Add DevInspector to your bundler config
627
+ server - Start standalone MCP server (default)
628
+
629
+ Run with --help for more information:
630
+ npx @mcpc-tech/unplugin-dev-inspector-mcp setup --help
631
+ npx dev-inspector-server --help
632
+ `);
633
+ process.exit(1);
634
+ }
635
+ }
174
636
  main();
175
637
 
176
638
  //#endregion