chrome-devtools-mcp-for-extension 0.9.24 → 0.9.26

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.
@@ -222,14 +222,62 @@ export const askChatGPTWeb = defineTool({
222
222
  });
223
223
  if (deepResearchEnabled) {
224
224
  response.appendResponseLine('✅ DeepResearchモード有効化完了');
225
- await new Promise((resolve) => setTimeout(resolve, 500));
225
+ await new Promise((resolve) => setTimeout(resolve, 1000));
226
+ // Verify mode was actually enabled (check for composer-pill button)
227
+ const verified = await page.evaluate(() => {
228
+ const DEEP_RESEARCH_PATTERN = /リサーチ|deep\s*research|ディープ\s*リサーチ|深度研究|深入研究/i;
229
+ const promptTextarea = document.querySelector('#prompt-textarea');
230
+ if (promptTextarea) {
231
+ const form = promptTextarea.closest('form');
232
+ if (form) {
233
+ const pillButton = Array.from(form.querySelectorAll('button')).find((btn) => {
234
+ const text = btn.textContent?.trim() || '';
235
+ const ariaLabel = btn.getAttribute('aria-label') || '';
236
+ return (btn.className.includes('composer-pill') &&
237
+ DEEP_RESEARCH_PATTERN.test(text + ' ' + ariaLabel));
238
+ });
239
+ return !!pillButton;
240
+ }
241
+ }
242
+ return false;
243
+ });
244
+ if (verified) {
245
+ response.appendResponseLine('✅ モード確認完了: DeepResearch有効(composer-pill検出)');
246
+ }
247
+ else {
248
+ response.appendResponseLine('⚠️ DeepResearchモードの確認に失敗しました');
249
+ }
226
250
  }
227
251
  else {
228
252
  response.appendResponseLine('⚠️ DeepResearchオプションが見つかりませんでした');
229
253
  }
230
254
  }
231
255
  }
232
- // Step 4: Send question
256
+ // Step 4: Send question (with final mode verification)
257
+ if (useDeepResearch) {
258
+ const finalCheck = await page.evaluate(() => {
259
+ const DEEP_RESEARCH_PATTERN = /リサーチ|deep\s*research|ディープ\s*リサーチ|深度研究|深入研究/i;
260
+ const promptTextarea = document.querySelector('#prompt-textarea');
261
+ if (promptTextarea) {
262
+ const form = promptTextarea.closest('form');
263
+ if (form) {
264
+ const pillButton = Array.from(form.querySelectorAll('button')).find((btn) => {
265
+ const text = btn.textContent?.trim() || '';
266
+ const ariaLabel = btn.getAttribute('aria-label') || '';
267
+ return (btn.className.includes('composer-pill') &&
268
+ DEEP_RESEARCH_PATTERN.test(text + ' ' + ariaLabel));
269
+ });
270
+ return !!pillButton;
271
+ }
272
+ }
273
+ return false;
274
+ });
275
+ if (!finalCheck) {
276
+ response.appendResponseLine('❌ エラー: DeepResearchモードが無効です(composer-pill未検出)。送信を中止します。');
277
+ return;
278
+ }
279
+ response.appendResponseLine('✅ 送信前確認: DeepResearchモード有効(composer-pill検出)');
280
+ }
233
281
  response.appendResponseLine('質問を送信中...');
234
282
  const questionSent = await page.evaluate((questionText) => {
235
283
  const prosemirror = document.querySelector('.ProseMirror[contenteditable="true"]');
@@ -129,33 +129,37 @@ function isCodeRelatedQuestion(question) {
129
129
  async function detectDeepResearchMode(page) {
130
130
  return await page.evaluate(() => {
131
131
  // Multi-language patterns for DeepResearch
132
- const DEEP_RESEARCH_PATTERN = /deep\s*research|ディープ\s*リサーチ|深度研究|深入研究/i;
133
- // Cache for performance (simple object-based cache instead of WeakRef for browser compatibility)
134
- const cache = { timestamp: 0 };
135
- const CACHE_TTL = 2000; // 2 seconds
136
- // Step 1: Find scoped root element first
137
- const findScopedRoot = () => {
138
- // Try conversation root selectors
139
- const candidates = [
140
- document.querySelector('[data-testid="conversation-turns"]'),
141
- document.querySelector('[role="main"]'),
142
- document.querySelector('main'),
143
- document.querySelector('[data-testid="conversation-root"]'),
144
- ];
145
- return candidates.find((el) => el !== null) || document.body;
146
- };
147
- const scopedRoot = findScopedRoot();
148
- if (!scopedRoot) {
149
- return { isEnabled: false };
132
+ const DEEP_RESEARCH_PATTERN = /リサーチ|deep\s*research|ディープ\s*リサーチ|深度研究|深入研究/i;
133
+ // Step 1: Check for the "リサーチ" pill button near prompt (MOST RELIABLE)
134
+ // When DeepResearch is ON, a pill button appears in the composer form
135
+ const promptTextarea = document.querySelector('#prompt-textarea');
136
+ if (promptTextarea) {
137
+ const form = promptTextarea.closest('form');
138
+ if (form) {
139
+ const pillButton = Array.from(form.querySelectorAll('button')).find((btn) => {
140
+ const text = btn.textContent?.trim() || '';
141
+ const ariaLabel = btn.getAttribute('aria-label') || '';
142
+ // Check for pill button with research text
143
+ return (btn.className.includes('composer-pill') &&
144
+ DEEP_RESEARCH_PATTERN.test(text + ' ' + ariaLabel));
145
+ });
146
+ if (pillButton) {
147
+ const text = pillButton.textContent?.trim() || '';
148
+ return {
149
+ isEnabled: true,
150
+ indicator: `composer-pill: "${text}"`,
151
+ };
152
+ }
153
+ }
150
154
  }
151
- // Step 2: Try data-testid selectors FIRST (most reliable)
155
+ // Step 2: Try data-testid selectors
152
156
  const dataTestIdSelectors = [
153
157
  '[data-testid*="deep-research"]',
154
158
  '[data-testid*="deepresearch"]',
155
159
  '[data-testid*="research-mode"]',
156
160
  ];
157
161
  for (const selector of dataTestIdSelectors) {
158
- const element = scopedRoot.querySelector(selector);
162
+ const element = document.querySelector(selector);
159
163
  if (element) {
160
164
  return {
161
165
  isEnabled: true,
@@ -170,7 +174,7 @@ async function detectDeepResearchMode(page) {
170
174
  '[aria-checked="true"][role="menuitemradio"]',
171
175
  ];
172
176
  for (const selector of ariaSelectors) {
173
- const elements = Array.from(scopedRoot.querySelectorAll(selector));
177
+ const elements = Array.from(document.querySelectorAll(selector));
174
178
  for (const element of elements) {
175
179
  const ariaLabel = element.getAttribute('aria-label') || '';
176
180
  const role = element.getAttribute('role') || '';
@@ -195,25 +199,13 @@ async function detectDeepResearchMode(page) {
195
199
  }
196
200
  }
197
201
  // Step 4: Text matching as LAST resort (least reliable)
198
- // Use cached result if available and fresh
199
- const now = Date.now();
200
- if (cache.element && now - cache.timestamp < CACHE_TTL) {
201
- return {
202
- isEnabled: true,
203
- indicator: 'cached indicator',
204
- };
205
- }
206
- // Search within scoped root only, not entire document
207
- const textElements = Array.from(scopedRoot.querySelectorAll('div, span, button'));
202
+ const textElements = Array.from(document.querySelectorAll('div, span, button'));
208
203
  for (const element of textElements) {
209
204
  const text = element.textContent || '';
210
205
  if (DEEP_RESEARCH_PATTERN.test(text)) {
211
- // Update cache
212
- cache.element = element;
213
- cache.timestamp = now;
214
206
  return {
215
207
  isEnabled: true,
216
- indicator: text.substring(0, 50),
208
+ indicator: `text match: ${text.substring(0, 50).trim()}`,
217
209
  };
218
210
  }
219
211
  }
@@ -226,32 +218,31 @@ async function detectDeepResearchMode(page) {
226
218
  async function enableDeepResearchMode(page, response) {
227
219
  try {
228
220
  response.appendResponseLine('DeepResearchモードを有効化中...');
229
- // Step 1: Click "+" button
221
+ // Step 1: Click "+" button (ファイルの追加など)
230
222
  const plusClicked = await page.evaluate(() => {
231
223
  const buttons = Array.from(document.querySelectorAll('button'));
232
224
  const plusButton = buttons.find((btn) => {
233
225
  const aria = btn.getAttribute('aria-label') || '';
234
- const desc = btn.getAttribute('description') || '';
235
- return aria.includes('ファイルの追加') || desc.includes('ファイルの追加');
226
+ return aria.includes('ファイルの追加');
236
227
  });
237
228
  if (!plusButton)
238
- return { success: false, error: '+ボタンが見つかりません' };
229
+ return { success: false, error: '+ボタン(ファイルの追加など)が見つかりません' };
239
230
  plusButton.click();
240
231
  return { success: true };
241
232
  });
242
233
  if (!plusClicked.success) {
243
234
  return { success: false, error: plusClicked.error };
244
235
  }
245
- await new Promise((resolve) => setTimeout(resolve, 800));
246
- // Step 2: Select DeepResearch option
236
+ await new Promise((resolve) => setTimeout(resolve, 500));
237
+ // Step 2: Click "Deep Research" menuitemradio
247
238
  const deepResearchSelected = await page.evaluate(() => {
248
239
  const menuItems = Array.from(document.querySelectorAll('[role="menuitemradio"]'));
249
240
  const deepResearchItem = menuItems.find((item) => item.textContent?.includes('Deep Research') ||
250
- item.textContent?.includes('ディープリサーチ'));
241
+ item.textContent?.includes('リサーチ'));
251
242
  if (!deepResearchItem) {
252
243
  return {
253
244
  success: false,
254
- error: 'DeepResearchオプションが見つかりません',
245
+ error: 'DeepResearch menuitemradio が見つかりません',
255
246
  };
256
247
  }
257
248
  deepResearchItem.click();
@@ -260,8 +251,17 @@ async function enableDeepResearchMode(page, response) {
260
251
  if (!deepResearchSelected.success) {
261
252
  return { success: false, error: deepResearchSelected.error };
262
253
  }
263
- response.appendResponseLine('✅ DeepResearchモード有効化');
264
- await new Promise((resolve) => setTimeout(resolve, 500));
254
+ response.appendResponseLine('✅ DeepResearch menuitemradio をクリック');
255
+ await new Promise((resolve) => setTimeout(resolve, 1000));
256
+ // Step 3: Verify mode was actually enabled (composer-pill detection)
257
+ const verification = await detectDeepResearchMode(page);
258
+ if (!verification.isEnabled) {
259
+ return {
260
+ success: false,
261
+ error: 'DeepResearchモードの有効化に失敗しました(リサーチpillが検出されませんでした)',
262
+ };
263
+ }
264
+ response.appendResponseLine(`✅ モード確認完了: DeepResearch有効 (${verification.indicator})`);
265
265
  return { success: true };
266
266
  }
267
267
  catch (error) {
@@ -323,6 +323,15 @@ async function configureSources(page, response, enableGitHub) {
323
323
  * Send question text and click send button
324
324
  */
325
325
  async function sendQuestion(page, response, question) {
326
+ // Final verification before sending
327
+ const finalCheck = await detectDeepResearchMode(page);
328
+ if (!finalCheck.isEnabled) {
329
+ return {
330
+ success: false,
331
+ error: 'DeepResearchモードが無効です。送信前の最終確認に失敗しました。',
332
+ };
333
+ }
334
+ response.appendResponseLine(`✅ 送信前確認: DeepResearchモード有効 (${finalCheck.indicator})`);
326
335
  response.appendResponseLine('リサーチテーマを送信中...');
327
336
  const questionSent = await page.evaluate((questionText) => {
328
337
  const prosemirror = document.querySelector('.ProseMirror[contenteditable="true"]');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-devtools-mcp-for-extension",
3
- "version": "0.9.24",
3
+ "version": "0.9.26",
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",