chrome-devtools-mcp-for-extension 0.18.3 → 0.18.5
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.
|
@@ -10,6 +10,32 @@ import { ToolCategories } from './categories.js';
|
|
|
10
10
|
import { defineTool } from './ToolDefinition.js';
|
|
11
11
|
import { GEMINI_CONFIG } from '../config.js';
|
|
12
12
|
import { isLoginRequired } from '../login-helper.js';
|
|
13
|
+
/**
|
|
14
|
+
* Navigate with retry logic for handling ERR_ABORTED and other network errors
|
|
15
|
+
*/
|
|
16
|
+
async function navigateWithRetry(page, url, options = { waitUntil: 'networkidle2', maxRetries: 3 }) {
|
|
17
|
+
const { waitUntil, maxRetries = 3 } = options;
|
|
18
|
+
let lastError = null;
|
|
19
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
20
|
+
try {
|
|
21
|
+
await page.goto(url, { waitUntil, timeout: 30000 });
|
|
22
|
+
return; // Success
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
26
|
+
// Check if it's a retryable error
|
|
27
|
+
const isRetryable = lastError.message.includes('ERR_ABORTED') ||
|
|
28
|
+
lastError.message.includes('ERR_CONNECTION_RESET') ||
|
|
29
|
+
lastError.message.includes('net::ERR_');
|
|
30
|
+
if (!isRetryable || attempt === maxRetries) {
|
|
31
|
+
throw lastError;
|
|
32
|
+
}
|
|
33
|
+
// Wait before retry (exponential backoff)
|
|
34
|
+
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
throw lastError;
|
|
38
|
+
}
|
|
13
39
|
/**
|
|
14
40
|
* Path to store chat session data
|
|
15
41
|
*/
|
|
@@ -146,7 +172,7 @@ export const askGeminiWeb = defineTool({
|
|
|
146
172
|
const page = context.getSelectedPage();
|
|
147
173
|
try {
|
|
148
174
|
response.appendResponseLine('Geminiに接続中...');
|
|
149
|
-
await page
|
|
175
|
+
await navigateWithRetry(page, GEMINI_CONFIG.DEFAULT_URL, { waitUntil: 'networkidle2' });
|
|
150
176
|
const needsLogin = await isLoginRequired(page);
|
|
151
177
|
if (needsLogin) {
|
|
152
178
|
response.appendResponseLine('\n❌ Geminiへのログインが必要です');
|
|
@@ -163,7 +189,7 @@ export const askGeminiWeb = defineTool({
|
|
|
163
189
|
const sortedSessions = [...projectSessions].sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
|
|
164
190
|
const latestSession = sortedSessions[0];
|
|
165
191
|
response.appendResponseLine(`既存のチャットを使用: ${latestSession.url}`);
|
|
166
|
-
await page
|
|
192
|
+
await navigateWithRetry(page, latestSession.url, { waitUntil: 'networkidle2' });
|
|
167
193
|
sessionChatId = latestSession.chatId;
|
|
168
194
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
169
195
|
}
|
|
@@ -176,7 +202,7 @@ export const askGeminiWeb = defineTool({
|
|
|
176
202
|
}
|
|
177
203
|
if (isNewChat) {
|
|
178
204
|
response.appendResponseLine('新規チャットを作成中...');
|
|
179
|
-
await page
|
|
205
|
+
await navigateWithRetry(page, GEMINI_CONFIG.BASE_URL + 'app', { waitUntil: 'networkidle2' });
|
|
180
206
|
}
|
|
181
207
|
response.appendResponseLine('質問を送信中...');
|
|
182
208
|
// Input text using the textbox element
|
|
@@ -254,12 +280,17 @@ export const askGeminiWeb = defineTool({
|
|
|
254
280
|
const stopButton = buttons.find(b => b.textContent?.includes('回答を停止') ||
|
|
255
281
|
b.textContent?.includes('Stop') ||
|
|
256
282
|
b.getAttribute('aria-label')?.includes('Stop'));
|
|
283
|
+
// Check for "プロンプトを送信" button - this indicates response is complete
|
|
284
|
+
const sendButton = buttons.find(b => b.textContent?.includes('プロンプトを送信') ||
|
|
285
|
+
b.getAttribute('aria-label')?.includes('プロンプトを送信') ||
|
|
286
|
+
b.getAttribute('aria-label')?.includes('Send message'));
|
|
257
287
|
// Check for status text
|
|
258
288
|
const bodyText = document.body.innerText;
|
|
259
289
|
const isTyping = bodyText.includes('Gemini が入力中です') ||
|
|
260
290
|
bodyText.includes('Gemini is typing');
|
|
261
291
|
const isComplete = bodyText.includes('Gemini が回答しました') ||
|
|
262
|
-
bodyText.includes('Gemini has responded')
|
|
292
|
+
bodyText.includes('Gemini has responded') ||
|
|
293
|
+
!!sendButton; // "プロンプトを送信" button indicates completion
|
|
263
294
|
const isGenerating = !!stopButton || isTyping;
|
|
264
295
|
// Get the response content from model-response elements
|
|
265
296
|
const modelResponses = Array.from(document.querySelectorAll('model-response'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-devtools-mcp-for-extension",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.5",
|
|
4
4
|
"description": "MCP server for Chrome extension development with Web Store automation. Fork of chrome-devtools-mcp with extension-specific tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "./scripts/cli.mjs",
|