chrome-ai-bridge 1.0.2 → 1.0.4

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.
Files changed (69) hide show
  1. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Base64.js +20 -2
  2. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Gzip.js +11 -0
  3. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Object.js +6 -1
  4. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ParsedURL.js +3 -0
  5. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ResourceType.js +6 -0
  6. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Settings.js +18 -8
  7. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/InspectorFrontendHostStub.js +3 -3
  8. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/ResourceLoader.js +1 -1
  9. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +17 -1
  10. package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/ArrayUtilities.js +10 -0
  11. package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/StringUtilities.js +63 -12
  12. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/CDPConnection.js +1 -0
  13. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/InspectorBackend.js +4 -1
  14. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMatchedStyles.js +44 -9
  15. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMetadata.js +6 -6
  16. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSModel.js +1 -1
  17. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DOMModel.js +169 -12
  18. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DebuggerModel.js +2 -1
  19. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/IsolateManager.js +6 -0
  20. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +18 -4
  21. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkRequest.js +7 -21
  22. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/OverlayModel.js +17 -5
  23. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +5 -1
  24. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +8 -5
  25. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMap.js +14 -2
  26. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapManager.js +1 -1
  27. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapScopesInfo.js +11 -4
  28. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/Target.js +3 -1
  29. package/build/node_modules/chrome-devtools-frontend/front_end/generated/ARIAProperties.js +1 -1
  30. package/build/node_modules/chrome-devtools-frontend/front_end/generated/Deprecation.js +1 -16
  31. package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +35 -14
  32. package/build/node_modules/chrome-devtools-frontend/front_end/generated/SupportedCSSProperties.js +197 -101
  33. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.js +2 -1
  34. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js +10 -16
  35. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.js +97 -26
  36. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AICallTree.js +35 -0
  37. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +5 -3
  38. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/DebuggerWorkspaceBinding.js +7 -3
  39. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/DeviceModeModel.js +1 -1
  40. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/EmulatedDevices.js +14 -0
  41. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +8 -5
  42. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceImpl.js +70 -1
  43. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceModel.js +82 -30
  44. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/EventsSerializer.js +7 -2
  45. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/LanternComputationData.js +2 -2
  46. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Processor.js +18 -19
  47. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Styles.js +12 -4
  48. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/Initiators.js +46 -0
  49. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +4 -3
  50. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/extras.js +1 -0
  51. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LargestImagePaintHandler.js +2 -2
  52. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LayoutShiftsHandler.js +1 -1
  53. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +6 -0
  54. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/NetworkRequestsHandler.js +10 -1
  55. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/PageLoadMetricsHandler.js +44 -27
  56. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/helpers/Timing.js +9 -2
  57. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Common.js +1 -6
  58. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +2 -2
  59. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +2 -4
  60. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +3 -2
  61. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +1 -1
  62. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/types/TraceEvents.js +30 -11
  63. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +28 -13
  64. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +1 -1
  65. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +4 -0
  66. package/build/src/tools/chatgpt-web.js +102 -64
  67. package/build/src/tools/gemini-web.js +43 -16
  68. package/build/src/tools/pages.js +0 -1
  69. package/package.json +1 -1
@@ -238,19 +238,47 @@ export const askChatGPTWeb = defineTool({
238
238
  // Get or create a dedicated ChatGPT tab
239
239
  const { page, needsNavigation } = await getOrCreateChatGPTPage(context);
240
240
  try {
241
- // Step 1: Navigate to ChatGPT (only if not already there)
241
+ // Step 1: Determine target URL (existing session or top page)
242
242
  response.appendResponseLine('ChatGPTに接続中...');
243
- if (needsNavigation) {
244
- await navigateWithRetry(page, CHATGPT_CONFIG.DEFAULT_URL, {
243
+ let isNewChat = false;
244
+ let sessionChatId;
245
+ let targetUrl = CHATGPT_CONFIG.DEFAULT_URL;
246
+ if (!createNewChat) {
247
+ // Check for existing session first
248
+ const sessions = await loadChatSessions();
249
+ const projectSessions = sessions[project] || [];
250
+ if (projectSessions.length > 0) {
251
+ // Get the most recently used session
252
+ const sortedSessions = [...projectSessions].sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
253
+ const latestSession = sortedSessions[0];
254
+ sessionChatId = latestSession.chatId;
255
+ targetUrl = latestSession.url;
256
+ response.appendResponseLine(`既存のプロジェクトチャットを使用: ${latestSession.url}`);
257
+ }
258
+ else {
259
+ response.appendResponseLine('既存チャットが見つかりませんでした。新規作成します。');
260
+ isNewChat = true;
261
+ }
262
+ }
263
+ else {
264
+ isNewChat = true;
265
+ }
266
+ // Step 2: Navigate to target URL (skip if already there)
267
+ const currentUrl = page.url();
268
+ const isAlreadyOnTarget = sessionChatId
269
+ ? currentUrl.includes(sessionChatId)
270
+ : currentUrl.includes('chatgpt.com') && !needsNavigation;
271
+ if (!isAlreadyOnTarget) {
272
+ await navigateWithRetry(page, targetUrl, {
245
273
  waitUntil: 'networkidle2',
246
274
  });
247
- // Wait for page to fully render (ChatGPT takes time to load UI)
275
+ // Wait for page to fully render
248
276
  await new Promise(resolve => setTimeout(resolve, 2000));
249
277
  }
250
278
  else {
251
279
  response.appendResponseLine('✅ 既存のChatGPTタブを再利用');
252
280
  }
253
- // Step 2: Check login status using session probe (most reliable)
281
+ // Step 3: Check login status
254
282
  const loginStatus = await getLoginStatus(page, 'chatgpt');
255
283
  if (loginStatus === LoginStatus.NEEDS_LOGIN) {
256
284
  response.appendResponseLine('\n❌ ChatGPTへのログインが必要です');
@@ -287,54 +315,27 @@ export const askChatGPTWeb = defineTool({
287
315
  }
288
316
  }
289
317
  response.appendResponseLine('✅ ログイン確認完了');
290
- // Step 2: Load existing session or create new chat
291
- let isNewChat = false;
292
- let sessionChatId;
293
- if (!createNewChat) {
294
- // Try to load existing session for this project
295
- const sessions = await loadChatSessions();
296
- const projectSessions = sessions[project] || [];
297
- if (projectSessions.length > 0) {
298
- // Get the most recently used session
299
- const sortedSessions = [...projectSessions].sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
300
- const latestSession = sortedSessions[0];
301
- response.appendResponseLine(`既存のプロジェクトチャットを使用: ${latestSession.url}`);
302
- sessionChatId = latestSession.chatId;
303
- // Skip navigation if already on the same chat
304
- const currentUrl = page.url();
305
- if (!currentUrl.includes(latestSession.chatId)) {
306
- await navigateWithRetry(page, latestSession.url, {
307
- waitUntil: 'networkidle2', // Wait for JS to finish loading
308
- });
318
+ // Step 4: Wait for input field (for existing sessions)
319
+ if (sessionChatId) {
320
+ let inputFieldReady = false;
321
+ for (let attempt = 0; attempt < 3; attempt++) {
322
+ try {
323
+ await page.waitForSelector('.ProseMirror[contenteditable="true"]', { timeout: 5000 });
324
+ inputFieldReady = true;
325
+ break;
309
326
  }
310
- // Wait for input field to be ready with retry
311
- let inputFieldReady = false;
312
- for (let attempt = 0; attempt < 3; attempt++) {
313
- try {
314
- await page.waitForSelector('.ProseMirror[contenteditable="true"]', { timeout: 5000 });
315
- inputFieldReady = true;
316
- break;
317
- }
318
- catch {
319
- if (attempt < 2) {
320
- response.appendResponseLine(`⏳ 入力欄を待機中... (${attempt + 1}/3)`);
321
- await new Promise(r => setTimeout(r, 2000));
322
- }
327
+ catch {
328
+ if (attempt < 2) {
329
+ response.appendResponseLine(`⏳ 入力欄を待機中... (${attempt + 1}/3)`);
330
+ await new Promise(r => setTimeout(r, 2000));
323
331
  }
324
332
  }
325
- if (!inputFieldReady) {
326
- response.appendResponseLine('⚠️ 入力欄の準備に時間がかかっています。続行を試みます...');
327
- }
328
333
  }
329
- else {
330
- response.appendResponseLine('既存チャットが見つかりませんでした。新規作成します。');
331
- isNewChat = true;
334
+ if (!inputFieldReady) {
335
+ response.appendResponseLine('⚠️ 入力欄の準備に時間がかかっています。続行を試みます...');
332
336
  }
333
337
  }
334
- else {
335
- isNewChat = true;
336
- }
337
- // Step 3: Create new chat if needed
338
+ // Step 5: Create new chat if needed
338
339
  if (isNewChat) {
339
340
  response.appendResponseLine('新規チャットを作成中...');
340
341
  // Click "新しいチャット"
@@ -363,6 +364,18 @@ export const askChatGPTWeb = defineTool({
363
364
  await new Promise(resolve => setTimeout(resolve, 200));
364
365
  }
365
366
  }
367
+ // Capture initial message counts BEFORE sending
368
+ // This is critical to detect if our message was actually sent
369
+ const initialCounts = await page.evaluate(() => {
370
+ const userMessages = document.querySelectorAll('[data-message-author-role="user"]');
371
+ const assistantMessages = document.querySelectorAll('[data-message-author-role="assistant"]');
372
+ return {
373
+ userCount: userMessages.length,
374
+ assistantCount: assistantMessages.length,
375
+ };
376
+ });
377
+ const initialUserMsgCount = initialCounts.userCount;
378
+ const initialAssistantMsgCount = initialCounts.assistantCount;
366
379
  // Step 4: Send question with retry
367
380
  response.appendResponseLine('質問を送信中...');
368
381
  let questionSent = false;
@@ -403,11 +416,12 @@ export const askChatGPTWeb = defineTool({
403
416
  response.appendResponseLine('❌ 送信ボタンが見つかりません');
404
417
  return;
405
418
  }
406
- // Wait for message to actually be sent (user message appears in DOM)
407
- await page.waitForFunction(() => {
419
+ // Wait for message to actually be sent (user message count INCREASED)
420
+ // This ensures we detect our NEW message, not existing ones
421
+ await page.waitForFunction(initialCount => {
408
422
  const messages = document.querySelectorAll('[data-message-author-role="user"]');
409
- return messages.length > 0;
410
- }, { timeout: 10000 });
423
+ return messages.length > initialCount;
424
+ }, { timeout: 10000 }, initialUserMsgCount);
411
425
  response.appendResponseLine('✅ 質問送信完了');
412
426
  // Step 5: Monitor streaming with progress updates
413
427
  response.appendResponseLine('ChatGPTの回答を待機中... (10秒ごとに進捗を表示)');
@@ -420,39 +434,45 @@ export const askChatGPTWeb = defineTool({
420
434
  await new Promise(resolve => setTimeout(resolve, 500));
421
435
  }
422
436
  isFirstCheck = false;
423
- const status = await page.evaluate(() => {
437
+ const status = await page.evaluate(initialAssistantCount => {
424
438
  // Streaming detection - check for stop button by data-testid
425
439
  // When ChatGPT is generating, send-button becomes stop-button
426
440
  const stopButton = document.querySelector('button[data-testid="stop-button"]');
427
441
  const isStreaming = !!stopButton;
428
442
  if (!isStreaming) {
429
- // Get final response
443
+ // Get final response - only look at NEW messages
430
444
  const assistantMessages = document.querySelectorAll('[data-message-author-role="assistant"]');
431
- if (assistantMessages.length === 0)
445
+ // Check if we have a NEW assistant message (not old ones)
446
+ if (assistantMessages.length <= initialAssistantCount) {
432
447
  return { completed: false };
433
- const latestMessage = assistantMessages[assistantMessages.length - 1];
434
- const thinkingButton = latestMessage.querySelector('button[aria-label*="思考時間"]');
448
+ }
449
+ // Get the NEW message (first one after initial count)
450
+ const newMessage = assistantMessages[initialAssistantCount];
451
+ const thinkingButton = newMessage.querySelector('button[aria-label*="思考時間"]');
435
452
  const thinkingTime = thinkingButton
436
453
  ? parseInt((thinkingButton.textContent || '').match(/\d+/)?.[0] || '0')
437
454
  : undefined;
438
455
  return {
439
456
  completed: true,
440
- text: latestMessage.textContent || '',
457
+ text: newMessage.textContent || '',
441
458
  thinkingTime,
442
459
  };
443
460
  }
444
- // Get current text
461
+ // Get current text from NEW message during streaming
445
462
  const assistantMessages = document.querySelectorAll('[data-message-author-role="assistant"]');
446
- const latestMessage = assistantMessages[assistantMessages.length - 1];
447
- const currentText = latestMessage
448
- ? latestMessage.textContent?.substring(0, 200)
463
+ // Only check new messages
464
+ const newMessage = assistantMessages.length > initialAssistantCount
465
+ ? assistantMessages[initialAssistantCount]
466
+ : null;
467
+ const currentText = newMessage
468
+ ? newMessage.textContent?.substring(0, 200)
449
469
  : '';
450
470
  return {
451
471
  completed: false,
452
472
  streaming: true,
453
473
  currentText,
454
474
  };
455
- });
475
+ }, initialAssistantMsgCount);
456
476
  if (status.completed) {
457
477
  response.appendResponseLine(`\n✅ 回答完了 (所要時間: ${Math.floor((Date.now() - startTime) / 1000)}秒)`);
458
478
  if (status.thinkingTime) {
@@ -530,8 +550,26 @@ export const askChatGPTWeb = defineTool({
530
550
  }
531
551
  }
532
552
  catch (error) {
533
- const errorMessage = error instanceof Error ? error.message : String(error);
534
- response.appendResponseLine(`❌ エラー: ${errorMessage}`);
553
+ const msg = error instanceof Error ? error.message : String(error);
554
+ // ケース分類:致命的エラーには明確なメッセージを表示
555
+ if (msg.includes('No page selected') || msg.includes('page is null')) {
556
+ response.appendResponseLine('❌ ブラウザタブがありません');
557
+ response.appendResponseLine('→ MCPサーバーを再起動してブラウザを開いてください');
558
+ }
559
+ else if (msg.includes('Target closed') ||
560
+ msg.includes('Session closed') ||
561
+ msg.includes('Connection closed')) {
562
+ response.appendResponseLine('❌ ブラウザ接続が切れました');
563
+ response.appendResponseLine('→ MCPサーバーを再起動してください');
564
+ }
565
+ else if (msg.includes('Protocol error') ||
566
+ msg.includes('Browser disconnected')) {
567
+ response.appendResponseLine('❌ ブラウザとの通信エラー');
568
+ response.appendResponseLine('→ MCPサーバーを再起動してください');
569
+ }
570
+ else {
571
+ response.appendResponseLine(`❌ エラー: ${msg}`);
572
+ }
535
573
  }
536
574
  },
537
575
  });
@@ -468,23 +468,50 @@ export const askGeminiWeb = defineTool({
468
468
  response.appendResponseLine(`📝 会話ログ保存: ${logPath}`);
469
469
  }
470
470
  catch (error) {
471
- const errorMessage = error instanceof Error ? error.message : String(error);
472
- response.appendResponseLine(`❌ エラー: ${errorMessage}`);
473
- // Error snapshot
474
- try {
475
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
476
- const debugDir = path.join(process.cwd(), 'docs/ask/gemini/debug');
477
- await fs.promises.mkdir(debugDir, { recursive: true });
478
- const screenshotPath = path.join(debugDir, `error-${timestamp}.png`);
479
- await page.screenshot({ path: screenshotPath });
480
- response.appendResponseLine(`📸 エラー時のスクリーンショット: ${screenshotPath}`);
481
- const htmlPath = path.join(debugDir, `error-${timestamp}.html`);
482
- const html = await page.content();
483
- await fs.promises.writeFile(htmlPath, html, 'utf-8');
484
- response.appendResponseLine(`📄 エラー時のHTML: ${htmlPath}`);
471
+ const msg = error instanceof Error ? error.message : String(error);
472
+ // ケース分類:致命的エラーには明確なメッセージを表示
473
+ const isFatalError = msg.includes('No page selected') ||
474
+ msg.includes('page is null') ||
475
+ msg.includes('Target closed') ||
476
+ msg.includes('Session closed') ||
477
+ msg.includes('Connection closed') ||
478
+ msg.includes('Protocol error') ||
479
+ msg.includes('Browser disconnected');
480
+ if (msg.includes('No page selected') || msg.includes('page is null')) {
481
+ response.appendResponseLine('❌ ブラウザタブがありません');
482
+ response.appendResponseLine('→ MCPサーバーを再起動してブラウザを開いてください');
483
+ }
484
+ else if (msg.includes('Target closed') ||
485
+ msg.includes('Session closed') ||
486
+ msg.includes('Connection closed')) {
487
+ response.appendResponseLine('❌ ブラウザ接続が切れました');
488
+ response.appendResponseLine('→ MCPサーバーを再起動してください');
485
489
  }
486
- catch (snapshotError) {
487
- console.error('Failed to capture error snapshot:', snapshotError);
490
+ else if (msg.includes('Protocol error') ||
491
+ msg.includes('Browser disconnected')) {
492
+ response.appendResponseLine('❌ ブラウザとの通信エラー');
493
+ response.appendResponseLine('→ MCPサーバーを再起動してください');
494
+ }
495
+ else {
496
+ response.appendResponseLine(`❌ エラー: ${msg}`);
497
+ }
498
+ // Error snapshot(致命的エラーの場合はスキップ)
499
+ if (!isFatalError) {
500
+ try {
501
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
502
+ const debugDir = path.join(process.cwd(), 'docs/ask/gemini/debug');
503
+ await fs.promises.mkdir(debugDir, { recursive: true });
504
+ const screenshotPath = path.join(debugDir, `error-${timestamp}.png`);
505
+ await page.screenshot({ path: screenshotPath });
506
+ response.appendResponseLine(`📸 エラー時のスクリーンショット: ${screenshotPath}`);
507
+ const htmlPath = path.join(debugDir, `error-${timestamp}.html`);
508
+ const html = await page.content();
509
+ await fs.promises.writeFile(htmlPath, html, 'utf-8');
510
+ response.appendResponseLine(`📄 エラー時のHTML: ${htmlPath}`);
511
+ }
512
+ catch (snapshotError) {
513
+ console.error('Failed to capture error snapshot:', snapshotError);
514
+ }
488
515
  }
489
516
  }
490
517
  },
@@ -129,7 +129,6 @@ export const resizePage = defineTool({
129
129
  },
130
130
  handler: async (request, response, context) => {
131
131
  const page = context.getSelectedPage();
132
- // @ts-expect-error internal API for now.
133
132
  await page.resize({
134
133
  contentWidth: request.params.width,
135
134
  contentHeight: request.params.height,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-ai-bridge",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "MCP server bridging Chrome browser and AI assistants (ChatGPT, Gemini). Browser automation + AI consultation.",
5
5
  "type": "module",
6
6
  "bin": "./scripts/cli.mjs",