@weavetab/mcp 2.5.0-beta.2 → 2.5.0-beta.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 (127) hide show
  1. package/AGENTS.md +1 -1
  2. package/ARCHITECTURE.md +6 -6
  3. package/LICENSE +216 -631
  4. package/README.md +153 -1074
  5. package/SECURITY.md +33 -22
  6. package/TROUBLESHOOTING.md +2 -2
  7. package/dist/cdp/bridge.js +2 -1
  8. package/dist/cdp/connector.d.ts +2 -0
  9. package/dist/cdp/connector.js +10 -6
  10. package/dist/cdp/helpers.d.ts +4 -0
  11. package/dist/cdp/helpers.js +181 -0
  12. package/dist/cdp/omni_broker.d.ts +1 -1
  13. package/dist/cdp/omni_broker.js +1 -1
  14. package/dist/cdp/walker.d.ts +25 -1
  15. package/dist/cdp/walker.js +304 -7
  16. package/dist/cli/plugin.d.ts +1 -0
  17. package/dist/cli/plugin.js +81 -18
  18. package/dist/cli/updater.d.ts +1 -1
  19. package/dist/cli/updater.js +27 -7
  20. package/dist/config/loader.d.ts +9 -1
  21. package/dist/config/loader.js +42 -3
  22. package/dist/desktop/discovery.d.ts +44 -0
  23. package/dist/desktop/discovery.js +364 -0
  24. package/dist/index.js +137 -21
  25. package/dist/intelligence/marks.d.ts +36 -0
  26. package/dist/intelligence/marks.js +30 -0
  27. package/dist/intelligence/patternCompiler.d.ts +118 -0
  28. package/dist/intelligence/patternCompiler.js +259 -0
  29. package/dist/intelligence/sessionMemory.d.ts +2 -0
  30. package/dist/intelligence/sessionMemory.js +18 -8
  31. package/dist/overlay/injector.js +2 -2
  32. package/dist/plugin/interface.d.ts +88 -5
  33. package/dist/plugin/loader.d.ts +12 -1
  34. package/dist/plugin/loader.js +280 -70
  35. package/dist/plugin/pipeline.d.ts +75 -0
  36. package/dist/plugin/pipeline.js +183 -0
  37. package/dist/plugin/registry.d.ts +2 -1
  38. package/dist/plugin/registry.js +24 -14
  39. package/dist/security/secrets.d.ts +7 -0
  40. package/dist/security/secrets.js +37 -0
  41. package/dist/sensors/actionability.js +1 -2
  42. package/dist/sensors/guard.js +4 -10
  43. package/dist/sensors/mutations.js +12 -0
  44. package/dist/sensors/operation_monitor.js +1 -0
  45. package/dist/server.d.ts +1 -1
  46. package/dist/server.js +453 -178
  47. package/dist/state/agent.d.ts +1 -0
  48. package/dist/state/agent.js +3 -0
  49. package/dist/state/delta.d.ts +12 -4
  50. package/dist/state/delta.js +67 -14
  51. package/dist/state/session.d.ts +6 -0
  52. package/dist/state/session.js +27 -0
  53. package/dist/tools/browser_detect.d.ts +16 -3
  54. package/dist/tools/browser_detect.js +52 -7
  55. package/dist/tools/burst.d.ts +17 -8
  56. package/dist/tools/burst.js +236 -77
  57. package/dist/tools/captcha.js +1 -1
  58. package/dist/tools/checkpoint.d.ts +38 -0
  59. package/dist/tools/checkpoint.js +271 -0
  60. package/dist/tools/click.d.ts +1 -0
  61. package/dist/tools/click.js +74 -70
  62. package/dist/tools/design_extract.js +1 -1
  63. package/dist/tools/eval.js +1 -1
  64. package/dist/tools/fill.d.ts +20 -1
  65. package/dist/tools/fill.js +199 -40
  66. package/dist/tools/find.d.ts +16 -0
  67. package/dist/tools/find.js +67 -44
  68. package/dist/tools/github/index.d.ts +19 -4
  69. package/dist/tools/github/index.js +40 -4
  70. package/dist/tools/highlight.d.ts +6 -2
  71. package/dist/tools/highlight.js +158 -72
  72. package/dist/tools/inspect.js +1 -1
  73. package/dist/tools/key.js +65 -56
  74. package/dist/tools/navigate.d.ts +1 -1
  75. package/dist/tools/navigate.js +34 -39
  76. package/dist/tools/pdf.js +21 -13
  77. package/dist/tools/pointer.d.ts +18 -3
  78. package/dist/tools/pointer.js +89 -1
  79. package/dist/tools/read.d.ts +28 -8
  80. package/dist/tools/read.js +230 -56
  81. package/dist/tools/scrape.js +67 -13
  82. package/dist/tools/screenshot.js +21 -16
  83. package/dist/tools/scroll.js +6 -11
  84. package/dist/tools/select.js +8 -2
  85. package/dist/tools/snapshot.js +3 -34
  86. package/dist/tools/tabs.js +15 -7
  87. package/dist/tools/thought.d.ts +2 -0
  88. package/dist/tools/thought.js +13 -14
  89. package/dist/tools/type.d.ts +2 -0
  90. package/dist/tools/type.js +107 -58
  91. package/dist/tools/type_secret.js +42 -76
  92. package/dist/tools/upload.js +1 -1
  93. package/dist/tools/video_compiler.d.ts +1 -1
  94. package/dist/tools/video_compiler.js +11 -12
  95. package/dist/version.d.ts +5 -0
  96. package/dist/version.js +5 -0
  97. package/docs/DOCUMENTATION.md +37 -41
  98. package/docs/PLUGINS.md +121 -0
  99. package/docs/TOOLS.md +54 -0
  100. package/docs/architecture/blind-injection.md +83 -20
  101. package/docs/architecture/overview.md +49 -49
  102. package/docs/architecture/security.md +8 -7
  103. package/docs/architecture/transport.md +2 -2
  104. package/docs/cli/cli-commands.md +7 -1
  105. package/docs/cli/cli-flags.md +15 -7
  106. package/docs/cli/cli-scripting.md +6 -3
  107. package/docs/configuration/config-locations.md +3 -4
  108. package/docs/configuration/env-variables.md +4 -4
  109. package/docs/configuration/folders.md +55 -54
  110. package/docs/desktop-automation/electron-apps.md +214 -162
  111. package/docs/get-started/introduction.md +60 -60
  112. package/docs/get-started/setup-wizard.md +7 -6
  113. package/docs/intelligence/site-profiles.md +151 -0
  114. package/docs/tools/tools.md +631 -293
  115. package/docs/troubleshooting/trouble-browser.md +1 -1
  116. package/docs/troubleshooting/trouble-loop.md +31 -31
  117. package/ext-dist/background.js +10 -62
  118. package/ext-dist/content.js +333 -920
  119. package/ext-dist/hud/hud.js +9 -9
  120. package/ext-dist/manifest.json +2 -6
  121. package/ext-dist/styles.css +6 -1
  122. package/icon.png +0 -0
  123. package/mcp.json +87 -71
  124. package/package.json +118 -119
  125. package/server.json +5 -5
  126. package/ext-dist/sidepanel/sidepanel.js +0 -25
  127. package/ext-dist/sidepanel.html +0 -547
@@ -226,19 +226,18 @@ function __wt_safeAppendToBody(el) {
226
226
  if (msg.type === 'TOOL_CALL_EVENT' && iframe && iframe.contentWindow) {
227
227
  iframe.contentWindow.postMessage({ type: 'TOOL_CALL_EVENT', payload: msg.payload }, '*');
228
228
  }
229
- // Relay sidepanel open/close state to HUD iframe so it can gate browser_thought pill
230
- if (msg.type === 'WT_SIDEPANEL_STATE' && iframe && iframe.contentWindow) {
231
- iframe.contentWindow.postMessage({ type: 'WT_SIDEPANEL_STATE', open: msg.open }, '*');
232
- }
233
- // Background tells us to suppress the thought pill for this specific event
234
- if (msg.type === 'WT_SUPPRESS_THOUGHT_HUD' && iframe && iframe.contentWindow) {
235
- iframe.contentWindow.postMessage({ type: 'WT_SUPPRESS_THOUGHT_HUD' }, '*');
236
- }
237
- // Scripted pill toggle from sidepanel settings — relay to HUD iframe
229
+ // Scripted pill toggle — relay to HUD iframe
238
230
  if (msg.type === 'WT_SCRIPTED_PILL_TOGGLE' && iframe && iframe.contentWindow) {
239
231
  iframe.contentWindow.postMessage({ type: 'WT_SCRIPTED_PILL_TOGGLE', enabled: msg.enabled }, '*');
240
232
  }
241
- // Handle incoming user notes sent from the sidepanel input
233
+ // Handle agent thoughts in middle-down HUD
234
+ if (msg.type === 'WT_THOUGHT' || msg.type === 'Weavetab_THOUGHT') {
235
+ __wt_showThought(msg.text, msg);
236
+ }
237
+ if (msg.type === 'WT_CLEAR_THOUGHT' || msg.type === 'Weavetab_CLEAR_THOUGHT') {
238
+ __wt_removeThought();
239
+ }
240
+ // Handle incoming user notes from the extension
242
241
  if (msg.type === 'WT_USER_NOTE_INJECT' || msg.type === 'WT_USER_NOTE') {
243
242
  window.__wt_chat_queue = window.__wt_chat_queue || [];
244
243
  let formattedMsg = msg.text || '';
@@ -299,7 +298,7 @@ function __wt_safeAppendToBody(el) {
299
298
 
300
299
  // State persistence bridge: listen for state changes from iframe
301
300
  window.addEventListener('message', function(e) {
302
- // Forward relevant events to the extension background/sidepanel
301
+ // Forward relevant events to the extension background
303
302
  if (e.data && (
304
303
  e.data.type === 'WT_TOOL_CALL' ||
305
304
  e.data.type === 'WT_PLAN_UPDATE' ||
@@ -477,133 +476,240 @@ function __wt_destroyBubble() {
477
476
  __wt_lastRemoveTime = Date.now();
478
477
  }
479
478
 
479
+ // ── MIDDLE-DOWN THOUGHT & PRESENCE HUD ─────────────────────────────
480
+ let __wt_thoughtHudEl = null;
481
+ let __wt_thoughtHudTimer = null;
482
+ let __wt_thoughtHudCountdown = null;
483
+
484
+ function __wt_highlightAnchor(anchor) {
485
+ if (!anchor) return;
486
+ try {
487
+ let sel = anchor;
488
+ if (anchor.startsWith('w:')) {
489
+ const stripped = anchor.slice(2);
490
+ sel = `[data-wt-id="${stripped}"]`;
491
+ }
492
+ const el = document.querySelector(sel) || (window.__Weavetab_shadowQuery ? window.__Weavetab_shadowQuery(sel) : null);
493
+ if (!el) return;
494
+ const r = el.getBoundingClientRect();
495
+ if (r.width === 0 && r.height === 0) return;
496
+
497
+ const ring = document.createElement('div');
498
+ ring.setAttribute('data-wt-ignore', 'true');
499
+ ring.style.cssText = `position:fixed;left:${r.left}px;top:${r.top}px;width:${r.width}px;height:${r.height}px;border:1.5px solid #38bdf8;box-shadow:0 0 16px rgba(56,189,248,0.5);border-radius:4px;z-index:2147483646;pointer-events:none;animation:wt-consider-pulse 1.2s ease-in-out infinite;`;
500
+ (document.getElementById('Weavetab-root')?.shadowRoot || document.body || document.documentElement).appendChild(ring);
501
+ setTimeout(() => {
502
+ ring.style.transition = 'opacity 0.25s ease-out';
503
+ ring.style.opacity = '0';
504
+ setTimeout(() => ring.remove(), 260);
505
+ }, 2400);
506
+ } catch(e) {}
507
+ }
508
+
480
509
  function __wt_removeThought() {
481
- if (__wt_feedbackSticky) return;
482
- if (__wt_thoughtBirth && Date.now() - __wt_thoughtBirth < 300) return;
510
+ if (__wt_thoughtHudTimer) {
511
+ clearTimeout(__wt_thoughtHudTimer);
512
+ __wt_thoughtHudTimer = null;
513
+ }
514
+ if (__wt_thoughtHudCountdown) {
515
+ clearInterval(__wt_thoughtHudCountdown);
516
+ __wt_thoughtHudCountdown = null;
517
+ }
518
+ if (__wt_thoughtHudEl) {
519
+ const el = __wt_thoughtHudEl;
520
+ __wt_thoughtHudEl = null;
521
+ el.style.opacity = '0';
522
+ el.style.transform = 'translateX(-50%) translateY(10px)';
523
+ setTimeout(() => {
524
+ if (el.parentNode) el.remove();
525
+ }, 220);
526
+ }
527
+ __wt_feedbackSticky = false;
528
+ clearTimeout(window.__wt_feedbackStickyTimer);
483
529
  __wt_destroyBubble();
484
530
  }
485
531
 
486
532
  function __wt_showThought(text, options) {
487
- // On-page thought bubbles removed — all tool calls/thoughts display inside sidepanel logs
488
- return;
489
- }
533
+ if (typeof __wt_masterVisualsEnabled !== 'undefined' && !__wt_masterVisualsEnabled) return;
534
+ if (!text || typeof text !== 'string') return;
490
535
 
491
- function __wt_renderThought(text, options) {
492
- // On-page thought bubbles removed — all tool calls/thoughts display inside sidepanel logs
493
- return;
494
- }
536
+ const opts = options || {};
537
+ const isQuestion = opts.action === 'question' || opts.kind === 'question' || !!opts.ask;
538
+ const anchor = opts.anchor || '';
495
539
 
496
- function __wt_processThoughtQueue() {
497
- if (__wt_thoughtQueue.length > 0) {
498
- var next = __wt_thoughtQueue.shift();
499
- setTimeout(function() { __wt_renderThought(next.text, next.options); }, 200);
540
+ // Contextual visual anchor highlight
541
+ if (anchor) {
542
+ __wt_highlightAnchor(anchor);
500
543
  }
501
- }
502
544
 
503
- // ── QUESTION INPUT (merged into thought bubble system) ────────
504
- let __wt_askContainer = null;
505
- let __wt_askTimer = null;
506
- let __wt_askBridge = null;
545
+ // Clear pending timers
546
+ if (__wt_thoughtHudTimer) {
547
+ clearTimeout(__wt_thoughtHudTimer);
548
+ __wt_thoughtHudTimer = null;
549
+ }
550
+ if (__wt_thoughtHudCountdown) {
551
+ clearInterval(__wt_thoughtHudCountdown);
552
+ __wt_thoughtHudCountdown = null;
553
+ }
507
554
 
508
- function __wt_showQuestion(text, inputType, timeoutSeconds) {
509
- __wt_removeAsk();
510
- __wt_feedbackSticky = true;
511
- var ts = timeoutSeconds || 120;
512
-
513
- // DOM bridge
514
- __wt_askBridge = document.getElementById('__wt_ask_bridge');
515
- if (!__wt_askBridge) {
516
- __wt_askBridge = document.createElement('div');
517
- __wt_askBridge.id = '__wt_ask_bridge';
518
- __wt_askBridge.style.display = 'none';
519
- document.body.appendChild(__wt_askBridge);
520
- }
521
- __wt_askBridge.dataset.status = 'pending';
522
- __wt_askBridge.dataset.result = '';
523
-
524
- // Update HUD to "waiting..." so the top bar doesn't show question text twice
525
- updateHUD('waiting for your input...');
526
-
527
- // Render green thought bubble (same as sticky feedback — 0ms delay)
528
- __wt_renderThought(text, { active: false, sticky: true });
529
-
530
- // Countdown timer
531
- var remaining = ts;
532
- __wt_askTimer = setInterval(function() {
533
- remaining--;
534
- if (remaining <= 0) {
535
- clearInterval(__wt_askTimer);
536
- __wt_askTimer = null;
537
- if (__wt_askBridge) { __wt_askBridge.dataset.status = 'timeout'; __wt_askBridge.dataset.result = ''; }
538
- __wt_removeAsk();
539
- }
540
- }, 1000);
541
-
542
- // Smooth input row — delays slightly so bubble appears first, then input slides up
543
- setTimeout(function() {
544
- if (!__wt_askBridge) return;
545
-
546
- var row = document.createElement('div');
547
- row.setAttribute('data-wt-ignore', '');
548
- row.style.cssText = 'position:fixed;bottom:16px;left:50%;transform:translateX(-50%) translateY(8px);z-index:2147483640;display:flex;align-items:center;gap:0;pointer-events:auto;opacity:0;transition:opacity 0.25s ease-out, transform 0.25s ease-out;';
549
-
550
- var input;
551
- if (inputType === 'paragraph') {
552
- input = document.createElement('textarea');
553
- input.rows = 3;
554
- input.style.cssText = 'min-width:280px;max-width:480px;font-size:11px;padding:6px 8px;border-radius:4px 0 0 4px;background:#042f2e;color:#e4e4e7;border:1px solid #059669;border-right:none;outline:none;resize:vertical;font-family:"IBM Plex Mono",monospace;';
555
- input.placeholder = 'Type your response...';
556
- } else {
557
- input = document.createElement('input');
558
- input.style.cssText = 'min-width:200px;font-size:11px;padding:4px 8px;border-radius:4px 0 0 4px;background:#042f2e;color:#e4e4e7;border:1px solid #059669;border-right:none;outline:none;caret-color:#10b981;font-family:"IBM Plex Mono",monospace;';
559
- input.placeholder = 'Your answer...';
560
- }
555
+ let hud = __wt_thoughtHudEl;
556
+ if (!hud || !hud.parentNode) {
557
+ hud = document.createElement('div');
558
+ hud.id = '__wt_thought_hud';
559
+ hud.setAttribute('data-wt-ignore', 'true');
560
+ hud.style.cssText = `
561
+ position: fixed;
562
+ bottom: 24px;
563
+ left: 50%;
564
+ transform: translateX(-50%) translateY(8px);
565
+ z-index: 2147483647;
566
+ width: 320px;
567
+ max-width: calc(100vw - 32px);
568
+ background: #0b0d12;
569
+ border: 1px solid #1e222b;
570
+ border-radius: 4px;
571
+ padding: 10px 12px;
572
+ box-shadow: 0 10px 30px rgba(0,0,0,0.8), 0 0 1px rgba(255,255,255,0.08);
573
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", sans-serif;
574
+ color: #f3f4f6;
575
+ pointer-events: auto;
576
+ opacity: 0;
577
+ transition: opacity 0.18s cubic-bezier(0.16, 1, 0.3, 1), transform 0.18s cubic-bezier(0.16, 1, 0.3, 1);
578
+ box-sizing: border-box;
579
+ `;
580
+ (document.getElementById('Weavetab-root')?.shadowRoot || document.body || document.documentElement).appendChild(hud);
581
+ __wt_thoughtHudEl = hud;
582
+ }
561
583
 
562
- var btn = document.createElement('button');
563
- btn.style.cssText = 'padding:4px 10px;background:#059670;border:1px solid #059670;border-left:none;border-radius:0 4px 4px 0;color:#fff;cursor:pointer;font-size:10px;font-family:"IBM Plex Mono",monospace;';
564
- btn.textContent = 'Send';
584
+ const cleanText = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
585
+ const anchorBadge = anchor ? `<span style="color:#2b70ff;font-size:10px;font-family:monospace;font-weight:600;margin-left:4px;">@${anchor.replace(/&/g,'&amp;')}</span>` : '';
565
586
 
566
- row.appendChild(input);
567
- row.appendChild(btn);
568
- document.body.appendChild(row);
569
- __wt_askContainer = row;
587
+ if (isQuestion) {
588
+ const timeoutSec = (opts.timeout || (opts.ask && opts.ask.timeout) || 20);
589
+ hud.innerHTML = `
590
+ <div style="display:flex;align-items:flex-start;justify-content:space-between;gap:8px;margin-bottom:8px;">
591
+ <div style="font-size:12px;line-height:1.4;color:#ffffff;font-weight:500;word-break:break-word;">
592
+ ${cleanText}${anchorBadge}
593
+ </div>
594
+ <button id="wt-hud-close" title="Dismiss" style="background:transparent;border:none;color:#555d6d;font-size:12px;cursor:pointer;padding:0 2px;line-height:1;margin-top:1px;">✕</button>
595
+ </div>
596
+ <div style="display:flex;align-items:center;gap:6px;">
597
+ <input id="wt-hud-input" type="text" placeholder="Type answer..." style="height:28px;background:#14161f;border:1px solid #252a36;border-radius:3px;padding:0 8px;font-size:12px;color:#fff;outline:none;flex:1;min-width:0;caret-color:#2b70ff;font-family:inherit;box-sizing:border-box;" />
598
+ <button id="wt-hud-submit-btn" title="Send" style="width:28px;height:28px;background:#2b70ff;border:none;border-radius:3px;display:flex;align-items:center;justify-content:center;cursor:pointer;flex-shrink:0;padding:0;box-sizing:border-box;">
599
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
600
+ </button>
601
+ <span id="wt-hud-countdown" style="font-size:10px;color:#64748b;font-family:monospace;margin-left:2px;min-width:20px;text-align:right;">${timeoutSec}s</span>
602
+ </div>
603
+ `;
604
+ } else {
605
+ // Feedback / observation mode — ultra compact single row
606
+ hud.innerHTML = `
607
+ <div style="display:flex;align-items:center;justify-content:space-between;gap:8px;">
608
+ <div style="display:flex;align-items:center;gap:7px;min-width:0;">
609
+ <span style="display:inline-block;width:5px;height:5px;border-radius:50%;background:#2b70ff;box-shadow:0 0 6px #2b70ff;flex-shrink:0;"></span>
610
+ <span style="font-size:12px;line-height:1.4;color:#f3f4f6;word-break:break-word;font-weight:450;">${cleanText}${anchorBadge}</span>
611
+ </div>
612
+ <button id="wt-hud-close" title="Dismiss" style="background:transparent;border:none;color:#555d6d;font-size:12px;cursor:pointer;padding:0 2px;line-height:1;flex-shrink:0;">✕</button>
613
+ </div>
614
+ `;
615
+ }
570
616
 
571
- // Fade in
572
- requestAnimationFrame(function() {
573
- row.style.opacity = '1';
574
- row.style.transform = 'translateX(-50%) translateY(0)';
575
- });
617
+ // Animate in
618
+ requestAnimationFrame(() => {
619
+ if (hud) {
620
+ hud.style.opacity = '1';
621
+ hud.style.transform = 'translateX(-50%) translateY(0)';
622
+ }
623
+ });
576
624
 
577
- setTimeout(function() { input.focus(); }, 150);
625
+ // Wire close button
626
+ const closeBtn = hud.querySelector('#wt-hud-close');
627
+ if (closeBtn) {
628
+ closeBtn.addEventListener('click', () => {
629
+ __wt_removeThought();
630
+ });
631
+ }
578
632
 
579
- function submit() {
580
- if (__wt_askBridge) { __wt_askBridge.dataset.status = 'submitted'; __wt_askBridge.dataset.result = input.value; }
581
- __wt_removeAsk();
582
- }
583
- function cancel() {
584
- if (__wt_askBridge) { __wt_askBridge.dataset.status = 'cancelled'; __wt_askBridge.dataset.result = ''; }
585
- __wt_removeAsk();
586
- }
633
+ if (isQuestion) {
634
+ let askBridge = document.getElementById('__wt_ask_bridge');
635
+ if (!askBridge) {
636
+ askBridge = document.createElement('div');
637
+ askBridge.id = '__wt_ask_bridge';
638
+ askBridge.style.display = 'none';
639
+ document.body.appendChild(askBridge);
640
+ }
641
+ askBridge.dataset.status = 'pending';
642
+ askBridge.dataset.result = '';
643
+
644
+ const input = hud.querySelector('#wt-hud-input');
645
+ const submitBtn = hud.querySelector('#wt-hud-submit-btn');
646
+ const countdownSpan = hud.querySelector('#wt-hud-countdown');
647
+
648
+ let remaining = opts.timeout || (opts.ask && opts.ask.timeout) || 20;
649
+
650
+ __wt_thoughtHudCountdown = setInterval(() => {
651
+ remaining--;
652
+ if (countdownSpan) countdownSpan.textContent = `${remaining}s`;
653
+ if (remaining <= 0) {
654
+ clearInterval(__wt_thoughtHudCountdown);
655
+ __wt_thoughtHudCountdown = null;
656
+ if (askBridge) {
657
+ askBridge.dataset.status = 'timeout';
658
+ askBridge.dataset.result = '';
659
+ }
660
+ __wt_removeThought();
661
+ }
662
+ }, 1000);
587
663
 
588
- btn.onclick = submit;
589
- input.onkeydown = function(e) {
590
- if (e.key === 'Enter') {
591
- if (inputType === 'paragraph' && !e.ctrlKey && !e.metaKey) return;
592
- submit();
664
+ const submit = () => {
665
+ const val = input ? input.value.trim() : '';
666
+ if (askBridge) {
667
+ askBridge.dataset.status = 'submitted';
668
+ askBridge.dataset.result = val;
593
669
  }
594
- if (e.key === 'Escape') cancel();
670
+ if (window.__wt_ask_bridge && window.__wt_ask_bridge.resolve) {
671
+ window.__wt_ask_bridge.resolve({ success: true, response: val, status: 'answered' });
672
+ window.__wt_ask_bridge = {};
673
+ }
674
+ __wt_removeThought();
595
675
  };
596
- }, 400);
676
+
677
+ if (submitBtn) submitBtn.addEventListener('click', submit);
678
+ if (input) {
679
+ input.addEventListener('focus', () => { input.style.borderColor = '#2b70ff'; });
680
+ input.addEventListener('blur', () => { input.style.borderColor = '#252a36'; });
681
+ input.addEventListener('keydown', (e) => {
682
+ if (e.key === 'Enter') submit();
683
+ if (e.key === 'Escape') __wt_removeThought();
684
+ });
685
+ setTimeout(() => { if (input) input.focus(); }, 80);
686
+ }
687
+ } else {
688
+ // Auto-fade timer for feedback
689
+ const autoDuration = Math.max(3800, Math.min(8000, text.length * 50));
690
+ __wt_thoughtHudTimer = setTimeout(() => {
691
+ __wt_removeThought();
692
+ }, autoDuration);
693
+ }
694
+ }
695
+
696
+ function __wt_renderThought(text, options) {
697
+ __wt_showThought(text, options);
698
+ }
699
+
700
+ function __wt_processThoughtQueue() {
701
+ if (__wt_thoughtQueue.length > 0) {
702
+ var next = __wt_thoughtQueue.shift();
703
+ setTimeout(function() { __wt_showThought(next.text, next.options); }, 200);
704
+ }
705
+ }
706
+
707
+ function __wt_showQuestion(text, inputType, timeoutSeconds) {
708
+ __wt_showThought(text, { action: 'question', timeout: timeoutSeconds || 20 });
597
709
  }
598
710
 
599
711
  function __wt_removeAsk() {
600
- if (__wt_askTimer) { clearInterval(__wt_askTimer); __wt_askTimer = null; }
601
- if (__wt_askContainer) { __wt_askContainer.remove(); __wt_askContainer = null; }
602
- __wt_askBridge = null;
603
- __wt_feedbackSticky = false;
604
- clearTimeout(window.__wt_feedbackStickyTimer);
605
- __wt_thoughtQueue = [];
606
- __wt_destroyBubble();
712
+ __wt_removeThought();
607
713
  }
608
714
 
609
715
  // ── SHARED OVERLAY CONTAINER ────────────────────────────────────
@@ -960,6 +1066,33 @@ class WeaveCursor {
960
1066
 
961
1067
  const shadow = this._host.attachShadow({ mode: 'closed' });
962
1068
 
1069
+ // Liquid trail canvas inside shadow root (zero DOM reflows)
1070
+ this._trailCanvas = document.createElement('canvas');
1071
+ this._trailCanvas.setAttribute('data-wt-ignore', 'true');
1072
+ Object.assign(this._trailCanvas.style, {
1073
+ position: 'fixed',
1074
+ top: '0',
1075
+ left: '0',
1076
+ width: '100vw',
1077
+ height: '100vh',
1078
+ pointerEvents: 'none',
1079
+ zIndex: '2147483645',
1080
+ overflow: 'visible',
1081
+ });
1082
+ this._trailCanvas.width = typeof window !== 'undefined' && window.innerWidth ? window.innerWidth : 1920;
1083
+ this._trailCanvas.height = typeof window !== 'undefined' && window.innerHeight ? window.innerHeight : 1080;
1084
+ shadow.appendChild(this._trailCanvas);
1085
+ this._trailCtx = this._trailCanvas.getContext('2d');
1086
+ this._trailPoints = [];
1087
+ this._lastTrailRecord = 0;
1088
+
1089
+ window.addEventListener('resize', () => {
1090
+ if (this._trailCanvas) {
1091
+ this._trailCanvas.width = window.innerWidth;
1092
+ this._trailCanvas.height = window.innerHeight;
1093
+ }
1094
+ });
1095
+
963
1096
  // Hotspot aligned with the top-left pointer tip (3.0, 5.0 in 32x32 viewBox)
964
1097
  this._hotX = 3.0;
965
1098
  this._hotY = 5.0;
@@ -1043,6 +1176,9 @@ class WeaveCursor {
1043
1176
  if (typeof __wt_masterVisualsEnabled !== 'undefined' && !__wt_masterVisualsEnabled) {
1044
1177
  this._visible = false;
1045
1178
  this._cursor.style.opacity = '0';
1179
+ if (this._trailCtx && this._trailCanvas) {
1180
+ this._trailCtx.clearRect(0, 0, this._trailCanvas.width, this._trailCanvas.height);
1181
+ }
1046
1182
  return;
1047
1183
  }
1048
1184
  this._visible = visible;
@@ -1140,7 +1276,7 @@ class WeaveCursor {
1140
1276
  }
1141
1277
  }
1142
1278
 
1143
- this._render();
1279
+ this._render(currentTime);
1144
1280
  }
1145
1281
 
1146
1282
  this._animFrame = requestAnimationFrame(draw);
@@ -1149,15 +1285,66 @@ class WeaveCursor {
1149
1285
  this._animFrame = requestAnimationFrame(draw);
1150
1286
  }
1151
1287
 
1152
- _render() {
1288
+ _render(currentTime) {
1153
1289
  if (typeof __wt_masterVisualsEnabled !== 'undefined' && !__wt_masterVisualsEnabled) {
1154
1290
  this._cursor.style.opacity = '0';
1291
+ if (this._trailCtx && this._trailCanvas) {
1292
+ this._trailCtx.clearRect(0, 0, this._trailCanvas.width, this._trailCanvas.height);
1293
+ }
1155
1294
  return;
1156
1295
  }
1157
1296
  const x = this._lerpX;
1158
1297
  const y = this._lerpY;
1159
1298
  if (x === -9999 || y === -9999) return;
1160
- this._cursor.style.transform = `translate3d(${x - this._hotX}px, ${y - this._hotY}px, 0) scale(${this._scale})`;
1299
+
1300
+ const now = currentTime || performance.now();
1301
+
1302
+ // 1. Trail decay tracking
1303
+ const dx = this._targetX - this._lerpX;
1304
+ const dy = this._targetY - this._lerpY;
1305
+ const moveDist = Math.sqrt(dx * dx + dy * dy);
1306
+
1307
+ if (moveDist > 1.8 && now - this._lastTrailRecord > 22) {
1308
+ this._trailPoints.push({ x, y, birth: now });
1309
+ this._lastTrailRecord = now;
1310
+ if (this._trailPoints.length > 14) this._trailPoints.shift();
1311
+ }
1312
+
1313
+ // Render decaying trail
1314
+ if (this._trailCtx && this._trailCanvas) {
1315
+ this._trailCtx.clearRect(0, 0, this._trailCanvas.width, this._trailCanvas.height);
1316
+ for (let i = this._trailPoints.length - 1; i >= 0; i--) {
1317
+ const pt = this._trailPoints[i];
1318
+ const age = (now - pt.birth) / 260;
1319
+ if (age >= 1) {
1320
+ this._trailPoints.splice(i, 1);
1321
+ continue;
1322
+ }
1323
+ const alpha = (1 - age) * 0.45;
1324
+ const radius = Math.max(1, (1 - age) * 2.8);
1325
+ this._trailCtx.beginPath();
1326
+ this._trailCtx.arc(pt.x, pt.y, radius, 0, Math.PI * 2);
1327
+ this._trailCtx.fillStyle = `rgba(18, 104, 255, ${alpha})`;
1328
+ this._trailCtx.shadowColor = '#1268ff';
1329
+ this._trailCtx.shadowBlur = 4;
1330
+ this._trailCtx.fill();
1331
+ }
1332
+ }
1333
+
1334
+ // 2. Cursor scale and tactile micro-physics
1335
+ let targetScale = this._scale;
1336
+ if (this._state === 'clicking') {
1337
+ targetScale = this._scale * 0.82; // Tactile compression on click
1338
+ } else if (this._state === 'hover') {
1339
+ targetScale = this._scale * 1.08; // Interactive focus
1340
+ } else if (this._state === 'idle') {
1341
+ targetScale = this._scale + Math.sin(now * 0.003) * 0.012; // Alive breathing oscillation
1342
+ }
1343
+
1344
+ // 3. Dynamic velocity tilt (natural motion lag)
1345
+ const tilt = Math.max(-5, Math.min(5, dx * 0.06));
1346
+
1347
+ this._cursor.style.transform = `translate3d(${x - this._hotX}px, ${y - this._hotY}px, 0) rotate(${tilt}deg) scale(${targetScale})`;
1161
1348
  }
1162
1349
  }
1163
1350
 
@@ -1175,16 +1362,24 @@ function moveCursor(x, y, state) {
1175
1362
  }
1176
1363
  }
1177
1364
 
1178
-
1179
- // Click ripple (kept as page-level effect, not inside shadow DOM)
1365
+ // Enhanced twin action ripples radiating from click target
1180
1366
  function ripple(x, y) {
1181
1367
  if (typeof __wt_masterVisualsEnabled !== 'undefined' && !__wt_masterVisualsEnabled) return;
1182
- const el = document.createElement('div');
1183
- el.className = 'Weavetab-ripple';
1184
- el.setAttribute('data-wt-ignore', '');
1185
- el.style.cssText = `position:fixed;left:${x}px;top:${y}px;pointer-events:none;z-index:2147483646`;
1186
- getWeavetabRoot().appendChild(el);
1187
- el.addEventListener('animationend', () => el.remove());
1368
+ const host = document.createElement('div');
1369
+ host.className = 'Weavetab-ripple-host';
1370
+ host.setAttribute('data-wt-ignore', 'true');
1371
+ host.style.cssText = `position:fixed;left:${x}px;top:${y}px;pointer-events:none;z-index:2147483646;transform:translate(-50%, -50%);`;
1372
+
1373
+ const w1 = document.createElement('div');
1374
+ w1.style.cssText = 'position:absolute;top:50%;left:50%;width:8px;height:8px;margin:-4px 0 0 -4px;border:2px solid #1268ff;border-radius:50%;box-shadow:0 0 12px rgba(18,104,255,0.7);animation:__wt_ripple_expand 0.42s cubic-bezier(0.1, 0.8, 0.3, 1) forwards;pointer-events:none;';
1375
+
1376
+ const w2 = document.createElement('div');
1377
+ w2.style.cssText = 'position:absolute;top:50%;left:50%;width:8px;height:8px;margin:-4px 0 0 -4px;border:1.5px solid #60a5fa;border-radius:50%;animation:__wt_ripple_expand 0.52s 0.08s cubic-bezier(0.1, 0.8, 0.3, 1) forwards;pointer-events:none;';
1378
+
1379
+ host.appendChild(w1);
1380
+ host.appendChild(w2);
1381
+ (document.getElementById('Weavetab-root')?.shadowRoot || document.body || document.documentElement).appendChild(host);
1382
+ setTimeout(() => host.remove(), 620);
1188
1383
  }
1189
1384
 
1190
1385
  // ── X-RAY SPOTLIGHT OVERLAY (Phase 5.2) ────────────────────────
@@ -1703,78 +1898,21 @@ function __wt_handleWeavetabMsg(msg) {
1703
1898
  setTimeout(function(){ __wt_feedbackSticky = false; }, 2000);
1704
1899
  }
1705
1900
 
1706
- // stickyFeedback=true: fired by Weavetab_logs when agent answers a user question.
1707
- // Pin the bubble for 10s so tool chatter (moving to..., typing...) cannot override it.
1708
- if (msg.stickyFeedback === true && msg.hud && msg.hud.action) {
1709
- __wt_thoughtQueue = [];
1710
- clearTimeout(window.__wt_feedbackStickyTimer);
1711
-
1712
- if (msg.ask) {
1713
- window.__wt_feedbackStickyTimer = setTimeout(function(){
1714
- __wt_feedbackSticky = false;
1715
- __wt_removeAsk();
1716
- }, (msg.ask.timeout || 120) * 1000 + 2000);
1717
- __wt_showQuestion(msg.hud.action, msg.ask.input || 'sentence', msg.ask.timeout || 120);
1718
- } else {
1719
- __wt_feedbackSticky = true;
1720
- window.__wt_feedbackStickyTimer = setTimeout(function(){
1721
- __wt_feedbackSticky = false;
1722
- __wt_destroyBubble();
1723
- }, 10000);
1724
- __wt_renderThought(msg.hud.action, { active: false, sticky: true });
1725
- if (msg.hud) updateHUD(msg.hud.action, msg.hud.detail);
1726
- }
1727
- if (msg.cursor) {
1728
- __wt_lastCursor = { x: msg.cursor.x, y: msg.cursor.y };
1729
- if (msg.cursor.waypoints && msg.cursor.duration_ms) {
1730
- __weaveCursor.setWaypoints(msg.cursor.waypoints, msg.cursor.duration_ms);
1731
- }
1732
- moveCursor(msg.cursor.x, msg.cursor.y, msg.state);
1733
- }
1734
- else if (msg.state) { moveCursor(__wt_lastCursor.x, __wt_lastCursor.y, msg.state); }
1735
- return;
1736
- }
1737
-
1738
1901
  if (msg.hud) {
1739
1902
  updateHUD(msg.hud.action, msg.hud.detail);
1740
1903
  var a = (msg.hud.action || '').trim();
1741
1904
  if (a === 'reading the page...') {
1742
- __wt_showReadingGlow();
1743
- __wt_showThought('Reading the page...', { active: true });
1744
1905
  __weaveCursor.setState('reading');
1745
1906
  } else if (a === 'Mission Running') {
1746
- // Tool call is starting — switch to eval animation and show tool bubble
1747
1907
  __wt_toolActive = true;
1748
1908
  __weaveCursor.setState('eval');
1749
- __wt_showThought('Executing tool...', { active: true });
1750
1909
  } else if (a.startsWith('[OK]')) {
1751
- // Tool completed successfully — revert to idle and instantly hide bubble
1752
1910
  __weaveCursor.setState('idle');
1753
1911
  __wt_toolActive = false;
1754
- if (!__wt_feedbackSticky) {
1755
- __wt_destroyBubble(); // Instant removal
1756
- __wt_processThoughtQueue();
1757
- }
1758
1912
  } else if (a.startsWith('[ERR]')) {
1759
- // Tool errored — show stuck cursor briefly
1760
1913
  __weaveCursor.setState('stuck');
1761
1914
  __wt_toolActive = false;
1762
1915
  setTimeout(function(){ __weaveCursor.setState('idle'); }, 3000);
1763
- if (!__wt_feedbackSticky) {
1764
- __wt_destroyBubble(); // Instant removal
1765
- __wt_processThoughtQueue();
1766
- }
1767
- } else if (a && a.length > 3) {
1768
- __wt_hideReadingGlow();
1769
- if (!__wt_feedbackSticky) {
1770
- __wt_showThought(a, { active: true });
1771
- }
1772
- } else {
1773
- if (!__wt_feedbackSticky) {
1774
- __wt_hideReadingGlow();
1775
- __wt_destroyBubble(); // Instant removal
1776
- __wt_processThoughtQueue();
1777
- }
1778
1916
  }
1779
1917
  }
1780
1918
  if (msg.cursor || msg.hud) {
@@ -1782,6 +1920,14 @@ function __wt_handleWeavetabMsg(msg) {
1782
1920
  }
1783
1921
  }
1784
1922
 
1923
+ // Pure thought event from browser_thoughts tool only
1924
+ if (msg.type === 'WT_THOUGHT' || msg.type === 'Weavetab_THOUGHT') {
1925
+ __wt_showThought(msg.text, msg);
1926
+ }
1927
+ if (msg.type === 'WT_CLEAR_THOUGHT' || msg.type === 'Weavetab_CLEAR_THOUGHT') {
1928
+ __wt_removeThought();
1929
+ }
1930
+
1785
1931
  // Handle plan updates via sendToExtension channel
1786
1932
  if (msg.type === 'Weavetab_STATE' && msg.plan) {
1787
1933
  const p = msg.plan;
@@ -2050,741 +2196,8 @@ function setFaviconHref(dataUrl) {
2050
2196
 
2051
2197
 
2052
2198
 
2053
- // ── PERSISTENT MESSAGING PANEL (WeaveTab OS v2.5.0) ───────────────
2054
- // Design inspired by designs/elements.html
2055
- (function initWeaveTabUI() {
2056
- if (window.self !== window.top) return;
2057
- if (document.getElementById('wt-main-container')) return;
2058
-
2059
- const version = "2.5.0";
2060
- const isBeta = true;
2061
-
2062
- // ── CSS Injection ─────────────────────────────────────────────
2063
- const style = document.createElement('style');
2064
- style.id = 'wt-ui-styles';
2065
- style.textContent = `
2066
- /* ── Sidepanel Tokens ────────────────────────────────────── */
2067
- :host, .wt-sp-root { all: initial; }
2068
- .wt-sp-root, .wt-sp-root * { box-sizing: border-box; margin: 0; padding: 0; }
2069
-
2070
- .wt-sp-root {
2071
- --sp-bg: #ffffff;
2072
- --sp-bg-panel: #f9f9fb;
2073
- --sp-bg-item: #f4f4f5;
2074
- --sp-bg-hover: #e8e8ec;
2075
- --sp-border: #e4e4e7;
2076
- --sp-border-hi: #d4d4d8;
2077
- --sp-text: #18181b;
2078
- --sp-text-secondary: #52525b;
2079
- --sp-text-muted: #a1a1aa;
2080
- --sp-blue: #3b82f6;
2081
- --sp-blue-light: #60a5fa;
2082
- --sp-green: #16a34a;
2083
- --sp-green-bg: #f0fdf4;
2084
- --sp-red: #ef4444;
2085
- --sp-red-bg: #fef2f2;
2086
- --sp-yellow: #f59e0b;
2087
- --sp-shadow: 0 1px 3px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06);
2088
- --sp-font: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
2089
- --sp-font-mono: 'SF Mono', 'Cascadia Code', 'Consolas', monospace;
2090
- }
2091
-
2092
- .wt-sp-root[data-theme='dark'] {
2093
- --sp-bg: #09090b;
2094
- --sp-bg-panel: #111113;
2095
- --sp-bg-item: #1c1c1f;
2096
- --sp-bg-hover: #27272a;
2097
- --sp-border: #27272a;
2098
- --sp-border-hi: #3f3f46;
2099
- --sp-text: #fafafa;
2100
- --sp-text-secondary: #a1a1aa;
2101
- --sp-text-muted: #52525b;
2102
- --sp-green-bg: #052e16;
2103
- --sp-red-bg: #450a0a;
2104
- --sp-shadow: 0 1px 3px rgba(0,0,0,0.4), 0 4px 12px rgba(0,0,0,0.3);
2105
- }
2106
-
2107
- /* ── Panel Shell ─────────────────────────────────────────── */
2108
- .wt-sp-root {
2109
- position: fixed;
2110
- top: 0; bottom: 0; right: 0;
2111
- width: 360px;
2112
- display: none !important;
2113
- flex-direction: column;
2114
- background: var(--sp-bg);
2115
- border-left: 1px solid var(--sp-border);
2116
- z-index: 2147483646;
2117
- pointer-events: auto;
2118
- font-family: var(--sp-font);
2119
- color: var(--sp-text);
2120
-
2121
- transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
2122
- overflow: hidden;
2123
- }
2124
-
2125
- .wt-sp-root.minimized {
2126
- transform: translateX(100%);
2127
- pointer-events: none;
2128
- }
2129
-
2130
- /* ── Header ──────────────────────────────────────────────── */
2131
- .wt-sp-header {
2132
- display: flex;
2133
- justify-content: space-between;
2134
- align-items: center;
2135
- padding: 10px 14px;
2136
- border-bottom: 1px solid var(--sp-border);
2137
- flex-shrink: 0;
2138
- -webkit-app-region: drag;
2139
- }
2140
-
2141
- .wt-sp-brand {
2142
- font-size: 13px;
2143
- font-weight: 600;
2144
- color: var(--sp-text);
2145
- letter-spacing: -0.01em;
2146
- }
2147
-
2148
- .wt-sp-controls {
2149
- display: flex;
2150
- align-items: center;
2151
- gap: 2px;
2152
- -webkit-app-region: no-drag;
2153
- }
2154
-
2155
- .wt-sp-ctrl-btn {
2156
- width: 28px; height: 28px;
2157
- display: flex; align-items: center; justify-content: center;
2158
- background: transparent;
2159
- border: none;
2160
- border-radius: 6px;
2161
- color: var(--sp-text-muted);
2162
- cursor: pointer;
2163
- transition: background 0.15s, color 0.15s;
2164
- font-size: 14px;
2165
- }
2166
- .wt-sp-ctrl-btn:hover { background: var(--sp-bg-hover); color: var(--sp-text); }
2167
-
2168
- /* ── Badge Row ───────────────────────────────────────────── */
2169
- .wt-sp-badges {
2170
- display: flex;
2171
- align-items: center;
2172
- gap: 6px;
2173
- padding: 6px 14px;
2174
- border-bottom: 1px solid var(--sp-border);
2175
- flex-shrink: 0;
2176
- }
2177
-
2178
- .wt-sp-badge {
2179
- font-size: 9px;
2180
- font-weight: 600;
2181
- padding: 2px 6px;
2182
- border-radius: 4px;
2183
- text-transform: uppercase;
2184
- letter-spacing: 0.03em;
2185
- }
2186
- .wt-sp-badge-dev { background: var(--sp-blue); color: #fff; }
2187
- .wt-sp-badge-beta { background: var(--sp-yellow); color: #fff; }
2188
-
2189
- /* ── Body (scrollable) ───────────────────────────────────── */
2190
- .wt-sp-body {
2191
- flex: 1;
2192
- overflow-y: auto;
2193
- display: flex;
2194
- flex-direction: column;
2195
- }
2196
-
2197
- .wt-sp-body::-webkit-scrollbar { width: 5px; }
2198
- .wt-sp-body::-webkit-scrollbar-track { background: transparent; }
2199
- .wt-sp-body::-webkit-scrollbar-thumb { background: var(--sp-border-hi); border-radius: 3px; }
2200
-
2201
- /* ── Section ─────────────────────────────────────────────── */
2202
- .wt-sp-section {
2203
- border-bottom: 1px solid var(--sp-border);
2204
- }
2205
-
2206
- .wt-sp-section-hdr {
2207
- display: flex;
2208
- align-items: center;
2209
- gap: 6px;
2210
- padding: 8px 14px;
2211
- font-size: 11px;
2212
- font-weight: 600;
2213
- color: var(--sp-text-secondary);
2214
- text-transform: uppercase;
2215
- letter-spacing: 0.04em;
2216
- cursor: pointer;
2217
- user-select: none;
2218
- transition: color 0.15s;
2219
- }
2220
- .wt-sp-section-hdr:hover { color: var(--sp-text); }
2221
-
2222
- .wt-sp-chevron {
2223
- font-size: 10px;
2224
- transition: transform 0.2s ease;
2225
- display: inline-block;
2226
- color: var(--sp-text-muted);
2227
- }
2228
- .wt-sp-section.closed .wt-sp-chevron { transform: rotate(-90deg); }
2229
-
2230
- .wt-sp-section-body {
2231
- overflow: hidden;
2232
- transition: max-height 0.25s cubic-bezier(0.32, 0.72, 0, 1);
2233
- max-height: 500px;
2234
- }
2235
- .wt-sp-section.closed .wt-sp-section-body { max-height: 0; }
2236
-
2237
- .wt-sp-section-grow { flex: 1; display: flex; flex-direction: column; }
2238
- .wt-sp-section-grow .wt-sp-section-body { flex: 1; overflow-y: auto; max-height: none; }
2239
-
2240
- /* ── Tasks ────────────────────────────────────────────────── */
2241
- .wt-sp-tasks {
2242
- display: flex;
2243
- flex-direction: column;
2244
- padding: 0 14px 10px;
2245
- gap: 2px;
2246
- }
2247
-
2248
- .wt-sp-task {
2249
- display: flex;
2250
- align-items: flex-start;
2251
- gap: 8px;
2252
- padding: 6px 8px;
2253
- border-radius: 6px;
2254
- font-size: 12px;
2255
- line-height: 1.4;
2256
- cursor: pointer;
2257
- transition: background 0.15s;
2258
- }
2259
- .wt-sp-task:hover { background: var(--sp-bg-hover); }
2260
-
2261
- .wt-sp-task.done { color: var(--sp-green); }
2262
- .wt-sp-task.active { color: var(--sp-text); background: var(--sp-bg-item); border-left: 2px solid var(--sp-blue); padding-left: 6px; }
2263
- .wt-sp-task.pending { color: var(--sp-text-muted); }
2264
-
2265
- .wt-sp-task-icon { flex-shrink: 0; width: 16px; text-align: center; font-size: 11px; margin-top: 1px; }
2266
- .wt-sp-task.done .wt-sp-task-icon { color: var(--sp-green); }
2267
- .wt-sp-task.active .wt-sp-task-icon { color: var(--sp-blue); }
2268
-
2269
- .wt-sp-task-desc { flex: 1; word-break: break-word; }
2270
- .wt-sp-task.done .wt-sp-task-desc { text-decoration: line-through; opacity: 0.7; }
2271
-
2272
- .wt-sp-task-empty {
2273
- font-size: 11px;
2274
- color: var(--sp-text-muted);
2275
- padding: 8px;
2276
- text-align: center;
2277
- }
2278
-
2279
- /* ── Activity Log ────────────────────────────────────────── */
2280
- .wt-sp-log {
2281
- display: flex;
2282
- flex-direction: column;
2283
- gap: 1px;
2284
- padding: 0 14px 10px;
2285
- font-family: var(--sp-font-mono);
2286
- }
2287
-
2288
- .wt-sp-log-entry {
2289
- display: flex;
2290
- align-items: flex-start;
2291
- gap: 8px;
2292
- padding: 5px 8px;
2293
- border-radius: 4px;
2294
- font-size: 11px;
2295
- line-height: 1.4;
2296
- transition: background 0.1s;
2297
- }
2298
- .wt-sp-log-entry:hover { background: var(--sp-bg-hover); }
2299
-
2300
- .wt-sp-log-icon { flex-shrink: 0; width: 14px; text-align: center; margin-top: 1px; font-size: 10px; }
2301
- .wt-sp-log-icon.running { color: var(--sp-blue); }
2302
- .wt-sp-log-icon.done { color: var(--sp-green); }
2303
- .wt-sp-log-icon.error { color: var(--sp-red); }
2304
-
2305
- .wt-sp-log-name {
2306
- font-weight: 500;
2307
- color: var(--sp-text);
2308
- white-space: nowrap;
2309
- overflow: hidden;
2310
- text-overflow: ellipsis;
2311
- max-width: 140px;
2312
- }
2313
-
2314
- .wt-sp-log-badge {
2315
- font-size: 9px;
2316
- font-weight: 600;
2317
- padding: 1px 5px;
2318
- border-radius: 3px;
2319
- text-transform: uppercase;
2320
- letter-spacing: 0.02em;
2321
- flex-shrink: 0;
2322
- }
2323
- .wt-sp-log-badge.running { background: rgba(59,130,246,0.12); color: var(--sp-blue); }
2324
- .wt-sp-log-badge.done { background: rgba(22,163,74,0.12); color: var(--sp-green); }
2325
- .wt-sp-log-badge.error { background: rgba(239,68,68,0.12); color: var(--sp-red); }
2326
- .wt-sp-log-badge.info { background: var(--sp-bg-item); color: var(--sp-text-muted); }
2327
-
2328
- .wt-sp-log-time {
2329
- font-size: 10px;
2330
- color: var(--sp-text-muted);
2331
- margin-left: auto;
2332
- flex-shrink: 0;
2333
- }
2334
-
2335
- .wt-sp-log-empty {
2336
- font-size: 11px;
2337
- color: var(--sp-text-muted);
2338
- padding: 8px;
2339
- text-align: center;
2340
- font-family: var(--sp-font);
2341
- }
2342
-
2343
- /* ── Chat ─────────────────────────────────────────────────── */
2344
- .wt-sp-chat {
2345
- padding: 10px 14px;
2346
- border-top: 1px solid var(--sp-border);
2347
- flex-shrink: 0;
2348
- }
2349
-
2350
- .wt-sp-chat-row {
2351
- display: flex;
2352
- gap: 6px;
2353
- align-items: flex-end;
2354
- }
2355
-
2356
- .wt-sp-chat-input {
2357
- flex: 1;
2358
- padding: 8px 12px;
2359
- background: var(--sp-bg-item);
2360
- border: 1px solid var(--sp-border);
2361
- border-radius: 8px;
2362
- color: var(--sp-text);
2363
- font-family: var(--sp-font);
2364
- font-size: 12px;
2365
- outline: none;
2366
- resize: none;
2367
- min-height: 36px;
2368
- max-height: 100px;
2369
- transition: border-color 0.15s;
2370
- line-height: 1.4;
2371
- }
2372
- .wt-sp-chat-input::placeholder { color: var(--sp-text-muted); }
2373
- .wt-sp-chat-input:focus { border-color: var(--sp-blue); }
2374
-
2375
- .wt-sp-send-btn {
2376
- width: 36px; height: 36px;
2377
- display: flex; align-items: center; justify-content: center;
2378
- background: var(--sp-blue);
2379
- border: none;
2380
- border-radius: 8px;
2381
- cursor: pointer;
2382
- flex-shrink: 0;
2383
- transition: background 0.15s, transform 0.1s;
2384
- }
2385
- .wt-sp-send-btn:hover { background: #2563eb; }
2386
- .wt-sp-send-btn:active { transform: scale(0.95); }
2387
- .wt-sp-send-btn.sent { background: var(--sp-green); }
2388
- .wt-sp-send-btn svg { width: 16px; height: 16px; stroke: #fff; fill: none; }
2389
-
2390
- /* ── Debug Section ───────────────────────────────────────── */
2391
- .wt-sp-debug-area {
2392
- padding: 0 14px 10px;
2393
- position: relative;
2394
- min-height: 200px;
2395
- }
2396
-
2397
- .wt-sp-f3-btn {
2398
- margin-left: auto;
2399
- font-size: 9px;
2400
- font-weight: 600;
2401
- padding: 2px 6px;
2402
- border-radius: 4px;
2403
- background: var(--sp-bg-item);
2404
- border: 1px solid var(--sp-border);
2405
- color: var(--sp-text-muted);
2406
- cursor: pointer;
2407
- text-transform: uppercase;
2408
- transition: all 0.15s;
2409
- }
2410
- .wt-sp-f3-btn:hover { color: var(--sp-text); border-color: var(--sp-border-hi); }
2411
-
2412
- /* ── System Icon (minimized state) ───────────────────────── */
2413
- #wt-system-icon {
2414
- position: fixed;
2415
- bottom: 20px;
2416
- right: 20px;
2417
- width: 40px;
2418
- height: 40px;
2419
- background: var(--sp-bg);
2420
- border: 1px solid var(--sp-border);
2421
- border-radius: 10px;
2422
- display: none;
2423
- justify-content: center;
2424
- align-items: center;
2425
- cursor: pointer;
2426
- z-index: 2147483640;
2427
- box-shadow: var(--sp-shadow);
2428
- transition: background 0.15s, transform 0.15s;
2429
- pointer-events: auto;
2430
- }
2431
- #wt-system-icon:hover { background: var(--sp-bg-hover); transform: scale(1.05); }
2432
- #wt-system-icon svg { width: 18px; height: 18px; fill: var(--sp-text-muted); }
2433
-
2434
- /* ── Utilities ────────────────────────────────────────────── */
2435
- .wt-sp-root .hidden, .wt-sp-root.hidden, .wt-hidden { display: none !important; }
2436
-
2437
- @keyframes wt-sp-spin {
2438
- from { transform: rotate(0deg); }
2439
- to { transform: rotate(360deg); }
2440
- }
2441
- .wt-sp-spinner {
2442
- display: inline-block;
2443
- width: 10px; height: 10px;
2444
- border: 1.5px solid var(--sp-border-hi);
2445
- border-top-color: var(--sp-blue);
2446
- border-radius: 50%;
2447
- animation: wt-sp-spin 0.8s linear infinite;
2448
- }
2449
- `;
2450
- (document.head || document.documentElement).appendChild(style);
2451
-
2452
- // ── HTML Construction ─────────────────────────────────────────
2453
- const container = document.createElement('div');
2454
- container.id = 'wt-main-container';
2455
- container.className = 'wt-sp-root';
2456
- container.setAttribute('data-wt-ignore', 'true');
2457
- container.setAttribute('data-theme', 'dark');
2458
-
2459
- container.innerHTML = `
2460
- <div class="wt-sp-header">
2461
- <span class="wt-sp-brand">Weavetab</span>
2462
- <div class="wt-sp-controls">
2463
- <button class="wt-sp-ctrl-btn" id="wt-theme-toggle" title="Toggle theme">
2464
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
2465
- </button>
2466
- <button class="wt-sp-ctrl-btn" id="wt-minimize-btn" title="Minimize">
2467
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14"/></svg>
2468
- </button>
2469
- </div>
2470
- </div>
2471
- <div class="wt-sp-badges">
2472
- <span class="wt-sp-badge wt-sp-badge-dev hidden" id="wt-badge-dev">DEV</span>
2473
- ${isBeta ? '<span class="wt-sp-badge wt-sp-badge-beta">BETA</span>' : ''}
2474
- </div>
2475
- <div class="wt-sp-body">
2476
- <div class="wt-sp-section" id="wt-sec-tasks">
2477
- <div class="wt-sp-section-hdr" id="wt-header-tasks">
2478
- <span class="wt-sp-chevron">›</span>
2479
- <span>Tasks</span>
2480
- </div>
2481
- <div class="wt-sp-section-body">
2482
- <div class="wt-sp-tasks" id="wt-todo-list">
2483
- <div class="wt-sp-task-empty">No active mission</div>
2484
- </div>
2485
- </div>
2486
- </div>
2487
-
2488
- <div class="wt-sp-section wt-sp-section-grow" id="wt-sec-logs">
2489
- <div class="wt-sp-section-hdr" id="wt-header-logs">
2490
- <span class="wt-sp-chevron">›</span>
2491
- <span>Activity</span>
2492
- </div>
2493
- <div class="wt-sp-section-body">
2494
- <div class="wt-sp-log" id="wt-log-container">
2495
- <div class="wt-sp-log-empty">Waiting for activity...</div>
2496
- </div>
2497
- </div>
2498
- </div>
2499
-
2500
- <div class="wt-sp-section closed" id="wt-sec-debug">
2501
- <div class="wt-sp-section-hdr" id="wt-header-debug">
2502
- <span class="wt-sp-chevron">›</span>
2503
- <span>Debug</span>
2504
- </div>
2505
- <div class="wt-sp-section-body">
2506
- <div class="wt-sp-debug-area" id="wt-debug-content-area"></div>
2507
- </div>
2508
- </div>
2509
- </div>
2510
-
2511
- <div class="wt-sp-chat">
2512
- <div class="wt-sp-chat-row">
2513
- <textarea class="wt-sp-chat-input" id="wt-msg-input" placeholder="Send feedback..." rows="1"></textarea>
2514
- <button class="wt-sp-send-btn" id="wt-send-btn">
2515
- <svg viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
2516
- </button>
2517
- </div>
2518
- </div>
2519
- `;
2520
- __wt_safeAppendToBody(container);
2521
-
2522
- const systemIcon = document.createElement('div');
2523
- systemIcon.id = 'wt-system-icon';
2524
- systemIcon.title = 'Open Weavetab';
2525
- systemIcon.innerHTML = `
2526
- <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
2527
- <path d="M4 4h16v16H4V4zm2 2v12h12V6H6zm2 3h3v2H8V9zm4 4h4v2h-4v-2z" />
2528
- </svg>
2529
- `;
2530
- __wt_safeAppendToBody(systemIcon);
2531
-
2532
- // ── PERSISTENT ACTIVITY LOG ──────────────────────────────────
2533
- // Logs never clear until browser close — append-only like Claude Chrome
2534
- window.__wt_logEntries = [];
2535
- const logContainer = document.getElementById('wt-log-container');
2536
-
2537
- function __wt_addLogEntry(name, status, detail) {
2538
- const entry = {
2539
- name: name || 'unknown',
2540
- status: status || 'info',
2541
- detail: detail || '',
2542
- time: Date.now()
2543
- };
2544
- window.__wt_logEntries.push(entry);
2545
- __wt_renderLogEntry(entry);
2546
- // Auto-scroll to bottom
2547
- if (logContainer) {
2548
- logContainer.scrollTop = logContainer.scrollHeight;
2549
- }
2550
- }
2551
-
2552
- function __wt_renderLogEntry(entry) {
2553
- if (!logContainer) return;
2554
- // Remove empty placeholder on first real entry
2555
- const empty = logContainer.querySelector('.wt-sp-log-empty');
2556
- if (empty) empty.remove();
2557
-
2558
- const el = document.createElement('div');
2559
- el.className = 'wt-sp-log-entry';
2560
-
2561
- const iconClass = entry.status === 'done' ? 'done' : entry.status === 'error' ? 'error' : entry.status === 'running' ? 'running' : '';
2562
- const icon = entry.status === 'running' ? '<span class="wt-sp-spinner"></span>'
2563
- : entry.status === 'done' ? '&#10003;'
2564
- : entry.status === 'error' ? '&#10007;'
2565
- : '&#9679;';
2566
-
2567
- const badge = entry.status === 'running' ? 'RUNNING'
2568
- : entry.status === 'done' ? 'OK'
2569
- : entry.status === 'error' ? 'ERR'
2570
- : '';
2571
-
2572
- const timeStr = new Date(entry.time).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
2573
-
2574
- el.innerHTML = `
2575
- <span class="wt-sp-log-icon ${iconClass}">${icon}</span>
2576
- <span class="wt-sp-log-name">${__wt_escapeHtml(entry.name)}</span>
2577
- ${badge ? `<span class="wt-sp-log-badge ${entry.status}">${badge}</span>` : ''}
2578
- <span class="wt-sp-log-time">${timeStr}</span>
2579
- `;
2580
-
2581
- if (entry.detail) {
2582
- const detailEl = document.createElement('div');
2583
- detailEl.style.cssText = 'width:100%;font-size:10px;color:var(--sp-text-muted);white-space:pre-wrap;word-break:break-all;margin-top:2px;';
2584
- detailEl.textContent = entry.detail;
2585
- el.appendChild(detailEl);
2586
- }
2587
-
2588
- logContainer.appendChild(el);
2589
- }
2590
-
2591
- function __wt_escapeHtml(str) {
2592
- return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
2593
- }
2594
-
2595
- // ── THEME SYSTEM ──────────────────────────────────────────────
2596
- function __wt_applyTheme(theme) {
2597
- container.setAttribute('data-theme', theme);
2598
- document.getElementById('wt-system-icon') && document.getElementById('wt-system-icon').setAttribute('data-theme', theme);
2599
- try { browserAPI.storage.local.set({ wt_theme: theme }); } catch(e) {}
2600
- }
2601
-
2602
- function __wt_toggleTheme() {
2603
- const current = container.getAttribute('data-theme');
2604
- __wt_applyTheme(current === 'dark' ? 'light' : 'dark');
2605
- }
2606
-
2607
- // Restore persisted theme
2608
- try {
2609
- browserAPI.storage.local.get(['wt_theme'], function(res) {
2610
- if (res.wt_theme) {
2611
- __wt_applyTheme(res.wt_theme);
2612
- }
2613
- });
2614
- } catch(e) {}
2615
-
2616
-
2617
-
2618
- // ── HUD STATUS INTERCEPTION (for activity log) ────────────────
2619
- // Capture Weavetab_STATE hud updates and add to log
2620
- window.addEventListener('message', function(e) {
2621
- if (e.data && e.data.type === 'Weavetab-msg-in' && e.data.data && e.data.data.type === 'Weavetab_STATE' && e.data.data.hud) {
2622
- const hud = e.data.data.hud;
2623
- if (hud.action && hud.action.length > 2) {
2624
- __wt_addLogEntry(hud.action, 'info', hud.detail || '');
2625
- }
2626
- }
2627
- });
2628
-
2629
-
2630
-
2631
- // ── Panel State Persistence ────────────────────────────────────
2632
- // Sidepanel always opens on browser launch (background clears state on startup).
2633
- // Persists minimized state across page navigations within a session.
2634
- function minimizePanel() {
2635
- container.classList.add('minimized');
2636
- systemIcon.style.display = 'flex';
2637
- try { browserAPI.storage.local.set({ wt_panel_minimized: true }); } catch(e) {}
2638
- }
2639
-
2640
- function restorePanel() {
2641
- systemIcon.style.display = 'none';
2642
- container.classList.remove('minimized');
2643
- try { browserAPI.storage.local.set({ wt_panel_minimized: false }); } catch(e) {}
2644
- }
2645
-
2646
- // Restore minimized state from storage (respects user's last action)
2647
- try {
2648
- browserAPI.storage.local.get(['wt_panel_minimized'], function(res) {
2649
- if (res.wt_panel_minimized) {
2650
- container.classList.add('minimized');
2651
- systemIcon.style.display = 'flex';
2652
- }
2653
- });
2654
- } catch(e) {}
2655
-
2656
- function toggleSection(id) {
2657
- document.getElementById(id).classList.toggle('closed');
2658
- }
2659
-
2660
-
2661
-
2662
- function syncDevMode() {
2663
- const active = !!window.__wt_devMode;
2664
- const devBadge = document.getElementById('wt-badge-dev');
2665
-
2666
- if (devBadge) devBadge.classList.toggle('hidden', !active);
2667
- }
2668
-
2669
- window.addEventListener('wt-config-sync', syncDevMode);
2670
-
2671
- container.querySelector('#wt-minimize-btn').onclick = minimizePanel;
2672
- systemIcon.onclick = restorePanel;
2673
- container.querySelector('#wt-theme-toggle').onclick = __wt_toggleTheme;
2674
- container.querySelector('#wt-header-tasks').onclick = () => toggleSection('wt-sec-tasks');
2675
- container.querySelector('#wt-header-logs').onclick = () => toggleSection('wt-sec-logs');
2676
- container.querySelector('#wt-header-debug').onclick = () => toggleSection('wt-sec-debug');
2677
-
2678
-
2679
- syncDevMode();
2680
-
2681
- const msgInput = container.querySelector('#wt-msg-input');
2682
- const sendBtn = container.querySelector('#wt-send-btn');
2683
-
2684
- // Auto-resize textarea
2685
- msgInput.addEventListener('input', function() {
2686
- this.style.height = 'auto';
2687
- this.style.height = Math.min(this.scrollHeight, 100) + 'px';
2688
- });
2689
-
2690
- // ── Plan Rendering Integration ───────────────────────────────
2691
- function renderPlan(action, goal, tasks) {
2692
- const list = document.getElementById('wt-todo-list');
2693
- if (!list) return;
2694
-
2695
- if (action === 'hide' || (!goal && (!tasks || tasks.length === 0))) {
2696
- list.innerHTML = '<div class="wt-sp-task-empty">No active mission</div>';
2697
- return;
2698
- }
2699
-
2700
- list.innerHTML = '';
2701
- if (goal) {
2702
- const goalEl = document.createElement('div');
2703
- goalEl.className = 'wt-sp-task active';
2704
- goalEl.style.cssText = 'margin-bottom:4px;font-weight:500;';
2705
- goalEl.innerHTML = '<span class="wt-sp-task-icon">&#9654;</span><span class="wt-sp-task-desc">' + __wt_escapeHtml(goal) + '</span>';
2706
- list.appendChild(goalEl);
2707
- }
2708
- if (tasks && tasks.length > 0) {
2709
- tasks.forEach(task => {
2710
- const item = document.createElement('div');
2711
- const statusClass = task.status === 'done' ? 'done' : (task.status === 'in-progress' ? 'active' : 'pending');
2712
- const icon = task.status === 'done' ? '&#10003;' : (task.status === 'in-progress' ? '<span class="wt-sp-spinner"></span>' : '&#9675;');
2713
-
2714
- item.className = 'wt-sp-task ' + statusClass;
2715
- item.setAttribute('data-task-id', task.id);
2716
- item.innerHTML = '<span class="wt-sp-task-icon">' + icon + '</span><span class="wt-sp-task-desc">' + __wt_escapeHtml(task.description) + '</span>';
2717
-
2718
- list.appendChild(item);
2719
- });
2720
- }
2721
-
2722
- // Log the plan update
2723
- __wt_addLogEntry('Plan updated', 'info', (tasks ? tasks.length : 0) + ' tasks');
2724
- }
2725
-
2726
- window.__wt_plan = renderPlan;
2727
-
2728
- window.addEventListener('message', (e) => {
2729
- if (e.data && e.data.type === '__WT_PLAN') {
2730
- renderPlan(e.data.action, e.data.goal, e.data.tasks);
2731
- }
2732
- syncDevMode();
2733
- });
2734
-
2735
- setInterval(syncDevMode, 2000);
2736
-
2737
- try {
2738
- browserAPI.storage.local.get(['wt_plan_collapsed'], function(res) {});
2739
- } catch(e) {}
2740
-
2741
- // Persist draft
2742
- msgInput.addEventListener('input', function() {
2743
- try { browserAPI.storage.local.set({ wt_chat_draft: msgInput.value }); } catch(e) {}
2744
- });
2745
-
2746
- // Submit
2747
- function submitFeedback() {
2748
- var text = msgInput.value.trim();
2749
- if (!text) return;
2750
-
2751
- window.postMessage({
2752
- type: '__WT_FEEDBACK',
2753
- text: text
2754
- }, '*');
2755
-
2756
- window.dispatchEvent(new CustomEvent('Weavetab-msg-in', {
2757
- detail: {
2758
- type: 'USER_FEEDBACK',
2759
- text: text
2760
- }
2761
- }));
2762
-
2763
- try {
2764
- var existing = JSON.parse(localStorage.getItem('__wt_chat_queue_persist') || '[]');
2765
- existing.push({ text: text, ts: Date.now() });
2766
- if (existing.length > 20) existing.splice(0, existing.length - 20);
2767
- localStorage.setItem('__wt_chat_queue_persist', JSON.stringify(existing));
2768
- } catch(e) {}
2769
-
2770
- __wt_addLogEntry('Feedback sent', 'done', text.length > 60 ? text.substring(0, 60) + '...' : text);
2771
-
2772
- msgInput.value = '';
2773
- msgInput.style.height = 'auto';
2774
- try { browserAPI.storage.local.remove('wt_chat_draft'); } catch(e) {}
2775
- sendBtn.classList.add('sent');
2776
- setTimeout(function(){ sendBtn.classList.remove('sent'); }, 1200);
2777
- }
2778
-
2779
- sendBtn.onclick = submitFeedback;
2780
- msgInput.addEventListener('keydown', function(e) {
2781
- if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); submitFeedback(); }
2782
- if (e.key === 'Escape') { minimizePanel(); }
2783
- });
2784
-
2785
- })();
2199
+ // ── SIDE PANEL REMOVED (Replaced by pure middle-down Thought HUD) ──
2786
2200
 
2787
- // ── GEMINI-STYLE AREA SNIPE & DIRECT ANNOTATION ENGINE ─────────────────────
2788
2201
  (function initAreaSnipeEngine() {
2789
2202
  let isSnipeActive = false;
2790
2203
  let currentSnipeMode = 'dom_target';
@@ -3051,7 +2464,7 @@ function setFaviconHref(dataUrl) {
3051
2464
  }
3052
2465
  }
3053
2466
 
3054
- // Listen for start snipe message from sidepanel/background
2467
+ // Listen for snipe trigger from background
3055
2468
  browserAPI.runtime.onMessage.addListener((msg) => {
3056
2469
  if (msg.type === 'WT_START_SNIPE') {
3057
2470
  createOverlay(msg.mode || 'dom_target');