@hanzo/browser-extension 1.9.31 → 1.9.33

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 (62) hide show
  1. package/package.json +2 -1
  2. package/src/answer/AnswerEngine.tsx +553 -0
  3. package/src/manifest-firefox.json +10 -2
  4. package/src/manifest.json +17 -2
  5. package/src/newtab.css +277 -0
  6. package/src/newtab.html +13 -0
  7. package/src/popup.html +28 -0
  8. package/dist/browser-extension/README.md +0 -43
  9. package/dist/browser-extension/background-firefox.js +0 -4556
  10. package/dist/browser-extension/background.js +0 -7245
  11. package/dist/browser-extension/browser-control.js +0 -1317
  12. package/dist/browser-extension/chrome/ai-worker.js +0 -571
  13. package/dist/browser-extension/chrome/background.js +0 -7245
  14. package/dist/browser-extension/chrome/callback.html +0 -17
  15. package/dist/browser-extension/chrome/content-script.js +0 -2789
  16. package/dist/browser-extension/chrome/icon128.png +0 -0
  17. package/dist/browser-extension/chrome/icon16.png +0 -0
  18. package/dist/browser-extension/chrome/icon48.png +0 -0
  19. package/dist/browser-extension/chrome/manifest.json +0 -66
  20. package/dist/browser-extension/chrome/popup.css +0 -761
  21. package/dist/browser-extension/chrome/popup.html +0 -353
  22. package/dist/browser-extension/chrome/popup.js +0 -1650
  23. package/dist/browser-extension/chrome/sidebar.css +0 -1792
  24. package/dist/browser-extension/chrome/sidebar.html +0 -463
  25. package/dist/browser-extension/chrome/sidebar.js +0 -26541
  26. package/dist/browser-extension/cli.js +0 -233
  27. package/dist/browser-extension/firefox/ai-worker.js +0 -571
  28. package/dist/browser-extension/firefox/background.js +0 -4556
  29. package/dist/browser-extension/firefox/callback.html +0 -17
  30. package/dist/browser-extension/firefox/content-script.js +0 -2789
  31. package/dist/browser-extension/firefox/icon128.png +0 -0
  32. package/dist/browser-extension/firefox/icon16.png +0 -0
  33. package/dist/browser-extension/firefox/icon48.png +0 -0
  34. package/dist/browser-extension/firefox/manifest.json +0 -77
  35. package/dist/browser-extension/firefox/popup.css +0 -761
  36. package/dist/browser-extension/firefox/popup.html +0 -353
  37. package/dist/browser-extension/firefox/popup.js +0 -1650
  38. package/dist/browser-extension/firefox/sidebar.css +0 -1792
  39. package/dist/browser-extension/firefox/sidebar.html +0 -463
  40. package/dist/browser-extension/firefox/sidebar.js +0 -26541
  41. package/dist/browser-extension/icon128.png +0 -0
  42. package/dist/browser-extension/icon16.png +0 -0
  43. package/dist/browser-extension/icon48.png +0 -0
  44. package/dist/browser-extension/manifest.json +0 -66
  45. package/dist/browser-extension/package.json +0 -41
  46. package/dist/browser-extension/popup.js +0 -1650
  47. package/dist/browser-extension/safari/Info.plist +0 -21
  48. package/dist/browser-extension/safari/ai-worker.js +0 -571
  49. package/dist/browser-extension/safari/background.js +0 -7245
  50. package/dist/browser-extension/safari/callback.html +0 -17
  51. package/dist/browser-extension/safari/content-script.js +0 -2789
  52. package/dist/browser-extension/safari/icon128.png +0 -0
  53. package/dist/browser-extension/safari/icon16.png +0 -0
  54. package/dist/browser-extension/safari/icon48.png +0 -0
  55. package/dist/browser-extension/safari/popup.css +0 -761
  56. package/dist/browser-extension/safari/popup.html +0 -353
  57. package/dist/browser-extension/safari/popup.js +0 -1650
  58. package/dist/browser-extension/safari/sidebar.css +0 -1792
  59. package/dist/browser-extension/safari/sidebar.html +0 -463
  60. package/dist/browser-extension/safari/sidebar.js +0 -26541
  61. package/dist/browser-extension/sidebar.js +0 -26541
  62. package/dist/browser-extension/webgpu-ai.js +0 -568
package/src/newtab.css ADDED
@@ -0,0 +1,277 @@
1
+ /* Hanzo Answer Engine — strict monochrome (brand primaryColor #FFFFFF).
2
+ Shared tokens mirror popup.css / sidebar.css. */
3
+ :root {
4
+ --bg: #0a0a0a;
5
+ --surface: #0f0f0f;
6
+ --surface-2: #171717;
7
+ --surface-3: #1e1e1e;
8
+ --text: #fafafa;
9
+ --text-2: #a3a3a3;
10
+ --text-3: #666666;
11
+ --border: rgba(255, 255, 255, 0.10);
12
+ --border-2: rgba(255, 255, 255, 0.16);
13
+ --glass: rgba(255, 255, 255, 0.04);
14
+ --glass-2: rgba(255, 255, 255, 0.07);
15
+ --radius: 12px;
16
+ --radius-sm: 8px;
17
+ --radius-xs: 6px;
18
+ --sidebar-w: 232px;
19
+ }
20
+
21
+ * { box-sizing: border-box; }
22
+
23
+ html, body {
24
+ margin: 0;
25
+ height: 100%;
26
+ background: var(--bg);
27
+ color: var(--text);
28
+ font-family: 'Geist Sans', -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', sans-serif;
29
+ -webkit-font-smoothing: antialiased;
30
+ }
31
+
32
+ a { color: inherit; text-decoration: none; }
33
+
34
+ .ae-root {
35
+ display: grid;
36
+ grid-template-columns: var(--sidebar-w) 1fr;
37
+ height: 100vh;
38
+ transition: grid-template-columns 0.18s ease;
39
+ }
40
+ .ae-root.collapsed { grid-template-columns: 60px 1fr; }
41
+
42
+ /* ── Sidebar ─────────────────────────────────────────────── */
43
+ .ae-sidebar {
44
+ display: flex;
45
+ flex-direction: column;
46
+ gap: 6px;
47
+ padding: 14px 12px;
48
+ border-right: 1px solid var(--border);
49
+ background: var(--surface);
50
+ min-width: 0;
51
+ }
52
+ .ae-side-top { display: flex; align-items: center; justify-content: space-between; }
53
+ .ae-brand {
54
+ display: flex; align-items: center; gap: 9px;
55
+ background: none; border: none; color: var(--text);
56
+ font-size: 15px; font-weight: 600; letter-spacing: -0.01em;
57
+ cursor: pointer; padding: 4px; min-width: 0;
58
+ }
59
+ .ae-brand span { white-space: nowrap; overflow: hidden; }
60
+ .ae-collapse, .ae-new, .ae-signin {
61
+ cursor: pointer; font-family: inherit;
62
+ }
63
+ .ae-collapse {
64
+ background: none; border: none; color: var(--text-3);
65
+ padding: 4px; border-radius: var(--radius-xs); display: flex;
66
+ }
67
+ .ae-collapse:hover { color: var(--text); background: var(--glass); }
68
+ .ae-new {
69
+ display: flex; align-items: center; gap: 8px;
70
+ margin-top: 8px; padding: 9px 12px;
71
+ background: var(--text); color: #000; border: none;
72
+ border-radius: var(--radius-sm); font-size: 13px; font-weight: 600;
73
+ white-space: nowrap; overflow: hidden;
74
+ }
75
+ .ae-new:hover { background: #fff; }
76
+ .ae-nav { display: flex; flex-direction: column; margin-top: 12px; gap: 1px; }
77
+ .ae-nav a {
78
+ padding: 8px 10px; border-radius: var(--radius-xs);
79
+ color: var(--text-2); font-size: 13px; white-space: nowrap;
80
+ }
81
+ .ae-nav a:hover { background: var(--glass); color: var(--text); }
82
+ .ae-side-bottom { margin-top: auto; }
83
+ .ae-signin {
84
+ width: 100%; padding: 9px 12px;
85
+ background: var(--glass-2); border: 1px solid var(--border);
86
+ color: var(--text); border-radius: var(--radius-sm);
87
+ font-size: 12.5px; font-weight: 500; white-space: nowrap; overflow: hidden;
88
+ }
89
+ .ae-signin:hover { border-color: var(--border-2); background: var(--surface-2); }
90
+ .ae-signin.big { width: auto; padding: 10px 18px; font-size: 14px; }
91
+ .collapsed .ae-brand span, .collapsed .ae-new span, .collapsed .ae-nav { display: none; }
92
+
93
+ /* ── Main ────────────────────────────────────────────────── */
94
+ .ae-main { min-width: 0; overflow: hidden; display: flex; flex-direction: column; }
95
+
96
+ /* Hero (empty state) */
97
+ .ae-hero {
98
+ flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
99
+ gap: 26px; padding: 24px; overflow-y: auto;
100
+ }
101
+ .ae-wordmark {
102
+ display: flex; align-items: center; gap: 14px;
103
+ font-size: 46px; font-weight: 600; letter-spacing: -0.03em; color: var(--text);
104
+ }
105
+ .ae-hero-card { width: 100%; max-width: 720px; }
106
+ .ae-news { width: 100%; max-width: 720px; }
107
+ .ae-news-head, .ae-followups-head, .ae-model-group-label {
108
+ font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
109
+ color: var(--text-3); margin-bottom: 10px;
110
+ }
111
+ .ae-news-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
112
+ .ae-news-item {
113
+ display: flex; flex-direction: column; gap: 4px;
114
+ padding: 11px 13px; border: 1px solid var(--border);
115
+ border-radius: var(--radius-sm); background: var(--surface);
116
+ }
117
+ .ae-news-item:hover { border-color: var(--border-2); background: var(--surface-2); }
118
+ .ae-news-title { font-size: 13px; color: var(--text); line-height: 1.35; }
119
+ .ae-news-meta { font-size: 11px; color: var(--text-3); }
120
+
121
+ /* ── Input card ──────────────────────────────────────────── */
122
+ .ae-card {
123
+ background: var(--surface-2);
124
+ border: 1px solid var(--border-2);
125
+ border-radius: var(--radius);
126
+ box-shadow: 0 8px 40px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.02);
127
+ overflow: hidden;
128
+ }
129
+ .ae-input {
130
+ display: block; width: 100%; resize: none;
131
+ padding: 16px 18px 6px; min-height: 30px; max-height: 200px;
132
+ background: transparent; border: none; outline: none;
133
+ color: var(--text); font-family: inherit; font-size: 15px; line-height: 1.5;
134
+ }
135
+ .ae-input::placeholder { color: var(--text-3); }
136
+ .ae-card-row {
137
+ display: flex; align-items: center; justify-content: space-between;
138
+ gap: 8px; padding: 8px 10px 10px; flex-wrap: wrap;
139
+ }
140
+ .ae-chips { display: flex; gap: 4px; flex-wrap: wrap; }
141
+ .ae-chip {
142
+ padding: 4px 9px; border-radius: 999px; cursor: pointer;
143
+ background: var(--glass); border: 1px solid var(--border);
144
+ color: var(--text-3); font-size: 11px; font-family: inherit;
145
+ }
146
+ .ae-chip:hover { color: var(--text-2); }
147
+ .ae-chip.on { background: var(--text); color: #000; border-color: var(--text); }
148
+ .ae-card-right { display: flex; align-items: center; gap: 6px; }
149
+ .ae-modes { display: flex; gap: 2px; background: var(--glass); border-radius: var(--radius-xs); padding: 2px; }
150
+ .ae-mode {
151
+ padding: 4px 9px; border: none; background: none; cursor: pointer;
152
+ color: var(--text-3); font-size: 11.5px; font-family: inherit; border-radius: 5px;
153
+ }
154
+ .ae-mode:hover { color: var(--text-2); }
155
+ .ae-mode.on { background: var(--surface-3); color: var(--text); }
156
+ .ae-send {
157
+ width: 34px; height: 34px; flex-shrink: 0; cursor: pointer;
158
+ display: flex; align-items: center; justify-content: center;
159
+ background: var(--text); color: #000; border: none; border-radius: 50%;
160
+ }
161
+ .ae-send:disabled { opacity: 0.4; cursor: default; }
162
+
163
+ /* ── Model picker ────────────────────────────────────────── */
164
+ .ae-picker { position: relative; }
165
+ .ae-picker-btn {
166
+ display: flex; align-items: center; gap: 6px; cursor: pointer;
167
+ padding: 6px 10px; background: var(--glass); border: 1px solid var(--border);
168
+ border-radius: var(--radius-xs); color: var(--text-2); font-size: 12px; font-family: inherit;
169
+ }
170
+ .ae-picker-btn:hover { color: var(--text); border-color: var(--border-2); }
171
+ .ae-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-2); }
172
+ .ae-picker-menu {
173
+ position: absolute; bottom: calc(100% + 6px); right: 0; z-index: 40;
174
+ width: 320px; max-height: 420px; display: flex; flex-direction: column;
175
+ background: var(--surface-2); border: 1px solid var(--border-2);
176
+ border-radius: var(--radius-sm); box-shadow: 0 12px 48px rgba(0, 0, 0, 0.6); overflow: hidden;
177
+ }
178
+ .ae-picker-filter {
179
+ margin: 8px; padding: 8px 10px; background: var(--bg);
180
+ border: 1px solid var(--border); border-radius: var(--radius-xs);
181
+ color: var(--text); font-family: inherit; font-size: 13px; outline: none;
182
+ }
183
+ .ae-picker-list { overflow-y: auto; padding: 0 6px 6px; }
184
+ .ae-model-group-label { padding: 8px 8px 4px; margin: 0; }
185
+ .ae-model-row {
186
+ display: flex; flex-direction: column; gap: 2px; width: 100%; text-align: left;
187
+ padding: 8px 10px; background: none; border: none; cursor: pointer;
188
+ border-radius: var(--radius-xs); color: var(--text); font-family: inherit;
189
+ }
190
+ .ae-model-row:hover { background: var(--glass); }
191
+ .ae-model-row.active { background: var(--glass-2); }
192
+ .ae-model-name { font-size: 13px; display: flex; align-items: center; gap: 7px; }
193
+ .ae-model-desc { font-size: 11px; color: var(--text-3); line-height: 1.3; }
194
+ .ae-badge {
195
+ font-size: 9px; text-transform: uppercase; letter-spacing: 0.04em;
196
+ padding: 1px 5px; border-radius: 4px; background: var(--glass-2); color: var(--text-2);
197
+ }
198
+ .ae-plan-banner {
199
+ display: flex; align-items: center; justify-content: space-between; gap: 8px;
200
+ padding: 10px 12px; border-top: 1px solid var(--border);
201
+ font-size: 11.5px; color: var(--text-2); background: var(--surface);
202
+ }
203
+ .ae-plan-tiers { display: flex; gap: 8px; }
204
+ .ae-plan-tier b { color: var(--text); }
205
+
206
+ /* ── Answer view ─────────────────────────────────────────── */
207
+ .ae-answer-wrap { flex: 1; display: flex; flex-direction: column; min-height: 0; }
208
+ .ae-answer-scroll { flex: 1; overflow-y: auto; padding: 32px 28px 20px; }
209
+ .ae-answer-scroll > * { max-width: 760px; margin-left: auto; margin-right: auto; }
210
+ .ae-question { font-size: 26px; font-weight: 600; letter-spacing: -0.02em; margin: 0 0 20px; }
211
+ .ae-sources { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 16px; margin-bottom: 8px; }
212
+ .ae-source {
213
+ flex: 0 0 190px; display: flex; flex-direction: column; gap: 6px;
214
+ padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
215
+ background: var(--surface);
216
+ }
217
+ .ae-source:hover { border-color: var(--border-2); background: var(--surface-2); }
218
+ .ae-source-head { display: flex; align-items: center; gap: 6px; }
219
+ .ae-source-head img { border-radius: 3px; }
220
+ .ae-source-host { font-size: 11px; color: var(--text-3); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
221
+ .ae-source-idx { font-size: 10px; color: var(--text-3); border: 1px solid var(--border); border-radius: 4px; padding: 0 5px; }
222
+ .ae-source-title { font-size: 12.5px; line-height: 1.35; color: var(--text); display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
223
+
224
+ .ae-status { display: flex; align-items: center; gap: 10px; color: var(--text-2); font-size: 14px; padding: 8px 0; }
225
+
226
+ .ae-answer.markdown { font-size: 15px; line-height: 1.65; color: var(--text); }
227
+ .markdown h2 { font-size: 20px; margin: 22px 0 10px; font-weight: 600; }
228
+ .markdown h3 { font-size: 17px; margin: 18px 0 8px; font-weight: 600; }
229
+ .markdown h4, .markdown h5 { font-size: 15px; margin: 14px 0 6px; font-weight: 600; }
230
+ .markdown p { margin: 0 0 12px; }
231
+ .markdown ul, .markdown ol { margin: 0 0 12px; padding-left: 22px; }
232
+ .markdown li { margin: 4px 0; }
233
+ .markdown a { color: var(--text); text-decoration: underline; text-decoration-color: var(--text-3); text-underline-offset: 2px; }
234
+ .markdown a:hover { text-decoration-color: var(--text); }
235
+ .markdown code { background: var(--surface-2); padding: 1px 5px; border-radius: 4px; font-size: 0.9em; font-family: 'Geist Mono', ui-monospace, monospace; }
236
+
237
+ .ae-followups { margin-top: 26px; border-top: 1px solid var(--border); padding-top: 16px; }
238
+ .ae-followup {
239
+ display: flex; align-items: center; justify-content: space-between; width: 100%;
240
+ padding: 12px 4px; background: none; border: none; border-bottom: 1px solid var(--border);
241
+ color: var(--text); font-family: inherit; font-size: 14px; text-align: left; cursor: pointer;
242
+ }
243
+ .ae-followup:hover { color: var(--text); }
244
+ .ae-followup:hover .ae-followup-arrow { color: var(--text); transform: translateX(2px); }
245
+ .ae-followup-arrow { color: var(--text-3); transition: transform 0.12s ease; }
246
+
247
+ .ae-error { color: var(--text-2); padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); }
248
+ .ae-auth { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; padding: 8px 0; }
249
+ .ae-auth p { margin: 0; color: var(--text-2); font-size: 15px; }
250
+
251
+ .ae-answer-composer { padding: 12px 28px 20px; border-top: 1px solid var(--border); background: var(--bg); }
252
+ .ae-answer-composer > .ae-card { max-width: 760px; margin: 0 auto; }
253
+
254
+ /* ── Spinner ─────────────────────────────────────────────── */
255
+ .ae-spinner {
256
+ width: 14px; height: 14px; border-radius: 50%; display: inline-block;
257
+ border: 2px solid var(--border-2); border-top-color: var(--text);
258
+ animation: ae-spin 0.7s linear infinite;
259
+ }
260
+ @keyframes ae-spin { to { transform: rotate(360deg); } }
261
+
262
+ @media (max-width: 720px) {
263
+ .ae-root, .ae-root.collapsed { grid-template-columns: 1fr; }
264
+ .ae-sidebar { display: none; }
265
+ .ae-news-grid { grid-template-columns: 1fr; }
266
+ .ae-hero { gap: 20px; padding: 20px 16px; justify-content: flex-start; padding-top: 48px; }
267
+ .ae-wordmark { font-size: 34px; }
268
+ .ae-answer-scroll { padding: 20px 16px 16px; }
269
+ .ae-answer-composer { padding: 10px 16px 16px; }
270
+ .ae-question { font-size: 21px; }
271
+ /* Input card: let the control row wrap so the model picker + send stay
272
+ reachable at narrow widths (mobile-first). */
273
+ .ae-card-row { flex-direction: column; align-items: stretch; gap: 10px; }
274
+ .ae-card-right { justify-content: space-between; }
275
+ .ae-modes { flex: 1; justify-content: space-between; }
276
+ .ae-source { flex-basis: 150px; }
277
+ }
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Hanzo</title>
7
+ <link rel="stylesheet" href="newtab.css" />
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script src="newtab.js"></script>
12
+ </body>
13
+ </html>
package/src/popup.html CHANGED
@@ -57,6 +57,18 @@
57
57
  <div class="divider"></div>
58
58
  </div>
59
59
 
60
+ <!-- Embedded search: run a query through the Hanzo answer engine. -->
61
+ <form id="search-form" style="display:flex;gap:6px;margin-bottom:10px;">
62
+ <input id="search-input" type="text" placeholder="Search Hanzo AI…" autocomplete="off"
63
+ style="flex:1;min-width:0;padding:9px 12px;background:var(--surface-light,#171717);border:1px solid var(--border,rgba(255,255,255,0.12));border-radius:8px;color:var(--text,#fafafa);font-size:13px;font-family:inherit;outline:none;">
64
+ <button id="search-btn" type="submit" title="Search" aria-label="Search"
65
+ style="width:36px;height:36px;flex-shrink:0;display:flex;align-items:center;justify-content:center;background:var(--primary,#fafafa);border:none;border-radius:8px;color:#000;cursor:pointer;">
66
+ <svg viewBox="0 0 16 16" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8">
67
+ <circle cx="7" cy="7" r="4.5"/><path d="M11 11l3.5 3.5" stroke-linecap="round"/>
68
+ </svg>
69
+ </button>
70
+ </form>
71
+
60
72
  <!-- Actions: single Open Chat button + on-page surface settings. -->
61
73
  <button id="open-panel" class="btn btn-secondary" style="margin-bottom: 8px;">
62
74
  <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
@@ -96,6 +108,22 @@
96
108
 
97
109
  <div class="divider"></div>
98
110
 
111
+ <!-- AI Usage (Claude + Codex, from the current browser session) -->
112
+ <div class="usage-header" style="display:flex;align-items:center;justify-content:space-between;">
113
+ <h3>AI Usage</h3>
114
+ <button id="usage-refresh" class="btn-icon" title="Refresh usage">
115
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
116
+ <path d="M23 4v6h-6M1 20v-6h6"/>
117
+ <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>
118
+ </svg>
119
+ </button>
120
+ </div>
121
+ <div id="usage-list" class="usage-list" style="display:flex;flex-direction:column;gap:8px;"></div>
122
+ <a href="https://console.hanzo.ai/ai-accounts" target="_blank"
123
+ style="display:inline-block;margin-top:8px;font-size:11px;color:var(--text-muted,#888);">Manage AI accounts →</a>
124
+
125
+ <div class="divider"></div>
126
+
99
127
  <!-- Tools -->
100
128
  <h3>Tools</h3>
101
129
  <div class="tools-grid">
@@ -1,43 +0,0 @@
1
- # Hanzo Browser DevTools
2
-
3
- Click-to-code navigation for web developers with MCP integration.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install -g @hanzoai/browser-devtools
9
- ```
10
-
11
- ## Usage
12
-
13
- 1. Start the server:
14
- ```bash
15
- hanzo-browser-server start
16
- ```
17
-
18
- 2. Install the browser extension:
19
- ```bash
20
- hanzo-browser-server install-extension
21
- ```
22
-
23
- 3. Ctrl+Click any element in your browser to navigate to its source code!
24
-
25
- ## Features
26
-
27
- - 🎯 **Source-map support** for React, Vue, Svelte
28
- - 🔍 **Fallback tagging** for legacy code
29
- - 🚀 **MCP integration** for Claude Code
30
- - ⚡ **Lightning fast** WebSocket communication
31
-
32
- ## Integration with Claude Code
33
-
34
- The server exposes element selection events that can be consumed by MCP tools:
35
-
36
- ```javascript
37
- server.on('elementSelected', (data) => {
38
- // data.file - Source file path
39
- // data.line - Line number
40
- // data.column - Column number (if available)
41
- // data.framework - Detected framework
42
- });
43
- ```