@mcpc-tech/unplugin-dev-inspector-mcp 0.1.9 → 0.1.10
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 +427 -389
- package/dist/cli.js +426 -383
- package/dist/config-updater.cjs +5 -5
- package/dist/config-updater.js +18 -18
- package/dist/index.cjs +5 -5
- package/dist/index.d.ts +4 -4
- package/dist/index.js +14 -14
- package/dist/next.cjs +5 -3
- package/dist/next.d.cts +7 -1
- package/dist/next.d.ts +7 -1
- package/dist/next.js +5 -3
- package/dist/standalone-server.js +1 -1
- package/package.json +1 -1
- package/dist/codemod-transformer.cjs +0 -4
- package/dist/codemod-transformer.js +0 -3
package/dist/cli.cjs
CHANGED
|
@@ -1,206 +1,111 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const require_chunk = require('./chunk.cjs');
|
|
3
3
|
const require_config_updater = require('./config-updater.cjs');
|
|
4
|
-
let node_http = require("node:http");
|
|
5
|
-
node_http = require_chunk.__toESM(node_http);
|
|
6
|
-
let child_process = require("child_process");
|
|
7
4
|
let fs = require("fs");
|
|
8
5
|
let path = require("path");
|
|
6
|
+
let child_process = require("child_process");
|
|
9
7
|
let _babel_parser = require("@babel/parser");
|
|
10
8
|
let _babel_traverse = require("@babel/traverse");
|
|
11
9
|
_babel_traverse = require_chunk.__toESM(_babel_traverse);
|
|
12
10
|
let magic_string = require("magic-string");
|
|
13
11
|
magic_string = require_chunk.__toESM(magic_string);
|
|
12
|
+
let node_http = require("node:http");
|
|
13
|
+
node_http = require_chunk.__toESM(node_http);
|
|
14
14
|
|
|
15
|
-
//#region src/utils/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!res.writableEnded) {
|
|
28
|
-
res.statusCode = 404;
|
|
29
|
-
res.end("Not Found");
|
|
30
|
-
}
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const layer = this.middlewares[index++];
|
|
34
|
-
if ((req.url || "/").startsWith(layer.route)) try {
|
|
35
|
-
const originalUrl = req.url;
|
|
36
|
-
if (layer.route !== "/" && req.url) {}
|
|
37
|
-
await layer.handle(req, res, next);
|
|
38
|
-
if (layer.route !== "/") req.url = originalUrl;
|
|
39
|
-
} catch (error) {
|
|
40
|
-
console.error("Middleware error:", error);
|
|
41
|
-
if (!res.writableEnded) {
|
|
42
|
-
res.statusCode = 500;
|
|
43
|
-
res.end("Internal Server Error");
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else next();
|
|
47
|
-
};
|
|
48
|
-
await next();
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
use(routeOrHandle, handle) {
|
|
52
|
-
let route = "/";
|
|
53
|
-
let handler;
|
|
54
|
-
if (typeof routeOrHandle === "string") {
|
|
55
|
-
route = routeOrHandle;
|
|
56
|
-
if (!handle) throw new Error("Handler is required when route is provided");
|
|
57
|
-
handler = handle;
|
|
58
|
-
} else handler = routeOrHandle;
|
|
59
|
-
this.middlewares.push({
|
|
60
|
-
route,
|
|
61
|
-
handle: handler
|
|
62
|
-
});
|
|
63
|
-
return this;
|
|
15
|
+
//#region src/utils/package-manager.ts
|
|
16
|
+
function detectPackageManager(cwd = process.cwd()) {
|
|
17
|
+
let current = cwd;
|
|
18
|
+
const root = (0, path.dirname)(cwd) === cwd ? cwd : "/";
|
|
19
|
+
while (current !== root) {
|
|
20
|
+
if ((0, fs.existsSync)((0, path.join)(current, "pnpm-lock.yaml"))) return "pnpm";
|
|
21
|
+
if ((0, fs.existsSync)((0, path.join)(current, "yarn.lock"))) return "yarn";
|
|
22
|
+
if ((0, fs.existsSync)((0, path.join)(current, "bun.lockb"))) return "bun";
|
|
23
|
+
if ((0, fs.existsSync)((0, path.join)(current, "package-lock.json"))) return "npm";
|
|
24
|
+
const parent = (0, path.dirname)(current);
|
|
25
|
+
if (parent === current) break;
|
|
26
|
+
current = parent;
|
|
64
27
|
}
|
|
65
|
-
|
|
66
|
-
|
|
28
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
29
|
+
if (userAgent) {
|
|
30
|
+
if (userAgent.startsWith("pnpm")) return "pnpm";
|
|
31
|
+
if (userAgent.startsWith("yarn")) return "yarn";
|
|
32
|
+
if (userAgent.startsWith("bun")) return "bun";
|
|
67
33
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (err.code === "EADDRINUSE") {
|
|
79
|
-
this.server.close();
|
|
80
|
-
reject(err);
|
|
81
|
-
} else reject(err);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
return {
|
|
85
|
-
host: this.host,
|
|
86
|
-
port: this.port
|
|
87
|
-
};
|
|
88
|
-
} catch (error) {
|
|
89
|
-
if (error.code !== "EADDRINUSE") throw error;
|
|
90
|
-
}
|
|
91
|
-
throw new Error(`Could not find a free port starting from ${startPort}`);
|
|
34
|
+
return "npm";
|
|
35
|
+
}
|
|
36
|
+
function getInstallCommand(pm, packageName, dev = true) {
|
|
37
|
+
const flags = dev ? "-D" : "";
|
|
38
|
+
switch (pm) {
|
|
39
|
+
case "npm": return `npm install ${flags} ${packageName}`;
|
|
40
|
+
case "yarn": return `yarn add ${flags} ${packageName}`;
|
|
41
|
+
case "pnpm": return `pnpm add ${flags} ${packageName}`;
|
|
42
|
+
case "bun": return `bun add ${flags} ${packageName}`;
|
|
43
|
+
default: return `npm install ${flags} ${packageName}`;
|
|
92
44
|
}
|
|
93
|
-
|
|
94
|
-
|
|
45
|
+
}
|
|
46
|
+
function installPackage(packageName, dev = true) {
|
|
47
|
+
const pm = detectPackageManager();
|
|
48
|
+
const command = getInstallCommand(pm, packageName, dev);
|
|
49
|
+
console.log(`\n📦 Installing ${packageName} with ${pm}...`);
|
|
50
|
+
console.log(` Running: ${command}`);
|
|
51
|
+
try {
|
|
52
|
+
(0, child_process.execSync)(command, { stdio: "inherit" });
|
|
53
|
+
console.log(`✅ Successfully installed ${packageName}`);
|
|
54
|
+
return true;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error(`❌ Failed to install ${packageName}`);
|
|
57
|
+
return false;
|
|
95
58
|
}
|
|
96
|
-
};
|
|
97
|
-
let globalServer = null;
|
|
98
|
-
async function startStandaloneServer(options = {}) {
|
|
99
|
-
if (globalServer) return {
|
|
100
|
-
server: globalServer,
|
|
101
|
-
host: globalServer.host,
|
|
102
|
-
port: globalServer.port,
|
|
103
|
-
isNew: false
|
|
104
|
-
};
|
|
105
|
-
globalServer = new StandaloneServer();
|
|
106
|
-
const { host, port } = await globalServer.start(options);
|
|
107
|
-
return {
|
|
108
|
-
server: globalServer,
|
|
109
|
-
host,
|
|
110
|
-
port,
|
|
111
|
-
isNew: true
|
|
112
|
-
};
|
|
113
59
|
}
|
|
114
60
|
|
|
115
61
|
//#endregion
|
|
116
|
-
//#region src/utils
|
|
117
|
-
require_config_updater.init_helpers();
|
|
118
|
-
const CONFIG_PATTERNS = {
|
|
119
|
-
vite: [
|
|
120
|
-
"vite.config.ts",
|
|
121
|
-
"vite.config.js",
|
|
122
|
-
"vite.config.mjs"
|
|
123
|
-
],
|
|
124
|
-
webpack: ["webpack.config.ts", "webpack.config.js"],
|
|
125
|
-
nextjs: [
|
|
126
|
-
"next.config.ts",
|
|
127
|
-
"next.config.js",
|
|
128
|
-
"next.config.mjs"
|
|
129
|
-
]
|
|
130
|
-
};
|
|
131
|
-
/**
|
|
132
|
-
* Auto-detect bundler configuration files in the given directory
|
|
133
|
-
* @param cwd - Current working directory (defaults to process.cwd())
|
|
134
|
-
* @returns Array of detected configurations
|
|
135
|
-
*/
|
|
136
|
-
function detectConfigs(cwd = process.cwd()) {
|
|
137
|
-
const detected = [];
|
|
138
|
-
for (const [bundler, patterns] of Object.entries(CONFIG_PATTERNS)) for (const pattern of patterns) {
|
|
139
|
-
const configPath = (0, path.resolve)(cwd, pattern);
|
|
140
|
-
if ((0, fs.existsSync)(configPath)) {
|
|
141
|
-
detected.push({
|
|
142
|
-
path: configPath,
|
|
143
|
-
bundler,
|
|
144
|
-
exists: true
|
|
145
|
-
});
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return detected;
|
|
150
|
-
}
|
|
62
|
+
//#region src/commands/setup/utils.ts
|
|
151
63
|
/**
|
|
152
|
-
*
|
|
153
|
-
* @param bundler - Bundler type to detect
|
|
154
|
-
* @param cwd - Current working directory
|
|
155
|
-
* @returns Detected config or null
|
|
64
|
+
* Detects a configuration file in the given directory based on patterns.
|
|
156
65
|
*/
|
|
157
|
-
function
|
|
158
|
-
const patterns = CONFIG_PATTERNS[bundler];
|
|
66
|
+
function detectConfigFile(cwd, patterns) {
|
|
159
67
|
for (const pattern of patterns) {
|
|
160
68
|
const configPath = (0, path.resolve)(cwd, pattern);
|
|
161
|
-
if ((0, fs.existsSync)(configPath)) return
|
|
162
|
-
path: configPath,
|
|
163
|
-
bundler,
|
|
164
|
-
exists: true
|
|
165
|
-
};
|
|
69
|
+
if ((0, fs.existsSync)(configPath)) return configPath;
|
|
166
70
|
}
|
|
167
71
|
return null;
|
|
168
72
|
}
|
|
169
73
|
/**
|
|
170
|
-
*
|
|
171
|
-
* @param configPath - Explicit path to config file
|
|
172
|
-
* @returns Detected config or null
|
|
74
|
+
* Calculates the character position to insert an import, based on the last import line.
|
|
173
75
|
*/
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
for (
|
|
178
|
-
|
|
179
|
-
bundler,
|
|
180
|
-
exists: true
|
|
181
|
-
};
|
|
182
|
-
return null;
|
|
76
|
+
function getInsertPosition(code, lastImportLine) {
|
|
77
|
+
const lines = code.split("\n");
|
|
78
|
+
let insertPos = 0;
|
|
79
|
+
for (let i = 0; i < lastImportLine; i++) insertPos += lines[i].length + 1;
|
|
80
|
+
return insertPos;
|
|
183
81
|
}
|
|
184
|
-
|
|
185
|
-
//#endregion
|
|
186
|
-
//#region src/utils/codemod-transformer.ts
|
|
187
|
-
const traverse = _babel_traverse.default.default || _babel_traverse.default;
|
|
188
|
-
const PLUGIN_IMPORT = "@mcpc-tech/unplugin-dev-inspector-mcp";
|
|
189
|
-
const PLUGIN_VAR_NAME = "DevInspector";
|
|
190
82
|
/**
|
|
191
|
-
*
|
|
83
|
+
* Sanitizes a path string to prevent syntax errors in generated code.
|
|
192
84
|
*/
|
|
193
|
-
function
|
|
194
|
-
return
|
|
85
|
+
function sanitizePath(path$1) {
|
|
86
|
+
return path$1.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "");
|
|
195
87
|
}
|
|
196
88
|
/**
|
|
197
|
-
*
|
|
89
|
+
* Generates formatted plugin options string.
|
|
198
90
|
*/
|
|
199
|
-
function
|
|
200
|
-
|
|
91
|
+
function getPluginOptions(options, indent = 6) {
|
|
92
|
+
if (!options.entryPath) return "{ enabled: true }";
|
|
93
|
+
const baseIndent = " ".repeat(indent);
|
|
94
|
+
return `{
|
|
95
|
+
${baseIndent}enabled: true,
|
|
96
|
+
${baseIndent}entry: '${sanitizePath(options.entryPath)}',
|
|
97
|
+
${baseIndent}autoInject: false,
|
|
98
|
+
${baseIndent.slice(2)}}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/commands/setup/frameworks/vite.ts
|
|
103
|
+
const traverse$2 = _babel_traverse.default.default || _babel_traverse.default;
|
|
104
|
+
const PLUGIN_IMPORT$2 = "@mcpc-tech/unplugin-dev-inspector-mcp";
|
|
105
|
+
const PLUGIN_VAR_NAME$2 = "DevInspector";
|
|
106
|
+
function transformViteConfig(code, options) {
|
|
201
107
|
try {
|
|
202
|
-
|
|
203
|
-
if (hasDevInspectorImport(code)) return {
|
|
108
|
+
if (code.includes(PLUGIN_IMPORT$2)) return {
|
|
204
109
|
success: true,
|
|
205
110
|
modified: false,
|
|
206
111
|
message: "DevInspector is already configured in this file"
|
|
@@ -214,7 +119,7 @@ function transformViteConfig(options) {
|
|
|
214
119
|
let pluginsArrayStart = -1;
|
|
215
120
|
let firstPluginStart = -1;
|
|
216
121
|
let hasPluginsArray = false;
|
|
217
|
-
traverse(ast, {
|
|
122
|
+
traverse$2(ast, {
|
|
218
123
|
ImportDeclaration(path$1) {
|
|
219
124
|
if (path$1.node.loc) lastImportEnd = Math.max(lastImportEnd, path$1.node.loc.end.line);
|
|
220
125
|
},
|
|
@@ -229,18 +134,16 @@ function transformViteConfig(options) {
|
|
|
229
134
|
}
|
|
230
135
|
}
|
|
231
136
|
});
|
|
232
|
-
const
|
|
233
|
-
const importLine = `import ${PLUGIN_VAR_NAME} from '${PLUGIN_IMPORT}';\n`;
|
|
137
|
+
const importLine = `import ${PLUGIN_VAR_NAME$2} from '${PLUGIN_IMPORT$2}';\n`;
|
|
234
138
|
if (lastImportEnd > 0) {
|
|
235
|
-
|
|
236
|
-
for (let i = 0; i < lastImportEnd; i++) insertPos += lines[i].length + 1;
|
|
139
|
+
const insertPos = getInsertPosition(code, lastImportEnd);
|
|
237
140
|
s.appendLeft(insertPos, importLine);
|
|
238
141
|
} else s.prepend(importLine);
|
|
239
142
|
if (hasPluginsArray && firstPluginStart > -1) {
|
|
240
|
-
const pluginCall = `${PLUGIN_VAR_NAME}.vite({
|
|
143
|
+
const pluginCall = `${PLUGIN_VAR_NAME$2}.vite(${getPluginOptions(options, 6)}),\n `;
|
|
241
144
|
s.appendLeft(firstPluginStart, pluginCall);
|
|
242
145
|
} else if (hasPluginsArray && pluginsArrayStart > -1) {
|
|
243
|
-
const pluginCall = `\n ${PLUGIN_VAR_NAME}.vite({
|
|
146
|
+
const pluginCall = `\n ${PLUGIN_VAR_NAME$2}.vite(${getPluginOptions(options, 6)}),\n `;
|
|
244
147
|
s.appendLeft(pluginsArrayStart + 1, pluginCall);
|
|
245
148
|
} else return {
|
|
246
149
|
success: false,
|
|
@@ -263,14 +166,22 @@ function transformViteConfig(options) {
|
|
|
263
166
|
};
|
|
264
167
|
}
|
|
265
168
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
169
|
+
function detectViteConfig(cwd) {
|
|
170
|
+
return detectConfigFile(cwd, [
|
|
171
|
+
"vite.config.ts",
|
|
172
|
+
"vite.config.js",
|
|
173
|
+
"vite.config.mjs"
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/commands/setup/frameworks/webpack.ts
|
|
179
|
+
const traverse$1 = _babel_traverse.default.default || _babel_traverse.default;
|
|
180
|
+
const PLUGIN_IMPORT$1 = "@mcpc-tech/unplugin-dev-inspector-mcp";
|
|
181
|
+
const PLUGIN_VAR_NAME$1 = "DevInspector";
|
|
182
|
+
function transformWebpackConfig(code, options) {
|
|
271
183
|
try {
|
|
272
|
-
|
|
273
|
-
if (hasDevInspectorImport(code)) return {
|
|
184
|
+
if (code.includes(PLUGIN_IMPORT$1)) return {
|
|
274
185
|
success: true,
|
|
275
186
|
modified: false,
|
|
276
187
|
message: "DevInspector is already configured in this file"
|
|
@@ -283,7 +194,7 @@ function transformWebpackConfig(options) {
|
|
|
283
194
|
});
|
|
284
195
|
let lastImportEnd = 0;
|
|
285
196
|
let pluginsArrayStart = -1;
|
|
286
|
-
traverse(ast, {
|
|
197
|
+
traverse$1(ast, {
|
|
287
198
|
ImportDeclaration(path$1) {
|
|
288
199
|
if (path$1.node.loc) lastImportEnd = Math.max(lastImportEnd, path$1.node.loc.end.line);
|
|
289
200
|
},
|
|
@@ -296,15 +207,13 @@ function transformWebpackConfig(options) {
|
|
|
296
207
|
}
|
|
297
208
|
}
|
|
298
209
|
});
|
|
299
|
-
const
|
|
300
|
-
const importLine = isESM ? `import ${PLUGIN_VAR_NAME} from '${PLUGIN_IMPORT}';\n` : `const ${PLUGIN_VAR_NAME} = require('${PLUGIN_IMPORT}');\n`;
|
|
210
|
+
const importLine = isESM ? `import ${PLUGIN_VAR_NAME$1} from '${PLUGIN_IMPORT$1}';\n` : `const ${PLUGIN_VAR_NAME$1} = require('${PLUGIN_IMPORT$1}');\n`;
|
|
301
211
|
if (lastImportEnd > 0) {
|
|
302
|
-
|
|
303
|
-
for (let i = 0; i < lastImportEnd; i++) insertPos += lines[i].length + 1;
|
|
212
|
+
const insertPos = getInsertPosition(code, lastImportEnd);
|
|
304
213
|
s.appendLeft(insertPos, importLine);
|
|
305
214
|
} else s.prepend(importLine);
|
|
306
215
|
if (pluginsArrayStart > -1) {
|
|
307
|
-
const pluginCall = `\n ${PLUGIN_VAR_NAME}.webpack({
|
|
216
|
+
const pluginCall = `\n ${PLUGIN_VAR_NAME$1}.webpack(${getPluginOptions(options, 6)}),`;
|
|
308
217
|
s.appendLeft(pluginsArrayStart + 1, pluginCall);
|
|
309
218
|
} else return {
|
|
310
219
|
success: false,
|
|
@@ -327,14 +236,23 @@ function transformWebpackConfig(options) {
|
|
|
327
236
|
};
|
|
328
237
|
}
|
|
329
238
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
239
|
+
function detectWebpackConfig(cwd) {
|
|
240
|
+
return detectConfigFile(cwd, [
|
|
241
|
+
"webpack.config.ts",
|
|
242
|
+
"webpack.config.js",
|
|
243
|
+
"webpack.config.cjs",
|
|
244
|
+
"webpack.config.mjs"
|
|
245
|
+
]);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/commands/setup/frameworks/nextjs.ts
|
|
250
|
+
const traverse = _babel_traverse.default.default || _babel_traverse.default;
|
|
251
|
+
const PLUGIN_IMPORT = "@mcpc-tech/unplugin-dev-inspector-mcp";
|
|
252
|
+
const PLUGIN_VAR_NAME = "DevInspector";
|
|
253
|
+
function transformNextConfig(code, _options) {
|
|
335
254
|
try {
|
|
336
|
-
|
|
337
|
-
if (hasDevInspectorImport(code)) return {
|
|
255
|
+
if (code.includes(PLUGIN_IMPORT)) return {
|
|
338
256
|
success: true,
|
|
339
257
|
modified: false,
|
|
340
258
|
message: "DevInspector is already configured in this file"
|
|
@@ -347,6 +265,7 @@ function transformNextConfig(options) {
|
|
|
347
265
|
let lastImportEnd = 0;
|
|
348
266
|
let nextConfigStart = -1;
|
|
349
267
|
let hasWebpackProperty = false;
|
|
268
|
+
let hasTurbopackProperty = false;
|
|
350
269
|
traverse(ast, {
|
|
351
270
|
ImportDeclaration(path$1) {
|
|
352
271
|
if (path$1.node.loc) lastImportEnd = Math.max(lastImportEnd, path$1.node.loc.end.line);
|
|
@@ -355,25 +274,36 @@ function transformNextConfig(options) {
|
|
|
355
274
|
if (path$1.node.id.type === "Identifier" && path$1.node.id.name === "nextConfig" && path$1.node.init?.type === "ObjectExpression") {
|
|
356
275
|
if (path$1.node.init.start !== null && path$1.node.init.start !== void 0) nextConfigStart = path$1.node.init.start;
|
|
357
276
|
path$1.node.init.properties.forEach((prop) => {
|
|
358
|
-
if (prop.type === "ObjectProperty" && prop.key.type === "Identifier"
|
|
277
|
+
if (prop.type === "ObjectProperty" && prop.key.type === "Identifier") {
|
|
278
|
+
if (prop.key.name === "webpack") hasWebpackProperty = true;
|
|
279
|
+
if (prop.key.name === "turbopack") hasTurbopackProperty = true;
|
|
280
|
+
}
|
|
359
281
|
});
|
|
360
282
|
}
|
|
361
283
|
}
|
|
362
284
|
});
|
|
363
|
-
const
|
|
364
|
-
const importLine = `import ${PLUGIN_VAR_NAME} from '${PLUGIN_IMPORT}';\n`;
|
|
285
|
+
const importLine = `import ${PLUGIN_VAR_NAME}, { turbopackDevInspector } from '${PLUGIN_IMPORT}';\n`;
|
|
365
286
|
if (lastImportEnd > 0) {
|
|
366
|
-
|
|
367
|
-
for (let i = 0; i < lastImportEnd; i++) insertPos += lines[i].length + 1;
|
|
287
|
+
const insertPos = getInsertPosition(code, lastImportEnd);
|
|
368
288
|
s.appendLeft(insertPos, importLine);
|
|
369
289
|
} else s.prepend(importLine);
|
|
370
|
-
if (nextConfigStart > -1 && !hasWebpackProperty) {
|
|
371
|
-
const
|
|
290
|
+
if (nextConfigStart > -1 && !hasWebpackProperty && !hasTurbopackProperty) {
|
|
291
|
+
const pluginOptions = "{ enabled: true }";
|
|
292
|
+
const webpackConfig = `
|
|
293
|
+
webpack: (config) => {
|
|
294
|
+
config.plugins.push(
|
|
295
|
+
${PLUGIN_VAR_NAME}.webpack(${pluginOptions})
|
|
296
|
+
);
|
|
297
|
+
return config;
|
|
298
|
+
},
|
|
299
|
+
turbopack: {
|
|
300
|
+
rules: turbopackDevInspector(${pluginOptions}),
|
|
301
|
+
},`;
|
|
372
302
|
s.appendLeft(nextConfigStart + 1, webpackConfig);
|
|
373
|
-
} else if (hasWebpackProperty) return {
|
|
303
|
+
} else if (hasWebpackProperty || hasTurbopackProperty) return {
|
|
374
304
|
success: false,
|
|
375
305
|
modified: false,
|
|
376
|
-
message: "
|
|
306
|
+
message: `${hasWebpackProperty ? "webpack" : "turbopack"} property already exists. Please add DevInspector manually to avoid conflicts`
|
|
377
307
|
};
|
|
378
308
|
else return {
|
|
379
309
|
success: false,
|
|
@@ -396,33 +326,13 @@ function transformNextConfig(options) {
|
|
|
396
326
|
};
|
|
397
327
|
}
|
|
398
328
|
}
|
|
399
|
-
|
|
400
|
-
* Main transform function that routes to the appropriate transformer
|
|
401
|
-
*/
|
|
402
|
-
function transformConfig(options) {
|
|
403
|
-
switch (options.bundler) {
|
|
404
|
-
case "vite": return transformViteConfig(options);
|
|
405
|
-
case "webpack": return transformWebpackConfig(options);
|
|
406
|
-
case "nextjs": return transformNextConfig(options);
|
|
407
|
-
default: return {
|
|
408
|
-
success: false,
|
|
409
|
-
modified: false,
|
|
410
|
-
error: `Unknown bundler type: ${options.bundler}`,
|
|
411
|
-
message: "Unsupported bundler type"
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
/**
|
|
416
|
-
* Transform entry file to add DevInspector import
|
|
417
|
-
*/
|
|
418
|
-
function transformEntryFile(options) {
|
|
419
|
-
const { entryPath } = options;
|
|
329
|
+
function transformNextLayout(code) {
|
|
420
330
|
try {
|
|
421
|
-
const
|
|
422
|
-
if (code.includes("
|
|
331
|
+
const COMPONENT_IMPORT = "@mcpc-tech/unplugin-dev-inspector-mcp/next";
|
|
332
|
+
if (code.includes("DevInspector") || code.includes(COMPONENT_IMPORT)) return {
|
|
423
333
|
success: true,
|
|
424
334
|
modified: false,
|
|
425
|
-
message: "DevInspector is already
|
|
335
|
+
message: "DevInspector component is already in this file"
|
|
426
336
|
};
|
|
427
337
|
const s = new magic_string.default(code);
|
|
428
338
|
const ast = (0, _babel_parser.parse)(code, {
|
|
@@ -430,88 +340,55 @@ function transformEntryFile(options) {
|
|
|
430
340
|
plugins: ["typescript", "jsx"]
|
|
431
341
|
});
|
|
432
342
|
let lastImportEnd = 0;
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
343
|
+
let bodyStart = -1;
|
|
344
|
+
traverse(ast, {
|
|
345
|
+
ImportDeclaration(path$1) {
|
|
346
|
+
if (path$1.node.loc) lastImportEnd = Math.max(lastImportEnd, path$1.node.loc.end.line);
|
|
347
|
+
},
|
|
348
|
+
JSXElement(path$1) {
|
|
349
|
+
if (path$1.node.openingElement.name.type === "JSXIdentifier" && path$1.node.openingElement.name.name === "body" && path$1.node.start !== null) {
|
|
350
|
+
const openingEnd = path$1.node.openingElement.end;
|
|
351
|
+
if (openingEnd !== null && openingEnd !== void 0) bodyStart = openingEnd;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
const importLine = `import { DevInspector } from "${COMPONENT_IMPORT}";\n`;
|
|
438
356
|
if (lastImportEnd > 0) {
|
|
439
|
-
|
|
440
|
-
for (let i = 0; i < lastImportEnd; i++) insertPos += lines[i].length + 1;
|
|
357
|
+
const insertPos = getInsertPosition(code, lastImportEnd);
|
|
441
358
|
s.appendLeft(insertPos, importLine);
|
|
442
359
|
} else s.prepend(importLine);
|
|
360
|
+
if (bodyStart > -1) s.appendLeft(bodyStart, "\n <DevInspector />");
|
|
361
|
+
else return {
|
|
362
|
+
success: false,
|
|
363
|
+
modified: false,
|
|
364
|
+
error: "Could not find <body> element",
|
|
365
|
+
message: "Please add <DevInspector /> manually to your layout"
|
|
366
|
+
};
|
|
443
367
|
return {
|
|
444
368
|
success: true,
|
|
445
369
|
modified: true,
|
|
446
370
|
code: s.toString(),
|
|
447
|
-
message: "Successfully added DevInspector
|
|
371
|
+
message: "Successfully added DevInspector component to layout"
|
|
448
372
|
};
|
|
449
373
|
} catch (error) {
|
|
450
374
|
return {
|
|
451
375
|
success: false,
|
|
452
376
|
modified: false,
|
|
453
377
|
error: error instanceof Error ? error.message : String(error),
|
|
454
|
-
message: "Failed to transform
|
|
378
|
+
message: "Failed to transform layout file"
|
|
455
379
|
};
|
|
456
380
|
}
|
|
457
381
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
while (current !== root) {
|
|
465
|
-
if ((0, fs.existsSync)((0, path.join)(current, "pnpm-lock.yaml"))) return "pnpm";
|
|
466
|
-
if ((0, fs.existsSync)((0, path.join)(current, "yarn.lock"))) return "yarn";
|
|
467
|
-
if ((0, fs.existsSync)((0, path.join)(current, "bun.lockb"))) return "bun";
|
|
468
|
-
if ((0, fs.existsSync)((0, path.join)(current, "package-lock.json"))) return "npm";
|
|
469
|
-
const parent = (0, path.dirname)(current);
|
|
470
|
-
if (parent === current) break;
|
|
471
|
-
current = parent;
|
|
472
|
-
}
|
|
473
|
-
const userAgent = process.env.npm_config_user_agent;
|
|
474
|
-
if (userAgent) {
|
|
475
|
-
if (userAgent.startsWith("pnpm")) return "pnpm";
|
|
476
|
-
if (userAgent.startsWith("yarn")) return "yarn";
|
|
477
|
-
if (userAgent.startsWith("bun")) return "bun";
|
|
478
|
-
}
|
|
479
|
-
return "npm";
|
|
480
|
-
}
|
|
481
|
-
function getInstallCommand(pm, packageName, dev = true) {
|
|
482
|
-
const flags = dev ? "-D" : "";
|
|
483
|
-
switch (pm) {
|
|
484
|
-
case "npm": return `npm install ${flags} ${packageName}`;
|
|
485
|
-
case "yarn": return `yarn add ${flags} ${packageName}`;
|
|
486
|
-
case "pnpm": return `pnpm add ${flags} ${packageName}`;
|
|
487
|
-
case "bun": return `bun add ${flags} ${packageName}`;
|
|
488
|
-
default: return `npm install ${flags} ${packageName}`;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
function installPackage(packageName, dev = true) {
|
|
492
|
-
const pm = detectPackageManager();
|
|
493
|
-
const command = getInstallCommand(pm, packageName, dev);
|
|
494
|
-
console.log(`\n📦 Installing ${packageName} with ${pm}...`);
|
|
495
|
-
console.log(` Running: ${command}`);
|
|
496
|
-
try {
|
|
497
|
-
(0, child_process.execSync)(command, { stdio: "inherit" });
|
|
498
|
-
console.log(`✅ Successfully installed ${packageName}`);
|
|
499
|
-
return true;
|
|
500
|
-
} catch (error) {
|
|
501
|
-
console.error(`❌ Failed to install ${packageName}`);
|
|
502
|
-
return false;
|
|
503
|
-
}
|
|
382
|
+
function detectNextConfig(cwd) {
|
|
383
|
+
return detectConfigFile(cwd, [
|
|
384
|
+
"next.config.ts",
|
|
385
|
+
"next.config.js",
|
|
386
|
+
"next.config.mjs"
|
|
387
|
+
]);
|
|
504
388
|
}
|
|
505
389
|
|
|
506
390
|
//#endregion
|
|
507
|
-
//#region src/
|
|
508
|
-
/**
|
|
509
|
-
* CLI for dev-inspector
|
|
510
|
-
*
|
|
511
|
-
* Commands:
|
|
512
|
-
* setup - Add DevInspector to your bundler config
|
|
513
|
-
* server - Start standalone MCP server (default)
|
|
514
|
-
*/
|
|
391
|
+
//#region src/commands/setup/index.ts
|
|
515
392
|
async function runSetupCommand() {
|
|
516
393
|
const args = process.argv.slice(3);
|
|
517
394
|
let dryRun = false;
|
|
@@ -529,31 +406,7 @@ async function runSetupCommand() {
|
|
|
529
406
|
bundlerType = args[i + 1];
|
|
530
407
|
i++;
|
|
531
408
|
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
532
|
-
|
|
533
|
-
╔══════════════════════════════════════════════════════════╗
|
|
534
|
-
║ 🔧 DevInspector Setup Command ║
|
|
535
|
-
╚══════════════════════════════════════════════════════════╝
|
|
536
|
-
|
|
537
|
-
Usage:
|
|
538
|
-
npx @mcpc-tech/unplugin-dev-inspector-mcp setup [options]
|
|
539
|
-
|
|
540
|
-
Options:
|
|
541
|
-
--config <path> Specify config file path (auto-detect by default)
|
|
542
|
-
--entry <path> Specify entry file path to add import (optional)
|
|
543
|
-
--bundler <type> Specify bundler type: vite, webpack, nextjs
|
|
544
|
-
--dry-run Preview changes without applying them
|
|
545
|
-
--help, -h Show this help message
|
|
546
|
-
|
|
547
|
-
Examples:
|
|
548
|
-
# Auto-detect and setup
|
|
549
|
-
npx @mcpc-tech/unplugin-dev-inspector-mcp setup
|
|
550
|
-
|
|
551
|
-
# Setup defining entry file (for React Router v7 / non-HTML apps)
|
|
552
|
-
npx @mcpc-tech/unplugin-dev-inspector-mcp setup --entry src/main.tsx
|
|
553
|
-
|
|
554
|
-
# Preview changes without applying
|
|
555
|
-
npx @mcpc-tech/unplugin-dev-inspector-mcp setup --dry-run
|
|
556
|
-
`);
|
|
409
|
+
printHelp();
|
|
557
410
|
process.exit(0);
|
|
558
411
|
}
|
|
559
412
|
console.log(`
|
|
@@ -562,107 +415,287 @@ Examples:
|
|
|
562
415
|
╚══════════════════════════════════════════════════════════╝
|
|
563
416
|
`);
|
|
564
417
|
try {
|
|
565
|
-
|
|
418
|
+
const cwd = process.cwd();
|
|
419
|
+
let selectedConfigPath = null;
|
|
420
|
+
let selectedBundler = null;
|
|
421
|
+
const frameworks = [
|
|
422
|
+
{
|
|
423
|
+
type: "vite",
|
|
424
|
+
detect: detectViteConfig,
|
|
425
|
+
transform: transformViteConfig
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
type: "webpack",
|
|
429
|
+
detect: detectWebpackConfig,
|
|
430
|
+
transform: transformWebpackConfig
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
type: "nextjs",
|
|
434
|
+
detect: detectNextConfig,
|
|
435
|
+
transform: transformNextConfig
|
|
436
|
+
}
|
|
437
|
+
];
|
|
438
|
+
const validBundlers = [
|
|
439
|
+
"vite",
|
|
440
|
+
"webpack",
|
|
441
|
+
"nextjs"
|
|
442
|
+
];
|
|
566
443
|
if (configPath) {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
444
|
+
if (!(0, fs.existsSync)(configPath)) {
|
|
445
|
+
console.error(`❌ Provided config file does not exist: ${configPath}`);
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
selectedConfigPath = configPath;
|
|
449
|
+
const filename = configPath.toLowerCase();
|
|
450
|
+
if (/vite\.config\.(ts|js|mjs)$/i.test(filename)) selectedBundler = "vite";
|
|
451
|
+
else if (/webpack\.config\.(ts|js|cjs|mjs)$/i.test(filename)) selectedBundler = "webpack";
|
|
452
|
+
else if (/next\.config\.(ts|js|mjs)$/i.test(filename)) selectedBundler = "nextjs";
|
|
453
|
+
if (!selectedBundler) {
|
|
454
|
+
console.error(`❌ Could not determine bundler type from config path: ${configPath}`);
|
|
455
|
+
console.error(`💡 Use --bundler flag to specify: ${validBundlers.join(", ")}`);
|
|
570
456
|
process.exit(1);
|
|
571
457
|
}
|
|
572
458
|
} else if (bundlerType) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
console.error(
|
|
459
|
+
if (!validBundlers.includes(bundlerType)) {
|
|
460
|
+
console.error(`❌ Invalid bundler type: ${bundlerType}`);
|
|
461
|
+
console.error(`💡 Valid options: ${validBundlers.join(", ")}`);
|
|
576
462
|
process.exit(1);
|
|
577
463
|
}
|
|
464
|
+
selectedBundler = bundlerType;
|
|
465
|
+
const fw = frameworks.find((f) => f.type === bundlerType);
|
|
466
|
+
if (fw) selectedConfigPath = fw.detect(cwd);
|
|
578
467
|
} else {
|
|
579
|
-
const detected =
|
|
468
|
+
const detected = frameworks.map((f) => ({
|
|
469
|
+
type: f.type,
|
|
470
|
+
path: f.detect(cwd)
|
|
471
|
+
})).filter((d) => d.path !== null);
|
|
580
472
|
if (detected.length === 0) {
|
|
581
473
|
console.error("❌ No bundler config files found in current directory");
|
|
582
|
-
console.log("\nSupported configs: vite.config.{ts,js,mjs}, webpack.config.{ts,js}, next.config.{ts,js,mjs}");
|
|
583
474
|
process.exit(1);
|
|
584
475
|
}
|
|
585
476
|
if (detected.length > 1) {
|
|
586
477
|
console.log("📦 Multiple configs detected:");
|
|
587
|
-
detected.forEach((
|
|
588
|
-
console.log(` ${i + 1}. ${config.bundler}: ${config.path}`);
|
|
589
|
-
});
|
|
478
|
+
detected.forEach((d, i) => console.log(` ${i + 1}. ${d.type}: ${d.path}`));
|
|
590
479
|
console.log("\n💡 Tip: Use --bundler or --config to specify which one to transform");
|
|
591
|
-
targetConfig = detected[0];
|
|
592
|
-
console.log(`\n🎯 Using: ${targetConfig.bundler} (${targetConfig.path})`);
|
|
593
|
-
} else {
|
|
594
|
-
targetConfig = detected[0];
|
|
595
|
-
console.log(`🎯 Detected: ${targetConfig.bundler} config at ${targetConfig.path}`);
|
|
596
480
|
}
|
|
481
|
+
selectedBundler = detected[0].type;
|
|
482
|
+
selectedConfigPath = detected[0].path;
|
|
483
|
+
console.log(`🎯 Using: ${selectedBundler} (${selectedConfigPath})`);
|
|
597
484
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
485
|
+
if (!selectedConfigPath || !selectedBundler) {
|
|
486
|
+
console.error(`❌ Could not find or detect ${bundlerType || "any"} configuration`);
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
console.log(`\n${dryRun ? "🔍 Previewing" : "🔧 Transforming"} ${selectedBundler} config...`);
|
|
490
|
+
const code = (0, fs.readFileSync)(selectedConfigPath, "utf-8");
|
|
491
|
+
const options = {
|
|
492
|
+
dryRun,
|
|
493
|
+
configPath: selectedConfigPath,
|
|
494
|
+
entryPath
|
|
495
|
+
};
|
|
496
|
+
const framework = frameworks.find((f) => f.type === selectedBundler);
|
|
497
|
+
if (!framework) {
|
|
498
|
+
console.error(`❌ Unsupported bundler: ${selectedBundler}`);
|
|
499
|
+
process.exit(1);
|
|
500
|
+
}
|
|
501
|
+
const result = framework.transform(code, options);
|
|
604
502
|
if (!result.success) {
|
|
605
503
|
console.error(`\n❌ ${result.message}`);
|
|
606
504
|
if (result.error) console.error(` Error: ${result.error}`);
|
|
607
505
|
process.exit(1);
|
|
608
506
|
}
|
|
609
|
-
let entryResult;
|
|
610
|
-
if (entryPath) {
|
|
611
|
-
console.log(`\n${dryRun ? "🔍 Previewing" : "🔧 Transforming"} entry file: ${entryPath}...`);
|
|
612
|
-
const { transformEntryFile: transformEntryFile$1 } = await Promise.resolve().then(() => require("./codemod-transformer.cjs"));
|
|
613
|
-
entryResult = transformEntryFile$1({
|
|
614
|
-
entryPath,
|
|
615
|
-
dryRun
|
|
616
|
-
});
|
|
617
|
-
if (!entryResult.success) {
|
|
618
|
-
console.error(`\n❌ ${entryResult.message}`);
|
|
619
|
-
if (entryResult.error) console.error(` Error: ${entryResult.error}`);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
507
|
if (dryRun) {
|
|
623
|
-
|
|
624
|
-
console.log("\n📄 Preview of config changes:");
|
|
625
|
-
console.log("─".repeat(60));
|
|
626
|
-
console.log(result.code);
|
|
627
|
-
console.log("─".repeat(60));
|
|
628
|
-
} else console.log(`\n✅ Config: ${result.message}`);
|
|
629
|
-
if (entryPath && entryResult) {
|
|
630
|
-
if (entryResult.modified) {
|
|
631
|
-
console.log("\n📄 Preview of entry file changes:");
|
|
632
|
-
console.log("─".repeat(60));
|
|
633
|
-
console.log(entryResult.code);
|
|
634
|
-
console.log("─".repeat(60));
|
|
635
|
-
} else if (entryResult.success) console.log(`\n✅ Entry file: ${entryResult.message}`);
|
|
636
|
-
}
|
|
637
|
-
console.log("\n💡 Run without --dry-run to apply these changes");
|
|
508
|
+
showPreview(result);
|
|
638
509
|
process.exit(0);
|
|
639
510
|
}
|
|
640
511
|
const installed = installPackage("@mcpc-tech/unplugin-dev-inspector-mcp", true);
|
|
512
|
+
if (!installed) console.warn("⚠️ Package installation failed, but setup will continue with config transformation.");
|
|
641
513
|
if (result.modified) {
|
|
642
|
-
(0, fs.writeFileSync)(
|
|
514
|
+
(0, fs.writeFileSync)(selectedConfigPath, result.code, "utf-8");
|
|
643
515
|
console.log(`\n✅ ${result.message}`);
|
|
644
516
|
} else console.log(`\n✅ ${result.message}`);
|
|
645
|
-
if (
|
|
646
|
-
(0,
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
517
|
+
if (selectedBundler === "nextjs" && entryPath) {
|
|
518
|
+
const layoutPath = (0, path.resolve)(cwd, entryPath);
|
|
519
|
+
if (!(0, fs.existsSync)(layoutPath)) {
|
|
520
|
+
console.warn(`\n⚠️ Layout file not found: ${layoutPath}`);
|
|
521
|
+
console.warn(` Skipping layout transformation. Please add <DevInspector /> manually.`);
|
|
522
|
+
} else {
|
|
523
|
+
console.log(`\n🔧 Transforming layout file...`);
|
|
524
|
+
const layoutResult = transformNextLayout((0, fs.readFileSync)(layoutPath, "utf-8"));
|
|
525
|
+
if (layoutResult.success && layoutResult.modified) {
|
|
526
|
+
if (!dryRun) (0, fs.writeFileSync)(layoutPath, layoutResult.code, "utf-8");
|
|
527
|
+
console.log(`✅ ${layoutResult.message}`);
|
|
528
|
+
} else if (!layoutResult.success) {
|
|
529
|
+
console.warn(`⚠️ ${layoutResult.message}`);
|
|
530
|
+
if (layoutResult.error) console.warn(` ${layoutResult.error}`);
|
|
531
|
+
} else console.log(`ℹ️ ${layoutResult.message}`);
|
|
532
|
+
}
|
|
658
533
|
}
|
|
534
|
+
printNextSteps(selectedConfigPath, entryPath, selectedBundler, installed);
|
|
659
535
|
} catch (error) {
|
|
660
536
|
console.error("❌ Setup failed:", error instanceof Error ? error.message : error);
|
|
661
537
|
process.exit(1);
|
|
662
538
|
}
|
|
663
539
|
}
|
|
540
|
+
function printHelp() {
|
|
541
|
+
console.log(`
|
|
542
|
+
Usage:
|
|
543
|
+
npx @mcpc-tech/unplugin-dev-inspector-mcp setup [options]
|
|
544
|
+
|
|
545
|
+
Options:
|
|
546
|
+
--config <path> Specify config file path (auto-detect by default)
|
|
547
|
+
--entry <path> Specify entry file path to add import (optional)
|
|
548
|
+
--bundler <type> Specify bundler type: vite, webpack, nextjs
|
|
549
|
+
--dry-run Preview changes without applying them
|
|
550
|
+
--help, -h Show this help message
|
|
551
|
+
`);
|
|
552
|
+
}
|
|
553
|
+
function showPreview(result) {
|
|
554
|
+
if (result.modified) {
|
|
555
|
+
console.log("\n📄 Preview of config changes:");
|
|
556
|
+
console.log("─".repeat(60));
|
|
557
|
+
console.log(result.code);
|
|
558
|
+
console.log("─".repeat(60));
|
|
559
|
+
} else console.log(`\n✅ Config: ${result.message}`);
|
|
560
|
+
console.log("\n💡 Run without --dry-run to apply these changes");
|
|
561
|
+
}
|
|
562
|
+
function printNextSteps(configPath, entryPath, bundler, installed) {
|
|
563
|
+
console.log(`\n📝 Next steps:`);
|
|
564
|
+
if (!installed) {
|
|
565
|
+
console.log(` 1. Install the package manually: npm install -D @mcpc-tech/unplugin-dev-inspector-mcp`);
|
|
566
|
+
console.log(` 2. Review the changes in ${configPath} and package.json`);
|
|
567
|
+
console.log(` 3. Start your dev server`);
|
|
568
|
+
} else {
|
|
569
|
+
console.log(` 1. Review the changes in ${configPath} and package.json`);
|
|
570
|
+
console.log(` 2. Start your dev server`);
|
|
571
|
+
}
|
|
572
|
+
if (entryPath) {
|
|
573
|
+
console.log(`\n💡 Entry file specified: ${entryPath}`);
|
|
574
|
+
console.log(` This has been added to your config with autoInject: false`);
|
|
575
|
+
console.log(` No modifications were made to your entry file`);
|
|
576
|
+
}
|
|
577
|
+
if (bundler === "nextjs") {
|
|
578
|
+
console.log(`\n⚠️ Next.js 16+ uses Turbopack by default`);
|
|
579
|
+
console.log(` Turbopack mode requires running a standalone MCP server:`);
|
|
580
|
+
console.log(` `);
|
|
581
|
+
console.log(` Terminal 1: npm run dev`);
|
|
582
|
+
console.log(` Terminal 2: npx dev-inspector-server`);
|
|
583
|
+
console.log(` `);
|
|
584
|
+
console.log(` Or use concurrently: npx concurrently "npm run dev" "npx dev-inspector-server"`);
|
|
585
|
+
console.log(` (Webpack mode works without standalone server: npm run dev -- --webpack)`);
|
|
586
|
+
}
|
|
587
|
+
if (bundler === "vite") {
|
|
588
|
+
console.log(`\n⚠️ Important: DevInspector should be placed BEFORE framework plugins (react/vue/svelte)`);
|
|
589
|
+
console.log(` Please verify the plugin order in your config.`);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
//#endregion
|
|
594
|
+
//#region src/utils/standalone-server.ts
|
|
595
|
+
var StandaloneServer = class {
|
|
596
|
+
server;
|
|
597
|
+
middlewares = [];
|
|
598
|
+
port = 0;
|
|
599
|
+
host = "localhost";
|
|
600
|
+
stack = [];
|
|
601
|
+
constructor() {
|
|
602
|
+
this.server = node_http.default.createServer(async (req, res) => {
|
|
603
|
+
let index = 0;
|
|
604
|
+
const next = async () => {
|
|
605
|
+
if (index >= this.middlewares.length) {
|
|
606
|
+
if (!res.writableEnded) {
|
|
607
|
+
res.statusCode = 404;
|
|
608
|
+
res.end("Not Found");
|
|
609
|
+
}
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
const layer = this.middlewares[index++];
|
|
613
|
+
if ((req.url || "/").startsWith(layer.route)) try {
|
|
614
|
+
const originalUrl = req.url;
|
|
615
|
+
if (layer.route !== "/" && req.url) {}
|
|
616
|
+
await layer.handle(req, res, next);
|
|
617
|
+
if (layer.route !== "/") req.url = originalUrl;
|
|
618
|
+
} catch (error) {
|
|
619
|
+
console.error("Middleware error:", error);
|
|
620
|
+
if (!res.writableEnded) {
|
|
621
|
+
res.statusCode = 500;
|
|
622
|
+
res.end("Internal Server Error");
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
else next();
|
|
626
|
+
};
|
|
627
|
+
await next();
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
use(routeOrHandle, handle) {
|
|
631
|
+
let route = "/";
|
|
632
|
+
let handler;
|
|
633
|
+
if (typeof routeOrHandle === "string") {
|
|
634
|
+
route = routeOrHandle;
|
|
635
|
+
if (!handle) throw new Error("Handler is required when route is provided");
|
|
636
|
+
handler = handle;
|
|
637
|
+
} else handler = routeOrHandle;
|
|
638
|
+
this.middlewares.push({
|
|
639
|
+
route,
|
|
640
|
+
handle: handler
|
|
641
|
+
});
|
|
642
|
+
return this;
|
|
643
|
+
}
|
|
644
|
+
listen(...args) {
|
|
645
|
+
return this.server.listen(...args);
|
|
646
|
+
}
|
|
647
|
+
async start(options = {}) {
|
|
648
|
+
const startPort = options.port || 8888;
|
|
649
|
+
this.host = options.host || "localhost";
|
|
650
|
+
for (let port = startPort; port < startPort + 100; port++) try {
|
|
651
|
+
await new Promise((resolve$2, reject) => {
|
|
652
|
+
this.server.listen(port, this.host, () => {
|
|
653
|
+
this.port = port;
|
|
654
|
+
resolve$2();
|
|
655
|
+
});
|
|
656
|
+
this.server.on("error", (err) => {
|
|
657
|
+
if (err.code === "EADDRINUSE") {
|
|
658
|
+
this.server.close();
|
|
659
|
+
reject(err);
|
|
660
|
+
} else reject(err);
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
return {
|
|
664
|
+
host: this.host,
|
|
665
|
+
port: this.port
|
|
666
|
+
};
|
|
667
|
+
} catch (error) {
|
|
668
|
+
if (error.code !== "EADDRINUSE") throw error;
|
|
669
|
+
}
|
|
670
|
+
throw new Error(`Could not find a free port starting from ${startPort}`);
|
|
671
|
+
}
|
|
672
|
+
close() {
|
|
673
|
+
this.server.close();
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
let globalServer = null;
|
|
677
|
+
async function startStandaloneServer(options = {}) {
|
|
678
|
+
if (globalServer) return {
|
|
679
|
+
server: globalServer,
|
|
680
|
+
host: globalServer.host,
|
|
681
|
+
port: globalServer.port,
|
|
682
|
+
isNew: false
|
|
683
|
+
};
|
|
684
|
+
globalServer = new StandaloneServer();
|
|
685
|
+
const { host, port } = await globalServer.start(options);
|
|
686
|
+
return {
|
|
687
|
+
server: globalServer,
|
|
688
|
+
host,
|
|
689
|
+
port,
|
|
690
|
+
isNew: true
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
//#endregion
|
|
695
|
+
//#region src/commands/server/index.ts
|
|
696
|
+
require_config_updater.init_helpers();
|
|
664
697
|
async function runServerCommand() {
|
|
665
|
-
const args = process.argv.slice(
|
|
698
|
+
const args = process.argv.slice(3);
|
|
666
699
|
let port = 8888;
|
|
667
700
|
let host = "localhost";
|
|
668
701
|
for (let i = 0; i < args.length; i++) if (args[i] === "--port" && args[i + 1]) {
|
|
@@ -725,6 +758,16 @@ Example:
|
|
|
725
758
|
process.exit(1);
|
|
726
759
|
}
|
|
727
760
|
}
|
|
761
|
+
|
|
762
|
+
//#endregion
|
|
763
|
+
//#region src/cli.ts
|
|
764
|
+
/**
|
|
765
|
+
* CLI for dev-inspector
|
|
766
|
+
*
|
|
767
|
+
* Commands:
|
|
768
|
+
* setup - Add DevInspector to your bundler config
|
|
769
|
+
* server - Start standalone MCP server (default)
|
|
770
|
+
*/
|
|
728
771
|
async function main() {
|
|
729
772
|
const command = process.argv[2];
|
|
730
773
|
if (command === "setup") await runSetupCommand();
|
|
@@ -748,9 +791,4 @@ main();
|
|
|
748
791
|
|
|
749
792
|
//#endregion
|
|
750
793
|
exports.StandaloneServer = StandaloneServer;
|
|
751
|
-
exports.startStandaloneServer = startStandaloneServer;
|
|
752
|
-
exports.transformConfig = transformConfig;
|
|
753
|
-
exports.transformEntryFile = transformEntryFile;
|
|
754
|
-
exports.transformNextConfig = transformNextConfig;
|
|
755
|
-
exports.transformViteConfig = transformViteConfig;
|
|
756
|
-
exports.transformWebpackConfig = transformWebpackConfig;
|
|
794
|
+
exports.startStandaloneServer = startStandaloneServer;
|