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
|
-
|
|
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
|
-
|
|
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
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
231
|
-
|
|
271
|
+
// Return selector info instead of clicking
|
|
272
|
+
const ariaLabel = plusButton.getAttribute('aria-label');
|
|
273
|
+
return { success: true, ariaLabel };
|
|
232
274
|
});
|
|
233
|
-
if (!
|
|
234
|
-
return { success: false, 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
|
|
565
|
-
if (
|
|
566
|
-
|
|
567
|
-
|
|
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:
|
|
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.
|
|
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",
|