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