chrome-ai-bridge 1.0.3 → 1.0.5

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 (74) 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/annotations/AnnotationRepository.js +163 -0
  38. package/build/node_modules/chrome-devtools-frontend/front_end/models/annotations/AnnotationType.js +10 -0
  39. package/build/node_modules/chrome-devtools-frontend/front_end/models/annotations/annotations.js +5 -0
  40. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +5 -3
  41. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/DebuggerWorkspaceBinding.js +7 -3
  42. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/DeviceModeModel.js +1 -1
  43. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/EmulatedDevices.js +14 -0
  44. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +8 -5
  45. package/build/node_modules/chrome-devtools-frontend/front_end/models/greendev/Prototypes.js +33 -0
  46. package/build/node_modules/chrome-devtools-frontend/front_end/models/greendev/greendev.js +4 -0
  47. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceImpl.js +70 -1
  48. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceModel.js +82 -30
  49. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/EventsSerializer.js +7 -2
  50. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/LanternComputationData.js +2 -2
  51. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Processor.js +18 -19
  52. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Styles.js +12 -4
  53. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/Initiators.js +46 -0
  54. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +4 -3
  55. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/extras.js +1 -0
  56. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LargestImagePaintHandler.js +2 -2
  57. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LayoutShiftsHandler.js +1 -1
  58. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +6 -0
  59. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/NetworkRequestsHandler.js +10 -1
  60. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/PageLoadMetricsHandler.js +44 -27
  61. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/helpers/Timing.js +9 -2
  62. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Common.js +1 -6
  63. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +2 -2
  64. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +2 -4
  65. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +3 -2
  66. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +1 -1
  67. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/types/TraceEvents.js +30 -11
  68. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +28 -13
  69. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +1 -1
  70. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +4 -0
  71. package/build/src/tools/chatgpt-web.js +68 -49
  72. package/build/src/tools/gemini-web.js +66 -22
  73. package/build/src/tools/pages.js +0 -1
  74. package/package.json +1 -1
@@ -69,13 +69,12 @@ class Decoder {
69
69
  decode() {
70
70
  const iter = new TokenIterator(this.#encodedScopes);
71
71
  while (iter.hasNext()) {
72
- if (iter.peek() === ",") {
73
- iter.nextChar(); // Consume ",".
74
- this.#scopes.push(null); // Add an EmptyItem;
75
- continue;
76
- }
77
72
  const tag = iter.nextUnsignedVLQ();
78
73
  switch (tag) {
74
+ case 0 /* Tag.EMPTY */: {
75
+ this.#scopes.push(null);
76
+ break;
77
+ }
79
78
  case 1 /* Tag.ORIGINAL_SCOPE_START */: {
80
79
  const item = {
81
80
  flags: iter.nextUnsignedVLQ(),
@@ -158,6 +157,14 @@ class Decoder {
158
157
  this.#handleGeneratedRangeCallSite(iter.nextUnsignedVLQ(), iter.nextUnsignedVLQ(), iter.nextUnsignedVLQ());
159
158
  break;
160
159
  }
160
+ case 99 /* Tag.VENDOR_EXTENSION */: {
161
+ const _extensionNameIdx = iter.nextUnsignedVLQ();
162
+ break;
163
+ }
164
+ default: {
165
+ this.#throwInStrictMode(`Encountered illegal item tag ${tag}`);
166
+ break;
167
+ }
161
168
  }
162
169
  // Consume any trailing VLQ and the the ","
163
170
  while (iter.hasNext() && iter.peek() !== ",")
@@ -165,10 +172,6 @@ class Decoder {
165
172
  if (iter.hasNext())
166
173
  iter.nextChar();
167
174
  }
168
- if (iter.currentChar() === ",") {
169
- // Handle trailing EmptyItem.
170
- this.#scopes.push(null);
171
- }
172
175
  if (this.#scopeStack.length > 0) {
173
176
  this.#throwInStrictMode("Encountered ORIGINAL_SCOPE_START without matching END!");
174
177
  }
@@ -285,7 +288,6 @@ class Decoder {
285
288
  }
286
289
  }
287
290
  this.#rangeStack.push(range);
288
- this.#subRangeBindingsForRange.clear();
289
291
  }
290
292
  #handleGeneratedRangeBindingsItem(valueIdxs) {
291
293
  const range = this.#rangeStack.at(-1);
@@ -303,11 +305,21 @@ class Decoder {
303
305
  }
304
306
  }
305
307
  #recordGeneratedSubRangeBindingItem(variableIndex, bindings) {
306
- if (this.#subRangeBindingsForRange.has(variableIndex)) {
308
+ const range = this.#rangeStack.at(-1);
309
+ if (!range) {
310
+ this.#throwInStrictMode("Encountered GENERATED_RANGE_SUBRANGE_BINDING without surrounding GENERATED_RANGE_START");
311
+ return;
312
+ }
313
+ let subRangeBindings = this.#subRangeBindingsForRange.get(range);
314
+ if (!subRangeBindings) {
315
+ subRangeBindings = new Map();
316
+ this.#subRangeBindingsForRange.set(range, subRangeBindings);
317
+ }
318
+ if (subRangeBindings.has(variableIndex)) {
307
319
  this.#throwInStrictMode("Encountered multiple GENERATED_RANGE_SUBRANGE_BINDING items for the same variable");
308
320
  return;
309
321
  }
310
- this.#subRangeBindingsForRange.set(variableIndex, bindings);
322
+ subRangeBindings.set(variableIndex, bindings);
311
323
  }
312
324
  #handleGeneratedRangeCallSite(sourceIndex, line, column) {
313
325
  const range = this.#rangeStack.at(-1);
@@ -349,7 +361,10 @@ class Decoder {
349
361
  }
350
362
  }
351
363
  #handleGeneratedRangeSubRangeBindings(range) {
352
- for (const [variableIndex, bindings] of this.#subRangeBindingsForRange) {
364
+ const subRangeBindings = this.#subRangeBindingsForRange.get(range);
365
+ if (!subRangeBindings)
366
+ return;
367
+ for (const [variableIndex, bindings] of subRangeBindings) {
353
368
  const value = range.values[variableIndex];
354
369
  const subRanges = [];
355
370
  range.values[variableIndex] = subRanges;
@@ -48,7 +48,7 @@ export class Encoder {
48
48
  }
49
49
  #encodeOriginalScope(scope) {
50
50
  if (scope === null) {
51
- this.#encodedItems.push("");
51
+ this.#encodedItems.push("A" /* EncodedTag.EMPTY */);
52
52
  return;
53
53
  }
54
54
  this.#encodeOriginalScopeStart(scope);
@@ -0,0 +1,4 @@
1
+ // Copyright 2025 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+ export {};
@@ -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;
327
+ catch {
328
+ if (attempt < 2) {
329
+ response.appendResponseLine(`⏳ 入力欄を待機中... (${attempt + 1}/3)`);
330
+ await new Promise(r => setTimeout(r, 2000));
317
331
  }
318
- catch {
319
- if (attempt < 2) {
320
- response.appendResponseLine(`⏳ 入力欄を待機中... (${attempt + 1}/3)`);
321
- await new Promise(r => setTimeout(r, 2000));
322
- }
323
- }
324
- }
325
- if (!inputFieldReady) {
326
- response.appendResponseLine('⚠️ 入力欄の準備に時間がかかっています。続行を試みます...');
327
332
  }
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 "新しいチャット"
@@ -549,8 +550,26 @@ export const askChatGPTWeb = defineTool({
549
550
  }
550
551
  }
551
552
  catch (error) {
552
- const errorMessage = error instanceof Error ? error.message : String(error);
553
- 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
+ }
554
573
  }
555
574
  },
556
575
  });
@@ -304,6 +304,10 @@ export const askGeminiWeb = defineTool({
304
304
  return;
305
305
  }
306
306
  await new Promise(resolve => setTimeout(resolve, 500));
307
+ // 質問送信前に model-response 要素数を記録(ChatGPTと同じカウント方式)
308
+ const initialModelResponseCount = await page.evaluate(() => {
309
+ return document.querySelectorAll('model-response').length;
310
+ });
307
311
  // Click send button - look for "プロンプトを送信" or similar
308
312
  const sent = await page.evaluate(() => {
309
313
  const buttons = Array.from(document.querySelectorAll('button'));
@@ -405,9 +409,17 @@ export const askGeminiWeb = defineTool({
405
409
  });
406
410
  return !!stopButton;
407
411
  });
408
- // Stop button/icon disappeared = generation complete
412
+ // Stop button/icon disappeared = check if new message appeared
409
413
  if (!hasStopIndicator) {
410
- break;
414
+ // 追加: model-response 要素数が増えたか確認(ChatGPTと同じ方式)
415
+ const currentModelResponseCount = await page.evaluate(() => {
416
+ return document.querySelectorAll('model-response').length;
417
+ });
418
+ if (currentModelResponseCount > initialModelResponseCount) {
419
+ // ストップボタン消滅 AND 新規メッセージ出現で完了
420
+ break;
421
+ }
422
+ // メッセージ数が増えていなければ、まだ待機続行
411
423
  }
412
424
  if (Date.now() - startTime > 180000) {
413
425
  // 3 mins timeout
@@ -415,19 +427,24 @@ export const askGeminiWeb = defineTool({
415
427
  break;
416
428
  }
417
429
  }
418
- // Get the final response content
419
- const responseText = await page.evaluate(() => {
430
+ // Get the final response content (新規に追加された model-response のみを取得)
431
+ const responseText = await page.evaluate(initialCount => {
420
432
  // Get content from model-response elements
421
433
  const modelResponses = Array.from(document.querySelectorAll('model-response'));
434
+ if (modelResponses.length > initialCount) {
435
+ // 新規に追加された model-response を取得(ChatGPTと同じ方式)
436
+ const newResponse = modelResponses[initialCount];
437
+ return newResponse.textContent?.trim() || '';
438
+ }
439
+ // Fallback: get the last model response if any
422
440
  if (modelResponses.length > 0) {
423
- // Get the last model response
424
441
  const lastResponse = modelResponses[modelResponses.length - 1];
425
442
  return lastResponse.textContent?.trim() || '';
426
443
  }
427
444
  // Fallback: get text from main area
428
445
  const main = document.querySelector('main');
429
446
  return main?.innerText.slice(-5000) || '';
430
- });
447
+ }, initialModelResponseCount);
431
448
  response.appendResponseLine('✅ 回答完了');
432
449
  // Always save/update session (not just for new chats)
433
450
  const chatUrl = page.url();
@@ -468,23 +485,50 @@ export const askGeminiWeb = defineTool({
468
485
  response.appendResponseLine(`📝 会話ログ保存: ${logPath}`);
469
486
  }
470
487
  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}`);
488
+ const msg = error instanceof Error ? error.message : String(error);
489
+ // ケース分類:致命的エラーには明確なメッセージを表示
490
+ const isFatalError = msg.includes('No page selected') ||
491
+ msg.includes('page is null') ||
492
+ msg.includes('Target closed') ||
493
+ msg.includes('Session closed') ||
494
+ msg.includes('Connection closed') ||
495
+ msg.includes('Protocol error') ||
496
+ msg.includes('Browser disconnected');
497
+ if (msg.includes('No page selected') || msg.includes('page is null')) {
498
+ response.appendResponseLine('❌ ブラウザタブがありません');
499
+ response.appendResponseLine('→ MCPサーバーを再起動してブラウザを開いてください');
485
500
  }
486
- catch (snapshotError) {
487
- console.error('Failed to capture error snapshot:', snapshotError);
501
+ else if (msg.includes('Target closed') ||
502
+ msg.includes('Session closed') ||
503
+ msg.includes('Connection closed')) {
504
+ response.appendResponseLine('❌ ブラウザ接続が切れました');
505
+ response.appendResponseLine('→ MCPサーバーを再起動してください');
506
+ }
507
+ else if (msg.includes('Protocol error') ||
508
+ msg.includes('Browser disconnected')) {
509
+ response.appendResponseLine('❌ ブラウザとの通信エラー');
510
+ response.appendResponseLine('→ MCPサーバーを再起動してください');
511
+ }
512
+ else {
513
+ response.appendResponseLine(`❌ エラー: ${msg}`);
514
+ }
515
+ // Error snapshot(致命的エラーの場合はスキップ)
516
+ if (!isFatalError) {
517
+ try {
518
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
519
+ const debugDir = path.join(process.cwd(), 'docs/ask/gemini/debug');
520
+ await fs.promises.mkdir(debugDir, { recursive: true });
521
+ const screenshotPath = path.join(debugDir, `error-${timestamp}.png`);
522
+ await page.screenshot({ path: screenshotPath });
523
+ response.appendResponseLine(`📸 エラー時のスクリーンショット: ${screenshotPath}`);
524
+ const htmlPath = path.join(debugDir, `error-${timestamp}.html`);
525
+ const html = await page.content();
526
+ await fs.promises.writeFile(htmlPath, html, 'utf-8');
527
+ response.appendResponseLine(`📄 エラー時のHTML: ${htmlPath}`);
528
+ }
529
+ catch (snapshotError) {
530
+ console.error('Failed to capture error snapshot:', snapshotError);
531
+ }
488
532
  }
489
533
  }
490
534
  },
@@ -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.3",
3
+ "version": "1.0.5",
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",