chrome-devtools-mcp-for-extension 0.9.19 → 0.9.20

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.
@@ -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: Search for existing chat or create new one
137
+ // Step 2: Load existing session or create new chat
138
+ let isNewChat = false;
139
+ let sessionChatId;
111
140
  if (!createNewChat) {
112
- response.appendResponseLine(`既存のプロジェクトチャット「[Project: ${project}]」を検索中...`);
113
- // Open search
114
- const searchOpened = await page.evaluate(() => {
115
- const searchButton = Array.from(document.querySelectorAll('div.group.__menu-item.hoverable')).find((elem) => elem.textContent?.includes('チャットを検索'));
116
- if (searchButton) {
117
- searchButton.click();
118
- return true;
119
- }
120
- return false;
121
- });
122
- if (searchOpened) {
123
- await new Promise((resolve) => setTimeout(resolve, 500));
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));
157
149
  }
150
+ else {
151
+ response.appendResponseLine('既存チャットが見つかりませんでした。新規作成します。');
152
+ isNewChat = true;
153
+ }
154
+ }
155
+ else {
156
+ isNewChat = true;
158
157
  }
159
158
  // Step 3: Create new chat if needed
160
- let isNewChat = false;
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="/"]');
@@ -268,61 +265,37 @@ export const askChatGPTWeb = defineTool({
268
265
  if (status.thinkingTime) {
269
266
  response.appendResponseLine(`🤔 思考時間: ${status.thinkingTime}秒`);
270
267
  }
271
- // Rename chat if it's a new chat
268
+ // Save chat session if it's a new chat
272
269
  if (isNewChat) {
273
- response.appendResponseLine('チャット名を変更中...');
274
- // Wait for chat to be created
275
- await new Promise((resolve) => setTimeout(resolve, 2000));
276
- // Click chat menu
277
- const menuClicked = await page.evaluate(() => {
278
- const menuButtons = Array.from(document.querySelectorAll('button[aria-label="会話のオプションを開く"]'));
279
- // Find the first menu button (current chat)
280
- const btn = menuButtons[0];
281
- if (btn) {
282
- btn.click();
283
- return true;
284
- }
285
- return false;
286
- });
287
- if (menuClicked) {
288
- await new Promise((resolve) => setTimeout(resolve, 500));
289
- // Click "名前を変更する"
290
- const renameClicked = await page.evaluate(() => {
291
- const menuItems = Array.from(document.querySelectorAll('[role="menuitem"]'));
292
- const renameItem = menuItems.find((item) => item.textContent?.includes('名前を変更する'));
293
- if (renameItem) {
294
- renameItem.click();
295
- return true;
296
- }
297
- return false;
270
+ response.appendResponseLine('チャットセッションを保存中...');
271
+ // Extract chat ID from URL
272
+ const chatUrl = page.url();
273
+ const chatIdMatch = chatUrl.match(/\/c\/([a-f0-9-]+)/);
274
+ if (chatIdMatch) {
275
+ const chatId = chatIdMatch[1];
276
+ await saveChatSession(project, {
277
+ chatId,
278
+ url: chatUrl,
279
+ lastUsed: new Date().toISOString(),
280
+ title: `[Project: ${project}]`,
281
+ });
282
+ sessionChatId = chatId;
283
+ response.appendResponseLine(`✅ チャットセッション保存: ${chatId}`);
284
+ }
285
+ else {
286
+ response.appendResponseLine('⚠️ チャットIDが取得できませんでした');
287
+ }
288
+ }
289
+ else {
290
+ // Update last used timestamp for existing session
291
+ if (sessionChatId) {
292
+ const chatUrl = page.url();
293
+ await saveChatSession(project, {
294
+ chatId: sessionChatId,
295
+ url: chatUrl,
296
+ lastUsed: new Date().toISOString(),
297
+ title: `[Project: ${project}]`,
298
298
  });
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
299
  }
327
300
  }
328
301
  // 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.19",
3
+ "version": "0.9.20",
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",