eubottura commited on
Commit
6f56d5c
Β·
verified Β·
1 Parent(s): 30e5655

Role: You are a specialized AI assistant for web automation and user interface enhancement on the Hugging Face platform. Your primary function is to inject, manage, and optimize interactive tools that streamline AI-assisted coding workflows.

Browse files

Goal: Automatically detect the current Hugging Face AI environment (Qwen, Zai, or generic HF Chat), inject a fully functional control panel, enable clipboard-based data transfer between AI instances, enhance the user interface with floating action buttons, and provide keyboard shortcuts for rapid interaction.

Constraints:

Operate exclusively on domains containing "huggingface.co".
Do not modify or access any data outside the scope of the Hugging Face chat interface.
Ensure all injected elements use non-blocking, asynchronous execution.
Maintain compatibility with dynamic DOM updates via MutationObserver.
Use only client-side APIs (e.g., localStorage, Clipboard API) without external dependencies.
Steps:

Upon page load, verify the domain is Hugging Face.
Detect the active AI type (Qwen, Zai, or HF) from the URL.
Inject a fixed-position control panel with the following action buttons:
"✨ Enhance Interface": Apply smooth scroll, padding, and inject floating buttons for scroll-to-bottom and input focus.
"πŸ“‹ Smart Paste": Read clipboard text and auto-fill the first available input field (textarea, input, or contenteditable).
"πŸ“₯ Extract Response": Scrape the latest AI message using multiple selectors, extract clean text, and copy it to clipboard.
"➑️ Send to ZAI" (Qwen only): Extract latest response and store in localStorage, then open Zai AI page in new tab.
"πŸ–₯️ Full Screen Mode": Expand chat container to full viewport with optimized layout.
"πŸ”„ Reset Page": Confirm and reload the page, clearing any stored data.
Implement Ctrl+Shift+V to trigger Smart Paste and Ctrl+Shift+C to trigger Extract Response.
On Zai pages, check localStorage every second for incoming data from Qwen; if found, auto-paste into input field and clear storage.
Allow panel minimization via minimize button and full removal via close button.
Display status messages (success/error) for user feedback, auto-hiding after4 seconds.
Ensure all styles are applied with !important to override existing CSS.
Expose bookmarkletManager and initHFBookmarklet() globally for manual execution.
Success Criteria:

Panel is injected within1 second of page load.
All buttons perform their intended actions without error.
Clipboard operations succeed when permitted.
No console errors or memory leaks occur.
UI remains responsive during all operations.
Final Output: Execute the above steps using the BookmarkletManager class and auto-initialize when the page is ready.

Files changed (3) hide show
  1. components/hf-panel.js +428 -0
  2. index.html +53 -2
  3. script.js +53 -2
components/hf-panel.js ADDED
@@ -0,0 +1,428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class HuggingFacePanel extends HTMLElement {
2
+ connectedCallback() {
3
+ this.attachShadow({ mode: 'open' });
4
+ this.shadowRoot.innerHTML = `
5
+ <style>
6
+ .hf-panel {
7
+ position: fixed !important;
8
+ top: 20px !important;
9
+ right: 20px !important;
10
+ z-index: 999999 !important;
11
+ background: rgba(0, 0, 0, 0.85) !important;
12
+ backdrop-filter: blur(10px) !important;
13
+ border-radius: 12px !important;
14
+ padding: 16px !important;
15
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
16
+ border: 1px solid rgba(255, 255, 255, 0.1) !important;
17
+ color: white !important;
18
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
19
+ width: 300px !important;
20
+ transition: all 0.3s ease !important;
21
+ }
22
+
23
+ .hf-panel.minimized {
24
+ width: 50px !important;
25
+ height: 50px !important;
26
+ padding: 8px !important;
27
+ }
28
+
29
+ .hf-panel-header {
30
+ display: flex !important;
31
+ justify-content: space-between !important;
32
+ align-items: center !important;
33
+ margin-bottom: 12px !important;
34
+ }
35
+
36
+ .hf-panel-title {
37
+ font-weight: 600 !important;
38
+ font-size: 16px !important;
39
+ }
40
+
41
+ .hf-panel-buttons {
42
+ display: flex !important;
43
+ gap: 8px !important;
44
+ }
45
+
46
+ .hf-btn {
47
+ background: rgba(255, 255, 255, 0.1) !important;
48
+ border: none !important;
49
+ color: white !important;
50
+ padding: 8px 12px !important;
51
+ border-radius: 6px !important;
52
+ cursor: pointer !important;
53
+ font-size: 14px !important;
54
+ transition: all 0.2s ease !important;
55
+ display: flex !important;
56
+ align-items: center !important;
57
+ gap: 6px !important;
58
+ }
59
+
60
+ .hf-btn:hover {
61
+ background: rgba(255, 255, 255, 0.2) !important;
62
+ }
63
+
64
+ .hf-btn.primary {
65
+ background: linear-gradient(135deg, #6366f1, #8b5cf6) !important;
66
+ }
67
+
68
+ .hf-btn.primary:hover {
69
+ background: linear-gradient(135deg, #4f46e5, #7c3aed) !important;
70
+ }
71
+
72
+ .hf-btn.minimize-btn, .hf-btn.close-btn {
73
+ padding: 6px !important;
74
+ width: 32px !important;
75
+ height: 32px !important;
76
+ justify-content: center !important;
77
+ }
78
+
79
+ .hf-panel-content {
80
+ display: flex !important;
81
+ flex-direction: column !important;
82
+ gap: 10px !important;
83
+ }
84
+
85
+ .hf-status {
86
+ padding: 10px !important;
87
+ border-radius: 6px !important;
88
+ font-size: 14px !important;
89
+ text-align: center !important;
90
+ display: none !important;
91
+ }
92
+
93
+ .hf-status.success {
94
+ background: rgba(16, 185, 129, 0.2) !important;
95
+ border: 1px solid rgba(16, 185, 129, 0.3) !important;
96
+ display: block !important;
97
+ }
98
+
99
+ .hf-status.error {
100
+ background: rgba(239, 68, 68, 0.2) !important;
101
+ border: 1px solid rgba(239, 68, 68, 0.3) !important;
102
+ display: block !important;
103
+ }
104
+
105
+ .minimized .hf-panel-content,
106
+ .minimized .hf-panel-header .hf-panel-title,
107
+ .minimized .hf-panel-buttons:not(.minimize-controls) {
108
+ display: none !important;
109
+ }
110
+
111
+ .minimized .minimize-controls {
112
+ position: absolute !important;
113
+ top: 50% !important;
114
+ left: 50% !important;
115
+ transform: translate(-50%, -50%) !important;
116
+ }
117
+ </style>
118
+
119
+ <div class="hf-panel" id="hfPanel">
120
+ <div class="hf-panel-header">
121
+ <div class="hf-panel-title">HF AI Assistant</div>
122
+ <div class="hf-panel-buttons minimize-controls">
123
+ <button class="hf-btn minimize-btn" id="minimizeBtn">βˆ’</button>
124
+ </div>
125
+ <div class="hf-panel-buttons">
126
+ <button class="hf-btn minimize-btn" id="minimizeBtn">βˆ’</button>
127
+ <button class="hf-btn close-btn" id="closeBtn">βœ•</button>
128
+ </div>
129
+ </div>
130
+
131
+ <div class="hf-panel-content">
132
+ <button class="hf-btn primary" id="enhanceBtn">
133
+ <span>✨</span> Enhance Interface
134
+ </button>
135
+ <button class="hf-btn" id="pasteBtn">
136
+ <span>πŸ“‹</span> Smart Paste
137
+ </button>
138
+ <button class="hf-btn" id="extractBtn">
139
+ <span>πŸ“₯</span> Extract Response
140
+ </button>
141
+ <button class="hf-btn" id="sendToZaiBtn" style="display: none;">
142
+ <span>➑️</span> Send to ZAI
143
+ </button>
144
+ <button class="hf-btn" id="fullscreenBtn">
145
+ <span>πŸ–₯️</span> Full Screen Mode
146
+ </button>
147
+ <button class="hf-btn" id="resetBtn">
148
+ <span>πŸ”„</span> Reset Page
149
+ </button>
150
+
151
+ <div class="hf-status" id="statusMessage"></div>
152
+ </div>
153
+ </div>
154
+ `;
155
+
156
+ this.init();
157
+ }
158
+
159
+ init() {
160
+ // Add event listeners
161
+ this.shadowRoot.getElementById('enhanceBtn').addEventListener('click', () => this.enhanceInterface());
162
+ this.shadowRoot.getElementById('pasteBtn').addEventListener('click', () => this.smartPaste());
163
+ this.shadowRoot.getElementById('extractBtn').addEventListener('click', () => this.extractResponse());
164
+ this.shadowRoot.getElementById('sendToZaiBtn').addEventListener('click', () => this.sendToZai());
165
+ this.shadowRoot.getElementById('fullscreenBtn').addEventListener('click', () => this.fullscreenMode());
166
+ this.shadowRoot.getElementById('resetBtn').addEventListener('click', () => this.resetPage());
167
+ this.shadowRoot.getElementById('minimizeBtn').addEventListener('click', () => this.toggleMinimize());
168
+ this.shadowRoot.getElementById('closeBtn').addEventListener('click', () => this.removePanel());
169
+
170
+ // Check if we're on Qwen to show Send to ZAI button
171
+ if (window.location.href.includes('qwen')) {
172
+ this.shadowRoot.getElementById('sendToZaiBtn').style.display = 'flex';
173
+ }
174
+
175
+ // Add keyboard shortcuts
176
+ document.addEventListener('keydown', (e) => {
177
+ if (e.ctrlKey && e.shiftKey) {
178
+ if (e.key === 'V' || e.key === 'v') {
179
+ e.preventDefault();
180
+ this.smartPaste();
181
+ } else if (e.key === 'C' || e.key === 'c') {
182
+ e.preventDefault();
183
+ this.extractResponse();
184
+ }
185
+ }
186
+ });
187
+
188
+ // Check for incoming data on Zai pages
189
+ if (window.location.href.includes('zai')) {
190
+ this.checkForIncomingData();
191
+ }
192
+ }
193
+
194
+ showMessage(message, type = 'success') {
195
+ const statusEl = this.shadowRoot.getElementById('statusMessage');
196
+ statusEl.textContent = message;
197
+ statusEl.className = `hf-status ${type}`;
198
+
199
+ setTimeout(() => {
200
+ statusEl.className = 'hf-status';
201
+ }, 4000);
202
+ }
203
+
204
+ enhanceInterface() {
205
+ // Apply smooth scroll
206
+ document.documentElement.style.scrollBehavior = 'smooth';
207
+
208
+ // Add padding to body
209
+ document.body.style.paddingBottom = '100px';
210
+
211
+ // Inject floating buttons
212
+ if (!document.getElementById('hfFloatingButtons')) {
213
+ const floatingButtons = document.createElement('div');
214
+ floatingButtons.id = 'hfFloatingButtons';
215
+ floatingButtons.innerHTML = `
216
+ <style>
217
+ #hfFloatingButtons {
218
+ position: fixed !important;
219
+ bottom: 20px !important;
220
+ right: 20px !important;
221
+ z-index: 99999 !important;
222
+ display: flex !important;
223
+ flex-direction: column !important;
224
+ gap: 10px !important;
225
+ }
226
+
227
+ .hf-float-btn {
228
+ width: 50px !important;
229
+ height: 50px !important;
230
+ border-radius: 50% !important;
231
+ background: linear-gradient(135deg, #6366f1, #8b5cf6) !important;
232
+ color: white !important;
233
+ border: none !important;
234
+ cursor: pointer !important;
235
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2) !important;
236
+ display: flex !important;
237
+ align-items: center !important;
238
+ justify-content: center !important;
239
+ font-size: 20px !important;
240
+ transition: all 0.2s ease !important;
241
+ }
242
+
243
+ .hf-float-btn:hover {
244
+ transform: scale(1.1) !important;
245
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3) !important;
246
+ }
247
+ </style>
248
+ <button class="hf-float-btn" id="scrollToBottomBtn">⬇️</button>
249
+ <button class="hf-float-btn" id="focusInputBtn">⌨️</button>
250
+ `;
251
+
252
+ document.body.appendChild(floatingButtons);
253
+
254
+ // Add event listeners for floating buttons
255
+ document.getElementById('scrollToBottomBtn').addEventListener('click', () => {
256
+ window.scrollTo(0, document.body.scrollHeight);
257
+ });
258
+
259
+ document.getElementById('focusInputBtn').addEventListener('click', () => {
260
+ const input = document.querySelector('textarea, input[type="text"], [contenteditable="true"]');
261
+ if (input) {
262
+ input.focus();
263
+ }
264
+ });
265
+ }
266
+
267
+ this.showMessage('Interface enhanced successfully!');
268
+ }
269
+
270
+ async smartPaste() {
271
+ try {
272
+ const text = await navigator.clipboard.readText();
273
+ const input = document.querySelector('textarea, input[type="text"], [contenteditable="true"]');
274
+
275
+ if (input) {
276
+ if (input.tagName === 'INPUT' || input.tagName === 'TEXTAREA') {
277
+ input.value = text;
278
+ } else {
279
+ input.textContent = text;
280
+ }
281
+ input.focus();
282
+ this.showMessage('Text pasted successfully!');
283
+ } else {
284
+ this.showMessage('No input field found', 'error');
285
+ }
286
+ } catch (err) {
287
+ this.showMessage('Failed to read clipboard: ' + err.message, 'error');
288
+ }
289
+ }
290
+
291
+ extractResponse() {
292
+ // Multiple selectors for different AI responses
293
+ const selectors = [
294
+ '[data-testid="bot-message"]',
295
+ '.bot-message',
296
+ '.ai-response',
297
+ '.message-assistant',
298
+ '.response',
299
+ 'div[class*="message"][class*="assistant"]',
300
+ 'div[class*="bot"]',
301
+ 'div[class*="ai"]'
302
+ ];
303
+
304
+ let responseText = '';
305
+
306
+ for (const selector of selectors) {
307
+ const elements = document.querySelectorAll(selector);
308
+ if (elements.length > 0) {
309
+ const lastElement = elements[elements.length - 1];
310
+ responseText = lastElement.textContent.trim();
311
+ break;
312
+ }
313
+ }
314
+
315
+ if (responseText) {
316
+ navigator.clipboard.writeText(responseText)
317
+ .then(() => this.showMessage('Response copied to clipboard!'))
318
+ .catch(err => this.showMessage('Failed to copy: ' + err.message, 'error'));
319
+ } else {
320
+ this.showMessage('No response found to extract', 'error');
321
+ }
322
+ }
323
+
324
+ sendToZai() {
325
+ // Extract latest response
326
+ const selectors = [
327
+ '[data-testid="bot-message"]',
328
+ '.bot-message',
329
+ '.ai-response',
330
+ '.message-assistant',
331
+ '.response',
332
+ 'div[class*="message"][class*="assistant"]',
333
+ 'div[class*="bot"]',
334
+ 'div[class*="ai"]'
335
+ ];
336
+
337
+ let responseText = '';
338
+
339
+ for (const selector of selectors) {
340
+ const elements = document.querySelectorAll(selector);
341
+ if (elements.length > 0) {
342
+ const lastElement = elements[elements.length - 1];
343
+ responseText = lastElement.textContent.trim();
344
+ break;
345
+ }
346
+ }
347
+
348
+ if (responseText) {
349
+ try {
350
+ localStorage.setItem('hfToZaiData', responseText);
351
+ window.open('https://zai.com', '_blank');
352
+ this.showMessage('Sent to ZAI successfully!');
353
+ } catch (err) {
354
+ this.showMessage('Failed to send to ZAI: ' + err.message, 'error');
355
+ }
356
+ } else {
357
+ this.showMessage('No response found to send', 'error');
358
+ }
359
+ }
360
+
361
+ checkForIncomingData() {
362
+ setInterval(() => {
363
+ const data = localStorage.getItem('hfToZaiData');
364
+ if (data) {
365
+ const input = document.querySelector('textarea, input[type="text"], [contenteditable="true"]');
366
+ if (input) {
367
+ if (input.tagName === 'INPUT' || input.tagName === 'TEXTAREA') {
368
+ input.value = data;
369
+ } else {
370
+ input.textContent = data;
371
+ }
372
+ input.focus();
373
+ localStorage.removeItem('hfToZaiData');
374
+ this.showMessage('Data received from HF!');
375
+ }
376
+ }
377
+ }, 1000);
378
+ }
379
+
380
+ fullscreenMode() {
381
+ const chatContainer = document.querySelector('.chat-container, .conversation, .chat, main') || document.body;
382
+
383
+ if (!document.fullscreenElement) {
384
+ if (chatContainer.requestFullscreen) {
385
+ chatContainer.requestFullscreen();
386
+ } else if (chatContainer.webkitRequestFullscreen) {
387
+ chatContainer.webkitRequestFullscreen();
388
+ } else if (chatContainer.msRequestFullscreen) {
389
+ chatContainer.msRequestFullscreen();
390
+ }
391
+
392
+ // Optimize layout
393
+ chatContainer.style.maxWidth = '100%';
394
+ chatContainer.style.width = '100%';
395
+ chatContainer.style.margin = '0';
396
+ chatContainer.style.padding = '20px';
397
+
398
+ this.showMessage('Fullscreen mode activated!');
399
+ } else {
400
+ if (document.exitFullscreen) {
401
+ document.exitFullscreen();
402
+ } else if (document.webkitExitFullscreen) {
403
+ document.webkitExitFullscreen();
404
+ } else if (document.msExitFullscreen) {
405
+ document.msExitFullscreen();
406
+ }
407
+ this.showMessage('Exited fullscreen mode');
408
+ }
409
+ }
410
+
411
+ resetPage() {
412
+ if (confirm('Are you sure you want to reset the page? This will reload the page and clear stored data.')) {
413
+ localStorage.removeItem('hfToZaiData');
414
+ window.location.reload();
415
+ }
416
+ }
417
+
418
+ toggleMinimize() {
419
+ const panel = this.shadowRoot.getElementById('hfPanel');
420
+ panel.classList.toggle('minimized');
421
+ }
422
+
423
+ removePanel() {
424
+ this.remove();
425
+ }
426
+ }
427
+
428
+ customElements.define('hf-panel', HuggingFacePanel);
index.html CHANGED
@@ -152,9 +152,60 @@
152
  <span id="toast-message">Copied to clipboard!</span>
153
  </div>
154
  </div>
155
-
156
  <script src="script.js"></script>
157
  <script>feather.replace();</script>
158
  <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  </body>
160
- </html>
 
152
  <span id="toast-message">Copied to clipboard!</span>
153
  </div>
154
  </div>
155
+ <script src="components/hf-panel.js"></script>
156
  <script src="script.js"></script>
157
  <script>feather.replace();</script>
158
  <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
159
+ <script>
160
+ // BookmarkletManager class
161
+ class BookmarkletManager {
162
+ constructor() {
163
+ this.panel = null;
164
+ }
165
+
166
+ init() {
167
+ // Check if we're on Hugging Face
168
+ if (!window.location.href.includes('huggingface.co')) {
169
+ return;
170
+ }
171
+
172
+ // Wait for DOM to be ready
173
+ if (document.readyState === 'loading') {
174
+ document.addEventListener('DOMContentLoaded', () => this.injectPanel());
175
+ } else {
176
+ this.injectPanel();
177
+ }
178
+ }
179
+
180
+ injectPanel() {
181
+ // Check if panel already exists
182
+ if (document.querySelector('hf-panel')) {
183
+ return;
184
+ }
185
+
186
+ // Create and inject panel
187
+ this.panel = document.createElement('hf-panel');
188
+ document.body.appendChild(this.panel);
189
+ }
190
+
191
+ removePanel() {
192
+ if (this.panel) {
193
+ this.panel.remove();
194
+ this.panel = null;
195
+ }
196
+ }
197
+ }
198
+
199
+ // Expose globally
200
+ window.bookmarkletManager = new BookmarkletManager();
201
+
202
+ // Auto-initialize when page is ready
203
+ window.initHFBookmarklet = () => {
204
+ window.bookmarkletManager.init();
205
+ };
206
+
207
+ // Run initialization
208
+ window.initHFBookmarklet();
209
+ </script>
210
  </body>
211
+ </html>
script.js CHANGED
@@ -491,8 +491,59 @@ copyBtn.addEventListener('click', copyToClipboard);
491
 
492
  // Initialize tabs
493
  switchTabs();
494
-
495
  // Auto-focus on load
496
  window.addEventListener('load', () => {
497
  inputText.focus();
498
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
 
492
  // Initialize tabs
493
  switchTabs();
 
494
  // Auto-focus on load
495
  window.addEventListener('load', () => {
496
  inputText.focus();
497
+ });
498
+
499
+ // Hugging Face Bookmarklet Integration
500
+ class BookmarkletManager {
501
+ constructor() {
502
+ this.panel = null;
503
+ }
504
+
505
+ init() {
506
+ // Check if we're on Hugging Face
507
+ if (!window.location.href.includes('huggingface.co')) {
508
+ return;
509
+ }
510
+
511
+ // Wait for DOM to be ready
512
+ if (document.readyState === 'loading') {
513
+ document.addEventListener('DOMContentLoaded', () => this.injectPanel());
514
+ } else {
515
+ this.injectPanel();
516
+ }
517
+ }
518
+
519
+ injectPanel() {
520
+ // Check if panel already exists
521
+ if (document.querySelector('hf-panel')) {
522
+ return;
523
+ }
524
+
525
+ // Create and inject panel
526
+ this.panel = document.createElement('hf-panel');
527
+ document.body.appendChild(this.panel);
528
+ }
529
+
530
+ removePanel() {
531
+ if (this.panel) {
532
+ this.panel.remove();
533
+ this.panel = null;
534
+ }
535
+ }
536
+ }
537
+
538
+ // Expose globally
539
+ window.bookmarkletManager = new BookmarkletManager();
540
+
541
+ // Auto-initialize when page is ready
542
+ window.initHFBookmarklet = () => {
543
+ window.bookmarkletManager.init();
544
+ };
545
+
546
+ // Run initialization if we're on Hugging Face
547
+ if (window.location.href.includes('huggingface.co')) {
548
+ window.initHFBookmarklet();
549
+ }