chrome-devtools-mcp-for-extension 0.10.0 → 0.10.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.
@@ -259,56 +259,31 @@ async function detectDeepResearchMode(page) {
259
259
  async function enableDeepResearchMode(page, response) {
260
260
  try {
261
261
  response.appendResponseLine('DeepResearchモードを有効化中...');
262
- // Step 1: Click "+" button (ファイルの追加など)
263
- const plusButtonSelector = await page.evaluate(() => {
264
- const buttons = Array.from(document.querySelectorAll('button'));
265
- const plusButton = buttons.find((btn) => {
266
- const aria = btn.getAttribute('aria-label') || '';
267
- return aria.includes('ファイルの追加');
268
- });
269
- if (!plusButton)
270
- return { success: false, error: '+ボタン(ファイルの追加など)が見つかりません' };
271
- // Return selector info instead of clicking
272
- const ariaLabel = plusButton.getAttribute('aria-label');
273
- return { success: true, ariaLabel };
274
- });
275
- if (!plusButtonSelector.success) {
276
- return { success: false, error: plusButtonSelector.error };
262
+ // Step 1: +ボタンをクリック(Puppeteer click)
263
+ const plusButton = await page.$('button[aria-label*="ファイルの追加"]');
264
+ if (!plusButton) {
265
+ return { success: false, error: '+ボタンが見つかりません' };
277
266
  }
278
- // Use Puppeteer's click for reliable interaction
279
- await page.click(`button[aria-label="${plusButtonSelector.ariaLabel}"]`);
280
- response.appendResponseLine('✅ +ボタン(ファイルの追加など)をクリック');
281
- // Wait for menu to appear
282
- await page.waitForSelector('[role="menuitemradio"]', { visible: true, timeout: 5000 });
283
- await new Promise((resolve) => setTimeout(resolve, 500));
284
- // Step 2: Find and click "Deep Research" menuitemradio
285
- const deepResearchResult = await page.evaluate(() => {
286
- const menuItems = Array.from(document.querySelectorAll('[role="menuitemradio"]'));
287
- const deepResearchItem = menuItems.find((item) => item.textContent?.includes('Deep Research') || item.textContent?.includes('リサーチ'));
288
- if (!deepResearchItem) {
289
- return {
290
- success: false,
291
- error: `DeepResearch menuitemradio が見つかりません (found: ${menuItems.length} items: ${menuItems.map(m => m.textContent?.trim()).join(', ')})`,
292
- };
293
- }
294
- // Check if already checked
295
- const isChecked = deepResearchItem.getAttribute('aria-checked') === 'true';
296
- if (!isChecked) {
297
- deepResearchItem.click();
267
+ await plusButton.click();
268
+ response.appendResponseLine('✅ +ボタンをクリック');
269
+ await page.waitForTimeout(500);
270
+ // Step 2: Deep Research menuitemradio をクリック(Puppeteer click)
271
+ const menuItems = await page.$$('[role="menuitemradio"]');
272
+ let deepResearchItem = null;
273
+ for (const item of menuItems) {
274
+ const text = await item.evaluate((el) => el.textContent);
275
+ if (text?.includes('Deep Research') || text?.includes('リサーチ')) {
276
+ deepResearchItem = item;
277
+ break;
298
278
  }
299
- return { success: true, alreadyEnabled: isChecked };
300
- });
301
- if (!deepResearchResult.success) {
302
- return { success: false, error: deepResearchResult.error };
303
- }
304
- if (deepResearchResult.alreadyEnabled) {
305
- response.appendResponseLine('✅ DeepResearch は既に有効です');
306
279
  }
307
- else {
308
- response.appendResponseLine(' DeepResearch menuitemradio をクリック');
280
+ if (!deepResearchItem) {
281
+ return { success: false, error: 'Deep Research menuitemradio が見つかりません' };
309
282
  }
310
- await new Promise((resolve) => setTimeout(resolve, 1000));
311
- // Step 3: Verify mode was actually enabled (composer-pill detection)
283
+ await deepResearchItem.click();
284
+ response.appendResponseLine('✅ Deep Research menuitemradio をクリック');
285
+ await page.waitForTimeout(1000);
286
+ // Step 3: 検証(composer-pill確認)
312
287
  const verification = await detectDeepResearchMode(page);
313
288
  if (!verification.isEnabled) {
314
289
  return {
@@ -0,0 +1,146 @@
1
+ /**
2
+ * DeepResearch ON/OFF切り替え手順記録システム
3
+ *
4
+ * 目的: 毎回要素を探す必要をなくし、記録された手順で確実に切り替え
5
+ */
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ const PROCEDURE_FILE = path.join(process.cwd(), 'docs/deepresearch-procedure.json');
9
+ /**
10
+ * デフォルトの手順定義
11
+ */
12
+ const DEFAULT_PROCEDURE = {
13
+ version: '1.0.0',
14
+ lastUpdated: new Date().toISOString(),
15
+ steps: {
16
+ enable: [
17
+ {
18
+ action: 'click',
19
+ selector: 'button[aria-label*="ファイルの追加"]',
20
+ description: '+ボタンをクリックしてメニューを開く'
21
+ },
22
+ {
23
+ action: 'wait',
24
+ waitMs: 500,
25
+ description: 'メニューが表示されるまで待機'
26
+ },
27
+ {
28
+ action: 'click',
29
+ selector: '[role="menuitemradio"]',
30
+ textContent: 'Deep Research',
31
+ description: 'Deep Research menuitemradio をクリック'
32
+ },
33
+ {
34
+ action: 'wait',
35
+ waitMs: 1000,
36
+ description: 'DeepResearch有効化完了を待機'
37
+ }
38
+ ],
39
+ disable: [
40
+ {
41
+ action: 'click',
42
+ selector: 'button[aria-label*="リサーチ:クリックして削除"]',
43
+ description: 'リサーチpillボタンをクリックして無効化'
44
+ }
45
+ ],
46
+ verify: [
47
+ {
48
+ action: 'verify',
49
+ selector: 'button.__composer-pill[aria-label*="リサーチ"]',
50
+ description: 'リサーチpillボタンの存在確認'
51
+ }
52
+ ]
53
+ }
54
+ };
55
+ /**
56
+ * 手順をファイルから読み込み
57
+ */
58
+ export async function loadProcedure() {
59
+ try {
60
+ if (fs.existsSync(PROCEDURE_FILE)) {
61
+ const data = await fs.promises.readFile(PROCEDURE_FILE, 'utf-8');
62
+ return JSON.parse(data);
63
+ }
64
+ }
65
+ catch (error) {
66
+ console.error(`手順ファイルの読み込みエラー: ${error}`);
67
+ }
68
+ return DEFAULT_PROCEDURE;
69
+ }
70
+ /**
71
+ * 手順をファイルに保存
72
+ */
73
+ export async function saveProcedure(procedure) {
74
+ try {
75
+ const dir = path.dirname(PROCEDURE_FILE);
76
+ await fs.promises.mkdir(dir, { recursive: true });
77
+ await fs.promises.writeFile(PROCEDURE_FILE, JSON.stringify(procedure, null, 2), 'utf-8');
78
+ }
79
+ catch (error) {
80
+ console.error(`手順ファイルの保存エラー: ${error}`);
81
+ }
82
+ }
83
+ /**
84
+ * 手順を実行
85
+ */
86
+ export async function executeProcedure(page, steps) {
87
+ for (const step of steps) {
88
+ try {
89
+ if (step.action === 'click') {
90
+ const element = await page.$(step.selector);
91
+ if (!element) {
92
+ return { success: false, error: `要素が見つかりません: ${step.selector}` };
93
+ }
94
+ // textContent指定がある場合は検証
95
+ if (step.textContent) {
96
+ const text = await page.evaluate((el) => el.textContent, element);
97
+ if (!text?.includes(step.textContent)) {
98
+ return { success: false, error: `テキスト不一致: 期待="${step.textContent}", 実際="${text}"` };
99
+ }
100
+ }
101
+ await element.click();
102
+ }
103
+ else if (step.action === 'wait') {
104
+ await page.waitForTimeout(step.waitMs || 500);
105
+ }
106
+ else if (step.action === 'verify') {
107
+ const element = await page.$(step.selector);
108
+ if (!element) {
109
+ return { success: false, error: `検証失敗: ${step.selector} が見つかりません` };
110
+ }
111
+ }
112
+ }
113
+ catch (error) {
114
+ return {
115
+ success: false,
116
+ error: `ステップ実行エラー: ${step.description} - ${error}`
117
+ };
118
+ }
119
+ }
120
+ return { success: true };
121
+ }
122
+ /**
123
+ * DeepResearchを有効化
124
+ */
125
+ export async function enableDeepResearch(page) {
126
+ const procedure = await loadProcedure();
127
+ return await executeProcedure(page, procedure.steps.enable);
128
+ }
129
+ /**
130
+ * DeepResearchを無効化
131
+ */
132
+ export async function disableDeepResearch(page) {
133
+ const procedure = await loadProcedure();
134
+ return await executeProcedure(page, procedure.steps.disable);
135
+ }
136
+ /**
137
+ * DeepResearch状態を確認
138
+ */
139
+ export async function verifyDeepResearch(page) {
140
+ const procedure = await loadProcedure();
141
+ const result = await executeProcedure(page, procedure.steps.verify);
142
+ if (!result.success) {
143
+ return { enabled: false, error: result.error };
144
+ }
145
+ return { enabled: true };
146
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * DeepResearch ON/OFF 切り替えツール(簡潔版)
3
+ *
4
+ * 目的: 最小限のコードで確実にDeepResearchを切り替え
5
+ */
6
+ /**
7
+ * DeepResearch有効化(シンプル実装)
8
+ */
9
+ export async function enableDeepResearch(page) {
10
+ try {
11
+ // Step 1: +ボタンをクリック
12
+ const plusButton = await page.$('button[aria-label*="ファイルの追加"]');
13
+ if (!plusButton) {
14
+ return { success: false, error: '+ボタンが見つかりません' };
15
+ }
16
+ await plusButton.click();
17
+ await page.waitForTimeout(500);
18
+ // Step 2: Deep Research menuitemradio をクリック
19
+ const menuItems = await page.$$('[role="menuitemradio"]');
20
+ let deepResearchItem = null;
21
+ for (const item of menuItems) {
22
+ const text = await item.evaluate((el) => el.textContent);
23
+ if (text?.includes('Deep Research') || text?.includes('リサーチ')) {
24
+ deepResearchItem = item;
25
+ break;
26
+ }
27
+ }
28
+ if (!deepResearchItem) {
29
+ return { success: false, error: 'Deep Research menuitemradio が見つかりません' };
30
+ }
31
+ await deepResearchItem.click();
32
+ await page.waitForTimeout(1000);
33
+ // Step 3: 検証(composer-pill確認)
34
+ const pill = await page.$('button.__composer-pill[aria-label*="リサーチ"]');
35
+ if (!pill) {
36
+ return { success: false, error: 'DeepResearch pill が表示されませんでした' };
37
+ }
38
+ return { success: true };
39
+ }
40
+ catch (error) {
41
+ return { success: false, error: `エラー: ${error}` };
42
+ }
43
+ }
44
+ /**
45
+ * DeepResearch無効化(シンプル実装)
46
+ */
47
+ export async function disableDeepResearch(page) {
48
+ try {
49
+ // リサーチpillボタンをクリック
50
+ const pill = await page.$('button[aria-label*="リサーチ:クリックして削除"]');
51
+ if (!pill) {
52
+ return { success: false, error: 'リサーチpillボタンが見つかりません(既にOFFの可能性)' };
53
+ }
54
+ await pill.click();
55
+ await page.waitForTimeout(500);
56
+ // 検証: pillが消えたことを確認
57
+ const stillExists = await page.$('button[aria-label*="リサーチ:クリックして削除"]');
58
+ if (stillExists) {
59
+ return { success: false, error: 'DeepResearch無効化に失敗しました' };
60
+ }
61
+ return { success: true };
62
+ }
63
+ catch (error) {
64
+ return { success: false, error: `エラー: ${error}` };
65
+ }
66
+ }
67
+ /**
68
+ * DeepResearch状態確認(シンプル実装)
69
+ */
70
+ export async function checkDeepResearch(page) {
71
+ try {
72
+ const pill = await page.$('button.__composer-pill[aria-label*="リサーチ"]');
73
+ if (pill) {
74
+ const text = await pill.evaluate((el) => el.textContent?.trim());
75
+ return { enabled: true, indicator: `composer-pill: "${text}"` };
76
+ }
77
+ return { enabled: false };
78
+ }
79
+ catch (error) {
80
+ return { enabled: false };
81
+ }
82
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-devtools-mcp-for-extension",
3
- "version": "0.10.0",
3
+ "version": "0.10.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",