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

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.
File without changes
@@ -128,38 +128,96 @@ function isCodeRelatedQuestion(question) {
128
128
  */
129
129
  async function detectDeepResearchMode(page) {
130
130
  return await page.evaluate(() => {
131
- // Check for DeepResearch indicator in the UI
132
- const allElements = Array.from(document.querySelectorAll('div, span, button'));
133
- // Look for DeepResearch badge/text near input area
134
- const deepResearchIndicator = allElements.find((el) => {
135
- const text = el.textContent || '';
136
- const ariaLabel = el.getAttribute('aria-label') || '';
137
- return (text.includes('Deep Research') ||
138
- text.includes('ディープリサーチ') ||
139
- ariaLabel.includes('Deep Research') ||
140
- ariaLabel.includes('ディープリサーチ'));
141
- });
142
- if (deepResearchIndicator) {
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 };
150
+ }
151
+ // Step 2: Try data-testid selectors FIRST (most reliable)
152
+ const dataTestIdSelectors = [
153
+ '[data-testid*="deep-research"]',
154
+ '[data-testid*="deepresearch"]',
155
+ '[data-testid*="research-mode"]',
156
+ ];
157
+ for (const selector of dataTestIdSelectors) {
158
+ const element = scopedRoot.querySelector(selector);
159
+ if (element) {
160
+ return {
161
+ isEnabled: true,
162
+ indicator: `data-testid: ${element.getAttribute('data-testid')}`,
163
+ };
164
+ }
165
+ }
166
+ // Step 3: Try aria-* attributes SECOND
167
+ const ariaSelectors = [
168
+ '[aria-label*="Deep Research" i]',
169
+ '[aria-label*="ディープリサーチ" i]',
170
+ '[aria-checked="true"][role="menuitemradio"]',
171
+ ];
172
+ for (const selector of ariaSelectors) {
173
+ const elements = Array.from(scopedRoot.querySelectorAll(selector));
174
+ for (const element of elements) {
175
+ const ariaLabel = element.getAttribute('aria-label') || '';
176
+ const role = element.getAttribute('role') || '';
177
+ // Check aria-label with pattern
178
+ if (DEEP_RESEARCH_PATTERN.test(ariaLabel)) {
179
+ return {
180
+ isEnabled: true,
181
+ indicator: `aria-label: ${ariaLabel.substring(0, 50)}`,
182
+ };
183
+ }
184
+ // Check menuitemradio with aria-checked
185
+ if (role === 'menuitemradio') {
186
+ const isChecked = element.getAttribute('aria-checked') === 'true';
187
+ const text = element.textContent || '';
188
+ if (isChecked && DEEP_RESEARCH_PATTERN.test(text)) {
189
+ return {
190
+ isEnabled: true,
191
+ indicator: 'menuitemradio (checked)',
192
+ };
193
+ }
194
+ }
195
+ }
196
+ }
197
+ // 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) {
143
201
  return {
144
202
  isEnabled: true,
145
- indicator: deepResearchIndicator.textContent?.substring(0, 50) ||
146
- 'DeepResearch',
203
+ indicator: 'cached indicator',
147
204
  };
148
205
  }
149
- // Check for the "+" button state (if DeepResearch is selected)
150
- const menuItems = Array.from(document.querySelectorAll('[role="menuitemradio"]'));
151
- const deepResearchSelected = menuItems.some((item) => {
152
- const text = item.textContent || '';
153
- const isChecked = item.getAttribute('aria-checked') === 'true';
154
- return (isChecked &&
155
- (text.includes('Deep Research') || text.includes('ディープリサーチ')));
156
- });
157
- return {
158
- isEnabled: deepResearchSelected,
159
- indicator: deepResearchSelected
160
- ? 'DeepResearch (selected in menu)'
161
- : undefined,
162
- };
206
+ // Search within scoped root only, not entire document
207
+ const textElements = Array.from(scopedRoot.querySelectorAll('div, span, button'));
208
+ for (const element of textElements) {
209
+ const text = element.textContent || '';
210
+ if (DEEP_RESEARCH_PATTERN.test(text)) {
211
+ // Update cache
212
+ cache.element = element;
213
+ cache.timestamp = now;
214
+ return {
215
+ isEnabled: true,
216
+ indicator: text.substring(0, 50),
217
+ };
218
+ }
219
+ }
220
+ return { isEnabled: false };
163
221
  });
164
222
  }
165
223
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-devtools-mcp-for-extension",
3
- "version": "0.9.23",
3
+ "version": "0.9.24",
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",