chrome-devtools-mcp-for-extension 0.9.19 → 0.9.21
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.
- package/build/src/tools/chatgpt-web.js +84 -105
- package/package.json +1 -1
|
@@ -8,6 +8,33 @@ import path from 'node:path';
|
|
|
8
8
|
import z from 'zod';
|
|
9
9
|
import { ToolCategories } from './categories.js';
|
|
10
10
|
import { defineTool } from './ToolDefinition.js';
|
|
11
|
+
/**
|
|
12
|
+
* Path to store chat session data
|
|
13
|
+
*/
|
|
14
|
+
const CHAT_SESSIONS_FILE = path.join(process.cwd(), 'docs/ask/chatgpt/.chat-sessions.json');
|
|
15
|
+
/**
|
|
16
|
+
* Load chat sessions from JSON file
|
|
17
|
+
*/
|
|
18
|
+
async function loadChatSessions() {
|
|
19
|
+
try {
|
|
20
|
+
const data = await fs.promises.readFile(CHAT_SESSIONS_FILE, 'utf-8');
|
|
21
|
+
return JSON.parse(data);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Save a chat session for a project
|
|
29
|
+
*/
|
|
30
|
+
async function saveChatSession(projectName, session) {
|
|
31
|
+
const sessions = await loadChatSessions();
|
|
32
|
+
sessions[projectName] = session;
|
|
33
|
+
// Ensure directory exists
|
|
34
|
+
const dir = path.dirname(CHAT_SESSIONS_FILE);
|
|
35
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
36
|
+
await fs.promises.writeFile(CHAT_SESSIONS_FILE, JSON.stringify(sessions, null, 2), 'utf-8');
|
|
37
|
+
}
|
|
11
38
|
/**
|
|
12
39
|
* Sanitize question to remove sensitive information like passwords
|
|
13
40
|
*/
|
|
@@ -107,60 +134,30 @@ export const askChatGPTWeb = defineTool({
|
|
|
107
134
|
return;
|
|
108
135
|
}
|
|
109
136
|
response.appendResponseLine('✅ ログイン確認完了');
|
|
110
|
-
// Step 2:
|
|
137
|
+
// Step 2: Load existing session or create new chat
|
|
138
|
+
let isNewChat = false;
|
|
139
|
+
let sessionChatId;
|
|
111
140
|
if (!createNewChat) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Search for project chat
|
|
125
|
-
const chatFound = await page.evaluate((projectName) => {
|
|
126
|
-
const searchInput = document.querySelector('input[placeholder*="チャットを検索"]');
|
|
127
|
-
if (searchInput) {
|
|
128
|
-
searchInput.value = `[Project: ${projectName}]`;
|
|
129
|
-
searchInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
return false;
|
|
133
|
-
}, project);
|
|
134
|
-
if (chatFound) {
|
|
135
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
136
|
-
// Try to find and click the chat
|
|
137
|
-
const existingChat = await page.evaluate((projectName) => {
|
|
138
|
-
const chatLinks = Array.from(document.querySelectorAll('a[href^="/c/"]'));
|
|
139
|
-
const targetChat = chatLinks.find((link) => link.textContent?.includes(`[Project: ${projectName}]`));
|
|
140
|
-
if (targetChat) {
|
|
141
|
-
targetChat.click();
|
|
142
|
-
return {
|
|
143
|
-
found: true,
|
|
144
|
-
href: targetChat.href,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
return { found: false };
|
|
148
|
-
}, project);
|
|
149
|
-
if (existingChat.found) {
|
|
150
|
-
response.appendResponseLine(`✅ 既存チャットを使用: ${existingChat.href}`);
|
|
151
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
response.appendResponseLine('既存チャットが見つかりませんでした。新規作成します。');
|
|
155
|
-
}
|
|
156
|
-
}
|
|
141
|
+
// Try to load existing session for this project
|
|
142
|
+
const sessions = await loadChatSessions();
|
|
143
|
+
const existingSession = sessions[project];
|
|
144
|
+
if (existingSession) {
|
|
145
|
+
response.appendResponseLine(`既存のプロジェクトチャットを使用: ${existingSession.url}`);
|
|
146
|
+
await page.goto(existingSession.url, { waitUntil: 'networkidle2' });
|
|
147
|
+
sessionChatId = existingSession.chatId;
|
|
148
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
response.appendResponseLine('既存チャットが見つかりませんでした。新規作成します。');
|
|
152
|
+
isNewChat = true;
|
|
157
153
|
}
|
|
158
154
|
}
|
|
155
|
+
else {
|
|
156
|
+
isNewChat = true;
|
|
157
|
+
}
|
|
159
158
|
// Step 3: Create new chat if needed
|
|
160
|
-
|
|
161
|
-
if (createNewChat || page.url() === 'https://chatgpt.com/') {
|
|
159
|
+
if (isNewChat) {
|
|
162
160
|
response.appendResponseLine('新規チャットを作成中...');
|
|
163
|
-
isNewChat = true;
|
|
164
161
|
// Click "新しいチャット"
|
|
165
162
|
await page.evaluate(() => {
|
|
166
163
|
const newChatLink = document.querySelector('a[href="/"]');
|
|
@@ -231,10 +228,16 @@ export const askChatGPTWeb = defineTool({
|
|
|
231
228
|
while (true) {
|
|
232
229
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
233
230
|
const status = await page.evaluate(() => {
|
|
234
|
-
// Check if streaming
|
|
231
|
+
// Check if streaming - check both textContent and aria-label
|
|
235
232
|
const buttons = Array.from(document.querySelectorAll('button'));
|
|
236
|
-
const isStreaming = buttons.some((btn) =>
|
|
237
|
-
btn.textContent
|
|
233
|
+
const isStreaming = buttons.some((btn) => {
|
|
234
|
+
const text = btn.textContent || '';
|
|
235
|
+
const aria = btn.getAttribute('aria-label') || '';
|
|
236
|
+
return (text.includes('ストリーミングの停止') ||
|
|
237
|
+
text.includes('停止') ||
|
|
238
|
+
aria.includes('ストリーミングの停止') ||
|
|
239
|
+
aria.includes('停止'));
|
|
240
|
+
});
|
|
238
241
|
if (!isStreaming) {
|
|
239
242
|
// Get final response
|
|
240
243
|
const assistantMessages = document.querySelectorAll('[data-message-author-role="assistant"]');
|
|
@@ -268,61 +271,37 @@ export const askChatGPTWeb = defineTool({
|
|
|
268
271
|
if (status.thinkingTime) {
|
|
269
272
|
response.appendResponseLine(`🤔 思考時間: ${status.thinkingTime}秒`);
|
|
270
273
|
}
|
|
271
|
-
//
|
|
274
|
+
// Save chat session if it's a new chat
|
|
272
275
|
if (isNewChat) {
|
|
273
|
-
response.appendResponseLine('
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
276
|
+
response.appendResponseLine('チャットセッションを保存中...');
|
|
277
|
+
// Extract chat ID from URL
|
|
278
|
+
const chatUrl = page.url();
|
|
279
|
+
const chatIdMatch = chatUrl.match(/\/c\/([a-f0-9-]+)/);
|
|
280
|
+
if (chatIdMatch) {
|
|
281
|
+
const chatId = chatIdMatch[1];
|
|
282
|
+
await saveChatSession(project, {
|
|
283
|
+
chatId,
|
|
284
|
+
url: chatUrl,
|
|
285
|
+
lastUsed: new Date().toISOString(),
|
|
286
|
+
title: `[Project: ${project}]`,
|
|
287
|
+
});
|
|
288
|
+
sessionChatId = chatId;
|
|
289
|
+
response.appendResponseLine(`✅ チャットセッション保存: ${chatId}`);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
response.appendResponseLine('⚠️ チャットIDが取得できませんでした');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
// Update last used timestamp for existing session
|
|
297
|
+
if (sessionChatId) {
|
|
298
|
+
const chatUrl = page.url();
|
|
299
|
+
await saveChatSession(project, {
|
|
300
|
+
chatId: sessionChatId,
|
|
301
|
+
url: chatUrl,
|
|
302
|
+
lastUsed: new Date().toISOString(),
|
|
303
|
+
title: `[Project: ${project}]`,
|
|
298
304
|
});
|
|
299
|
-
if (renameClicked) {
|
|
300
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
301
|
-
// Enter new name
|
|
302
|
-
await page.evaluate((projectName) => {
|
|
303
|
-
const textbox = document.querySelector('input[type="text"]');
|
|
304
|
-
if (textbox) {
|
|
305
|
-
textbox.value = `[Project: ${projectName}]`;
|
|
306
|
-
textbox.dispatchEvent(new Event('input', { bubbles: true }));
|
|
307
|
-
// Press Enter to confirm
|
|
308
|
-
textbox.dispatchEvent(new KeyboardEvent('keydown', {
|
|
309
|
-
key: 'Enter',
|
|
310
|
-
code: 'Enter',
|
|
311
|
-
keyCode: 13,
|
|
312
|
-
bubbles: true,
|
|
313
|
-
}));
|
|
314
|
-
textbox.blur();
|
|
315
|
-
}
|
|
316
|
-
}, project);
|
|
317
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
318
|
-
response.appendResponseLine(`✅ チャット名を「[Project: ${project}]」に変更`);
|
|
319
|
-
// Close the menu popup by clicking outside
|
|
320
|
-
await page.evaluate(() => {
|
|
321
|
-
const body = document.body;
|
|
322
|
-
body.click();
|
|
323
|
-
});
|
|
324
|
-
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
325
|
-
}
|
|
326
305
|
}
|
|
327
306
|
}
|
|
328
307
|
// Save conversation log
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chrome-devtools-mcp-for-extension",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.21",
|
|
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",
|