chrome-devtools-mcp-for-extension 0.10.4 → 0.11.0
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.
|
@@ -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.0",
|
|
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",
|