chrome-devtools-mcp-for-extension 0.10.4 → 0.11.1
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.
|
@@ -280,29 +280,27 @@ export const askChatGPTWeb = defineTool({
|
|
|
280
280
|
if (deepResearchEnabled) {
|
|
281
281
|
response.appendResponseLine('✅ DeepResearchモード有効化完了');
|
|
282
282
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
283
|
-
// Verify mode was actually enabled (check for
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
return false;
|
|
283
|
+
// Verify mode was actually enabled (check for new UI indicators)
|
|
284
|
+
const verification = await page.evaluate(() => {
|
|
285
|
+
// Check placeholder text
|
|
286
|
+
const textarea = document.querySelector('textarea');
|
|
287
|
+
const placeholder = textarea?.getAttribute('placeholder') || '';
|
|
288
|
+
// Check for delete button
|
|
289
|
+
const deleteButton = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent?.includes('リサーチ:クリックして削除'));
|
|
290
|
+
// Check for sources button
|
|
291
|
+
const sourcesButton = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent?.includes('情報源'));
|
|
292
|
+
return {
|
|
293
|
+
hasCorrectPlaceholder: placeholder.includes('詳細なレポート') || placeholder.includes('リサーチ'),
|
|
294
|
+
hasDeleteButton: !!deleteButton,
|
|
295
|
+
hasSourcesButton: !!sourcesButton,
|
|
296
|
+
placeholder: placeholder
|
|
297
|
+
};
|
|
300
298
|
});
|
|
301
|
-
if (
|
|
302
|
-
response.appendResponseLine('✅ モード確認完了: DeepResearch
|
|
299
|
+
if (verification.hasCorrectPlaceholder || verification.hasDeleteButton) {
|
|
300
|
+
response.appendResponseLine('✅ モード確認完了: DeepResearch有効');
|
|
303
301
|
}
|
|
304
302
|
else {
|
|
305
|
-
response.appendResponseLine(
|
|
303
|
+
response.appendResponseLine(`⚠️ DeepResearchモードの確認に失敗しました(placeholder: ${verification.placeholder})`);
|
|
306
304
|
}
|
|
307
305
|
}
|
|
308
306
|
else {
|
|
@@ -313,27 +311,21 @@ export const askChatGPTWeb = defineTool({
|
|
|
313
311
|
// Step 4: Send question (with final mode verification)
|
|
314
312
|
if (useDeepResearch) {
|
|
315
313
|
const finalCheck = await page.evaluate(() => {
|
|
316
|
-
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
DEEP_RESEARCH_PATTERN.test(text + ' ' + ariaLabel));
|
|
326
|
-
});
|
|
327
|
-
return !!pillButton;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
return false;
|
|
314
|
+
// Check placeholder text
|
|
315
|
+
const textarea = document.querySelector('textarea');
|
|
316
|
+
const placeholder = textarea?.getAttribute('placeholder') || '';
|
|
317
|
+
// Check for delete button
|
|
318
|
+
const deleteButton = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent?.includes('リサーチ:クリックして削除'));
|
|
319
|
+
return {
|
|
320
|
+
isEnabled: placeholder.includes('詳細なレポート') || placeholder.includes('リサーチ') || !!deleteButton,
|
|
321
|
+
placeholder: placeholder
|
|
322
|
+
};
|
|
331
323
|
});
|
|
332
|
-
if (!finalCheck) {
|
|
333
|
-
response.appendResponseLine(
|
|
324
|
+
if (!finalCheck.isEnabled) {
|
|
325
|
+
response.appendResponseLine(`❌ エラー: DeepResearchモードが無効です。送信を中止します。(placeholder: ${finalCheck.placeholder})`);
|
|
334
326
|
return;
|
|
335
327
|
}
|
|
336
|
-
response.appendResponseLine('✅ 送信前確認: DeepResearch
|
|
328
|
+
response.appendResponseLine('✅ 送信前確認: DeepResearchモード有効');
|
|
337
329
|
}
|
|
338
330
|
response.appendResponseLine('質問を送信中...');
|
|
339
331
|
const questionSent = await page.evaluate((questionText) => {
|
|
@@ -266,44 +266,73 @@ async function detectDeepResearchMode(page) {
|
|
|
266
266
|
});
|
|
267
267
|
}
|
|
268
268
|
/**
|
|
269
|
-
* Enable DeepResearch mode
|
|
269
|
+
* Enable DeepResearch mode using new UI structure (2025-10)
|
|
270
|
+
* - Click "ファイルの追加など" button to open menu
|
|
271
|
+
* - Select "Deep Research" menuitemradio
|
|
272
|
+
* - Verify by checking placeholder and delete button
|
|
270
273
|
*/
|
|
271
274
|
async function enableDeepResearchMode(page, response) {
|
|
272
275
|
try {
|
|
273
276
|
response.appendResponseLine('DeepResearchモードを有効化中...');
|
|
274
|
-
// Step 1:
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
277
|
+
// Step 1: Find and click "ファイルの追加など" button (with haspopup="menu")
|
|
278
|
+
const menuButton = await page.evaluate(() => {
|
|
279
|
+
const buttons = Array.from(document.querySelectorAll('button[haspopup="menu"]'));
|
|
280
|
+
const targetButton = buttons.find(btn => {
|
|
281
|
+
const text = btn.textContent || '';
|
|
282
|
+
return text.includes('ファイルの追加') || text.includes('追加');
|
|
283
|
+
});
|
|
284
|
+
if (targetButton) {
|
|
285
|
+
targetButton.click();
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
return false;
|
|
289
|
+
});
|
|
290
|
+
if (!menuButton) {
|
|
291
|
+
return { success: false, error: '「ファイルの追加など」ボタンが見つかりません' };
|
|
278
292
|
}
|
|
279
|
-
|
|
280
|
-
response.appendResponseLine('✅ +ボタンをクリック');
|
|
293
|
+
response.appendResponseLine('✅ メニューボタンをクリック');
|
|
281
294
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
282
|
-
// Step 2: Deep Research menuitemradio
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
295
|
+
// Step 2: Click "Deep Research" menuitemradio from opened menu
|
|
296
|
+
const deepResearchClicked = await page.evaluate(() => {
|
|
297
|
+
const menuItems = Array.from(document.querySelectorAll('[role="menuitemradio"]'));
|
|
298
|
+
const deepResearchItem = menuItems.find(item => {
|
|
299
|
+
const text = item.textContent || '';
|
|
300
|
+
return text.includes('Deep Research') || text.includes('リサーチ');
|
|
301
|
+
});
|
|
302
|
+
if (deepResearchItem) {
|
|
303
|
+
deepResearchItem.click();
|
|
304
|
+
return true;
|
|
290
305
|
}
|
|
291
|
-
|
|
292
|
-
|
|
306
|
+
return false;
|
|
307
|
+
});
|
|
308
|
+
if (!deepResearchClicked) {
|
|
293
309
|
return { success: false, error: 'Deep Research menuitemradio が見つかりません' };
|
|
294
310
|
}
|
|
295
|
-
|
|
296
|
-
response.appendResponseLine('✅ Deep Research menuitemradio をクリック');
|
|
311
|
+
response.appendResponseLine('✅ Deep Research を選択');
|
|
297
312
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
298
|
-
// Step 3:
|
|
299
|
-
const verification = await
|
|
300
|
-
|
|
313
|
+
// Step 3: Verify DeepResearch mode is enabled
|
|
314
|
+
const verification = await page.evaluate(() => {
|
|
315
|
+
// Check placeholder text
|
|
316
|
+
const textarea = document.querySelector('textarea');
|
|
317
|
+
const placeholder = textarea?.getAttribute('placeholder') || '';
|
|
318
|
+
// Check for delete button
|
|
319
|
+
const deleteButton = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent?.includes('リサーチ:クリックして削除'));
|
|
320
|
+
// Check for sources button
|
|
321
|
+
const sourcesButton = Array.from(document.querySelectorAll('button')).find(btn => btn.textContent?.includes('情報源'));
|
|
322
|
+
return {
|
|
323
|
+
hasCorrectPlaceholder: placeholder.includes('詳細なレポート') || placeholder.includes('リサーチ'),
|
|
324
|
+
hasDeleteButton: !!deleteButton,
|
|
325
|
+
hasSourcesButton: !!sourcesButton,
|
|
326
|
+
placeholder: placeholder
|
|
327
|
+
};
|
|
328
|
+
});
|
|
329
|
+
if (!verification.hasCorrectPlaceholder && !verification.hasDeleteButton) {
|
|
301
330
|
return {
|
|
302
331
|
success: false,
|
|
303
|
-
error:
|
|
332
|
+
error: `DeepResearchモードの有効化に失敗しました(プレースホルダー: ${verification.placeholder})`,
|
|
304
333
|
};
|
|
305
334
|
}
|
|
306
|
-
response.appendResponseLine(`✅ モード確認完了: DeepResearch有効 (
|
|
335
|
+
response.appendResponseLine(`✅ モード確認完了: DeepResearch有効 (placeholder + delete button)`);
|
|
307
336
|
return { success: true };
|
|
308
337
|
}
|
|
309
338
|
catch (error) {
|
|
@@ -414,13 +443,28 @@ async function handleConversationLoop(page, response, maxTurns = 5) {
|
|
|
414
443
|
while (conversationTurns < maxTurns) {
|
|
415
444
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
416
445
|
const status = await page.evaluate(() => {
|
|
417
|
-
// Check for research progress indicator
|
|
446
|
+
// Check for research progress indicator (NEW UI: loading sources button)
|
|
447
|
+
const allButtons = Array.from(document.querySelectorAll('button'));
|
|
448
|
+
// NEW: Look for "〜を読み込んでいます X 情報源" button
|
|
449
|
+
const loadingSourcesButton = allButtons.find(btn => {
|
|
450
|
+
const text = btn.textContent || '';
|
|
451
|
+
return text.includes('読み込んでいます') && text.includes('情報源');
|
|
452
|
+
});
|
|
453
|
+
// Also check for "リサーチを開始しています" button
|
|
454
|
+
const researchStartButton = allButtons.find(btn => btn.textContent?.includes('リサーチを開始しています'));
|
|
455
|
+
if (loadingSourcesButton || researchStartButton) {
|
|
456
|
+
return {
|
|
457
|
+
phase: 'researching',
|
|
458
|
+
indicator: loadingSourcesButton ? 'loading sources' : 'starting research'
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
// Legacy indicators (fallback)
|
|
418
462
|
const progressIndicators = Array.from(document.querySelectorAll('div, span'));
|
|
419
463
|
const isResearching = progressIndicators.some((el) => el.textContent?.includes('リサーチ中') ||
|
|
420
464
|
el.textContent?.includes('Researching') ||
|
|
421
465
|
el.textContent?.includes('情報を収集中'));
|
|
422
466
|
if (isResearching) {
|
|
423
|
-
return { phase: 'researching' };
|
|
467
|
+
return { phase: 'researching', indicator: 'text match' };
|
|
424
468
|
}
|
|
425
469
|
// Check if ChatGPT is asking a clarifying question
|
|
426
470
|
const assistantMessages = document.querySelectorAll('[data-message-author-role="assistant"]');
|
|
@@ -430,8 +474,8 @@ async function handleConversationLoop(page, response, maxTurns = 5) {
|
|
|
430
474
|
const latestMessage = assistantMessages[assistantMessages.length - 1];
|
|
431
475
|
const messageText = latestMessage.textContent || '';
|
|
432
476
|
// Check if it's still streaming
|
|
433
|
-
const
|
|
434
|
-
const isStreaming =
|
|
477
|
+
const streamButtons = Array.from(document.querySelectorAll('button'));
|
|
478
|
+
const isStreaming = streamButtons.some((btn) => {
|
|
435
479
|
const text = btn.textContent || '';
|
|
436
480
|
const aria = btn.getAttribute('aria-label') || '';
|
|
437
481
|
return (text.includes('ストリーミングの停止') ||
|
|
@@ -501,22 +545,39 @@ async function monitorResearch(page, response, startTime) {
|
|
|
501
545
|
while (Date.now() - startTime < MAX_WAIT_TIME) {
|
|
502
546
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
503
547
|
const researchStatus = await page.evaluate(() => {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
548
|
+
const buttons = Array.from(document.querySelectorAll('button'));
|
|
549
|
+
// Check if still loading sources (NEW UI indicator)
|
|
550
|
+
const loadingSourcesButton = buttons.find(btn => {
|
|
551
|
+
const text = btn.textContent || '';
|
|
552
|
+
return text.includes('読み込んでいます') && text.includes('情報源');
|
|
553
|
+
});
|
|
554
|
+
// Check for "リサーチを開始しています" button
|
|
555
|
+
const researchStartButton = buttons.find(btn => btn.textContent?.includes('リサーチを開始しています'));
|
|
556
|
+
if (loadingSourcesButton || researchStartButton) {
|
|
557
|
+
const sourcesText = loadingSourcesButton?.textContent || '';
|
|
558
|
+
const match = sourcesText.match(/(\d+)\s*情報源/);
|
|
559
|
+
const sourcesCount = match ? match[1] : '?';
|
|
560
|
+
return {
|
|
561
|
+
completed: false,
|
|
562
|
+
stillResearching: true,
|
|
563
|
+
progress: `情報源読み込み中 (${sourcesCount}件)`
|
|
564
|
+
};
|
|
508
565
|
}
|
|
509
|
-
|
|
510
|
-
// Check if still researching
|
|
566
|
+
// Legacy: Check if still researching
|
|
511
567
|
const progressIndicators = Array.from(document.querySelectorAll('div, span'));
|
|
512
568
|
const isResearching = progressIndicators.some((el) => el.textContent?.includes('リサーチ中') ||
|
|
513
569
|
el.textContent?.includes('Researching') ||
|
|
514
570
|
el.textContent?.includes('情報を収集中'));
|
|
515
571
|
if (isResearching) {
|
|
516
|
-
return { completed: false, stillResearching: true };
|
|
572
|
+
return { completed: false, stillResearching: true, progress: 'リサーチ中' };
|
|
517
573
|
}
|
|
574
|
+
// Check if research completed
|
|
575
|
+
const assistantMessages = document.querySelectorAll('[data-message-author-role="assistant"]');
|
|
576
|
+
if (assistantMessages.length === 0) {
|
|
577
|
+
return { completed: false, stillResearching: true, progress: '待機中' };
|
|
578
|
+
}
|
|
579
|
+
const latestMessage = assistantMessages[assistantMessages.length - 1];
|
|
518
580
|
// Check if streaming
|
|
519
|
-
const buttons = Array.from(document.querySelectorAll('button'));
|
|
520
581
|
const isStreaming = buttons.some((btn) => {
|
|
521
582
|
const text = btn.textContent || '';
|
|
522
583
|
const aria = btn.getAttribute('aria-label') || '';
|
|
@@ -544,7 +605,8 @@ async function monitorResearch(page, response, startTime) {
|
|
|
544
605
|
progressCounter++;
|
|
545
606
|
if (progressCounter % 6 === 0) {
|
|
546
607
|
const elapsedSeconds = Math.floor((Date.now() - startTime) / 1000);
|
|
547
|
-
|
|
608
|
+
const progressText = researchStatus.progress || 'リサーチ継続中';
|
|
609
|
+
response.appendResponseLine(`⏱️ ${elapsedSeconds}秒経過 - ${progressText}...`);
|
|
548
610
|
}
|
|
549
611
|
}
|
|
550
612
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-devtools-mcp-for-extension",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
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": "./build/src/index.js",
|