chrome-devtools-mcp-for-extension 0.9.35 → 0.10.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.
@@ -13,12 +13,33 @@ import { defineTool } from './ToolDefinition.js';
13
13
  */
14
14
  const CHAT_SESSIONS_FILE = path.join(process.cwd(), 'docs/ask/chatgpt/.chat-sessions.json');
15
15
  /**
16
- * Load chat sessions from JSON file
16
+ * Load chat sessions from JSON file with backward compatibility
17
17
  */
18
18
  async function loadChatSessions() {
19
19
  try {
20
20
  const data = await fs.promises.readFile(CHAT_SESSIONS_FILE, 'utf-8');
21
- return JSON.parse(data);
21
+ const parsed = JSON.parse(data);
22
+ // Migrate from old format (single object) to new format (array)
23
+ const migrated = {};
24
+ for (const [projectName, value] of Object.entries(parsed)) {
25
+ if (Array.isArray(value)) {
26
+ // Already in new format
27
+ migrated[projectName] = value;
28
+ }
29
+ else {
30
+ // Old format - convert to array
31
+ const oldSession = value;
32
+ migrated[projectName] = [{
33
+ chatId: oldSession.chatId,
34
+ url: oldSession.url,
35
+ lastUsed: oldSession.lastUsed,
36
+ title: oldSession.title,
37
+ createdAt: oldSession.lastUsed, // Use lastUsed as createdAt for old sessions
38
+ conversationCount: 1,
39
+ }];
40
+ }
41
+ }
42
+ return migrated;
22
43
  }
23
44
  catch {
24
45
  return {};
@@ -29,7 +50,27 @@ async function loadChatSessions() {
29
50
  */
30
51
  async function saveChatSession(projectName, session) {
31
52
  const sessions = await loadChatSessions();
32
- sessions[projectName] = session;
53
+ // Initialize project array if it doesn't exist
54
+ if (!sessions[projectName]) {
55
+ sessions[projectName] = [];
56
+ }
57
+ // Check if session with same chatId already exists
58
+ const existingIndex = sessions[projectName].findIndex(s => s.chatId === session.chatId);
59
+ if (existingIndex >= 0) {
60
+ // Update existing session
61
+ sessions[projectName][existingIndex] = {
62
+ ...sessions[projectName][existingIndex],
63
+ ...session,
64
+ lastUsed: new Date().toISOString(),
65
+ };
66
+ }
67
+ else {
68
+ // Add new session to array
69
+ sessions[projectName].push({
70
+ ...session,
71
+ createdAt: session.createdAt || new Date().toISOString(),
72
+ });
73
+ }
33
74
  // Ensure directory exists
34
75
  const dir = path.dirname(CHAT_SESSIONS_FILE);
35
76
  await fs.promises.mkdir(dir, { recursive: true });
@@ -146,11 +187,14 @@ export const askChatGPTWeb = defineTool({
146
187
  if (!createNewChat) {
147
188
  // Try to load existing session for this project
148
189
  const sessions = await loadChatSessions();
149
- const existingSession = sessions[project];
150
- if (existingSession) {
151
- response.appendResponseLine(`既存のプロジェクトチャットを使用: ${existingSession.url}`);
152
- await page.goto(existingSession.url, { waitUntil: 'networkidle2' });
153
- sessionChatId = existingSession.chatId;
190
+ const projectSessions = sessions[project] || [];
191
+ if (projectSessions.length > 0) {
192
+ // Get the most recently used session
193
+ const sortedSessions = [...projectSessions].sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
194
+ const latestSession = sortedSessions[0];
195
+ response.appendResponseLine(`既存のプロジェクトチャットを使用: ${latestSession.url}`);
196
+ await page.goto(latestSession.url, { waitUntil: 'networkidle2' });
197
+ sessionChatId = latestSession.chatId;
154
198
  await new Promise((resolve) => setTimeout(resolve, 1000));
155
199
  }
156
200
  else {
@@ -416,11 +460,14 @@ export const askChatGPTWeb = defineTool({
416
460
  const chatIdMatch = chatUrl.match(/\/c\/([a-f0-9-]+)/);
417
461
  if (chatIdMatch) {
418
462
  const chatId = chatIdMatch[1];
463
+ const now = new Date().toISOString();
419
464
  await saveChatSession(project, {
420
465
  chatId,
421
466
  url: chatUrl,
422
- lastUsed: new Date().toISOString(),
467
+ lastUsed: now,
468
+ createdAt: now,
423
469
  title: `[Project: ${project}]`,
470
+ conversationCount: 1,
424
471
  });
425
472
  sessionChatId = chatId;
426
473
  response.appendResponseLine(`✅ チャットセッション保存: ${chatId}`);
@@ -430,14 +477,19 @@ export const askChatGPTWeb = defineTool({
430
477
  }
431
478
  }
432
479
  else {
433
- // Update last used timestamp for existing session
480
+ // Update last used timestamp and conversation count for existing session
434
481
  if (sessionChatId) {
435
482
  const chatUrl = page.url();
483
+ const sessions = await loadChatSessions();
484
+ const projectSessions = sessions[project] || [];
485
+ const existingSession = projectSessions.find(s => s.chatId === sessionChatId);
436
486
  await saveChatSession(project, {
437
487
  chatId: sessionChatId,
438
488
  url: chatUrl,
439
489
  lastUsed: new Date().toISOString(),
440
- title: `[Project: ${project}]`,
490
+ createdAt: existingSession?.createdAt || new Date().toISOString(),
491
+ title: existingSession?.title || `[Project: ${project}]`,
492
+ conversationCount: (existingSession?.conversationCount || 0) + 1,
441
493
  });
442
494
  }
443
495
  }
@@ -13,12 +13,33 @@ import { defineTool } from './ToolDefinition.js';
13
13
  */
14
14
  const CHAT_SESSIONS_FILE = path.join(process.cwd(), 'docs/ask/chatgpt/.chat-sessions.json');
15
15
  /**
16
- * Load chat sessions from JSON file
16
+ * Load chat sessions from JSON file with backward compatibility
17
17
  */
18
18
  async function loadChatSessions() {
19
19
  try {
20
20
  const data = await fs.promises.readFile(CHAT_SESSIONS_FILE, 'utf-8');
21
- return JSON.parse(data);
21
+ const parsed = JSON.parse(data);
22
+ // Migrate from old format (single object) to new format (array)
23
+ const migrated = {};
24
+ for (const [projectName, value] of Object.entries(parsed)) {
25
+ if (Array.isArray(value)) {
26
+ // Already in new format
27
+ migrated[projectName] = value;
28
+ }
29
+ else {
30
+ // Old format - convert to array
31
+ const oldSession = value;
32
+ migrated[projectName] = [{
33
+ chatId: oldSession.chatId,
34
+ url: oldSession.url,
35
+ lastUsed: oldSession.lastUsed,
36
+ title: oldSession.title,
37
+ createdAt: oldSession.lastUsed, // Use lastUsed as createdAt for old sessions
38
+ conversationCount: 1,
39
+ }];
40
+ }
41
+ }
42
+ return migrated;
22
43
  }
23
44
  catch {
24
45
  return {};
@@ -29,7 +50,27 @@ async function loadChatSessions() {
29
50
  */
30
51
  async function saveChatSession(projectName, session) {
31
52
  const sessions = await loadChatSessions();
32
- sessions[projectName] = session;
53
+ // Initialize project array if it doesn't exist
54
+ if (!sessions[projectName]) {
55
+ sessions[projectName] = [];
56
+ }
57
+ // Check if session with same chatId already exists
58
+ const existingIndex = sessions[projectName].findIndex(s => s.chatId === session.chatId);
59
+ if (existingIndex >= 0) {
60
+ // Update existing session
61
+ sessions[projectName][existingIndex] = {
62
+ ...sessions[projectName][existingIndex],
63
+ ...session,
64
+ lastUsed: new Date().toISOString(),
65
+ };
66
+ }
67
+ else {
68
+ // Add new session to array
69
+ sessions[projectName].push({
70
+ ...session,
71
+ createdAt: session.createdAt || new Date().toISOString(),
72
+ });
73
+ }
33
74
  const dir = path.dirname(CHAT_SESSIONS_FILE);
34
75
  await fs.promises.mkdir(dir, { recursive: true });
35
76
  await fs.promises.writeFile(CHAT_SESSIONS_FILE, JSON.stringify(sessions, null, 2), 'utf-8');
@@ -219,7 +260,7 @@ async function enableDeepResearchMode(page, response) {
219
260
  try {
220
261
  response.appendResponseLine('DeepResearchモードを有効化中...');
221
262
  // Step 1: Click "+" button (ファイルの追加など)
222
- const plusClicked = await page.evaluate(() => {
263
+ const plusButtonSelector = await page.evaluate(() => {
223
264
  const buttons = Array.from(document.querySelectorAll('button'));
224
265
  const plusButton = buttons.find((btn) => {
225
266
  const aria = btn.getAttribute('aria-label') || '';
@@ -227,12 +268,15 @@ async function enableDeepResearchMode(page, response) {
227
268
  });
228
269
  if (!plusButton)
229
270
  return { success: false, error: '+ボタン(ファイルの追加など)が見つかりません' };
230
- plusButton.click();
231
- return { success: true };
271
+ // Return selector info instead of clicking
272
+ const ariaLabel = plusButton.getAttribute('aria-label');
273
+ return { success: true, ariaLabel };
232
274
  });
233
- if (!plusClicked.success) {
234
- return { success: false, error: plusClicked.error };
275
+ if (!plusButtonSelector.success) {
276
+ return { success: false, error: plusButtonSelector.error };
235
277
  }
278
+ // Use Puppeteer's click for reliable interaction
279
+ await page.click(`button[aria-label="${plusButtonSelector.ariaLabel}"]`);
236
280
  response.appendResponseLine('✅ +ボタン(ファイルの追加など)をクリック');
237
281
  // Wait for menu to appear
238
282
  await page.waitForSelector('[role="menuitemradio"]', { visible: true, timeout: 5000 });
@@ -561,10 +605,13 @@ export const deepResearchChatGPT = defineTool({
561
605
  if (reuseSession) {
562
606
  // Try to load existing session
563
607
  const sessions = await loadChatSessions();
564
- const existingSession = sessions[project];
565
- if (existingSession) {
566
- response.appendResponseLine(`既存のプロジェクトチャットを使用: ${existingSession.url}`);
567
- await page.goto(existingSession.url, { waitUntil: 'networkidle2' });
608
+ const projectSessions = sessions[project] || [];
609
+ if (projectSessions.length > 0) {
610
+ // Get the most recently used session
611
+ const sortedSessions = [...projectSessions].sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
612
+ const latestSession = sortedSessions[0];
613
+ response.appendResponseLine(`既存のプロジェクトチャットを使用: ${latestSession.url}`);
614
+ await page.goto(latestSession.url, { waitUntil: 'networkidle2' });
568
615
  needsNewChat = false;
569
616
  await new Promise((resolve) => setTimeout(resolve, 1000));
570
617
  }
@@ -650,11 +697,14 @@ export const deepResearchChatGPT = defineTool({
650
697
  const chatIdMatch = chatUrl.match(/\/c\/([a-f0-9-]+)/);
651
698
  if (chatIdMatch) {
652
699
  const chatId = chatIdMatch[1];
700
+ const now = new Date().toISOString();
653
701
  await saveChatSession(project, {
654
702
  chatId,
655
703
  url: chatUrl,
656
- lastUsed: new Date().toISOString(),
704
+ lastUsed: now,
705
+ createdAt: now,
657
706
  title: `[DeepResearch: ${project}]`,
707
+ conversationCount: 1,
658
708
  });
659
709
  response.appendResponseLine(`💾 チャットセッション保存: ${chatId}`);
660
710
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-devtools-mcp-for-extension",
3
- "version": "0.9.35",
3
+ "version": "0.10.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",