@hanzo/browser-extension 1.7.6 → 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 (144) hide show
  1. package/LICENSE +9 -18
  2. package/dist/browser-extension/content-script.js +1642 -123
  3. package/images/icon128.png +0 -0
  4. package/images/icon16.png +0 -0
  5. package/images/icon48.png +0 -0
  6. package/manifest.json +7 -2
  7. package/package.json +28 -10
  8. package/src/answer/AnswerEngine.tsx +553 -0
  9. package/src/chat-widget.tsx +96 -0
  10. package/src/gui-primitives.tsx +116 -0
  11. package/src/icon128.png +0 -0
  12. package/src/icon16.png +0 -0
  13. package/src/icon32.png +0 -0
  14. package/src/icon48.png +0 -0
  15. package/src/manifest-firefox.json +32 -13
  16. package/src/manifest.json +35 -11
  17. package/src/newtab.css +277 -0
  18. package/src/newtab.html +13 -0
  19. package/src/package.json +1 -1
  20. package/src/popup.css +352 -110
  21. package/src/popup.html +186 -47
  22. package/src/popup.js +196 -0
  23. package/src/sidebar.css +772 -156
  24. package/src/sidebar.html +268 -85
  25. package/src/sidebar.js +885 -0
  26. package/.github/workflows/docs.yml +0 -44
  27. package/.github/workflows/release.yml +0 -55
  28. package/README.md +0 -126
  29. package/dist/browser-extension/README.md +0 -43
  30. package/dist/browser-extension/ai-worker.js +0 -30
  31. package/dist/browser-extension/background-firefox.js +0 -875
  32. package/dist/browser-extension/background.js +0 -2732
  33. package/dist/browser-extension/browser-control.js +0 -683
  34. package/dist/browser-extension/cdp-bridge-server.js +0 -444
  35. package/dist/browser-extension/chrome/ai-worker.js +0 -571
  36. package/dist/browser-extension/chrome/background.js +0 -2732
  37. package/dist/browser-extension/chrome/callback.html +0 -17
  38. package/dist/browser-extension/chrome/content-script.js +0 -1270
  39. package/dist/browser-extension/chrome/icon128.png +0 -0
  40. package/dist/browser-extension/chrome/icon16.png +0 -0
  41. package/dist/browser-extension/chrome/icon32.png +0 -0
  42. package/dist/browser-extension/chrome/icon48.png +0 -0
  43. package/dist/browser-extension/chrome/manifest.json +0 -57
  44. package/dist/browser-extension/chrome/popup.css +0 -519
  45. package/dist/browser-extension/chrome/popup.html +0 -242
  46. package/dist/browser-extension/chrome/popup.js +0 -278
  47. package/dist/browser-extension/chrome/sidebar.css +0 -1176
  48. package/dist/browser-extension/chrome/sidebar.html +0 -280
  49. package/dist/browser-extension/chrome/sidebar.js +0 -779
  50. package/dist/browser-extension/cli.js +0 -233
  51. package/dist/browser-extension/firefox/ai-worker.js +0 -571
  52. package/dist/browser-extension/firefox/background.js +0 -875
  53. package/dist/browser-extension/firefox/callback.html +0 -17
  54. package/dist/browser-extension/firefox/content-script.js +0 -1270
  55. package/dist/browser-extension/firefox/icon128.png +0 -0
  56. package/dist/browser-extension/firefox/icon16.png +0 -0
  57. package/dist/browser-extension/firefox/icon32.png +0 -0
  58. package/dist/browser-extension/firefox/icon48.png +0 -0
  59. package/dist/browser-extension/firefox/manifest.json +0 -66
  60. package/dist/browser-extension/firefox/popup.css +0 -519
  61. package/dist/browser-extension/firefox/popup.html +0 -242
  62. package/dist/browser-extension/firefox/popup.js +0 -278
  63. package/dist/browser-extension/firefox/sidebar.css +0 -1176
  64. package/dist/browser-extension/firefox/sidebar.html +0 -280
  65. package/dist/browser-extension/firefox/sidebar.js +0 -779
  66. package/dist/browser-extension/hanzo-browser-extension-firefox-1.1.0.zip +0 -0
  67. package/dist/browser-extension/icon128.png +0 -0
  68. package/dist/browser-extension/icon16.png +0 -0
  69. package/dist/browser-extension/icon32.png +0 -0
  70. package/dist/browser-extension/icon48.png +0 -0
  71. package/dist/browser-extension/manifest.json +0 -57
  72. package/dist/browser-extension/package.json +0 -41
  73. package/dist/browser-extension/popup.css +0 -468
  74. package/dist/browser-extension/popup.html +0 -191
  75. package/dist/browser-extension/popup.js +0 -278
  76. package/dist/browser-extension/safari/Info.plist +0 -21
  77. package/dist/browser-extension/safari/ai-worker.js +0 -571
  78. package/dist/browser-extension/safari/background.js +0 -2732
  79. package/dist/browser-extension/safari/callback.html +0 -17
  80. package/dist/browser-extension/safari/content-script.js +0 -1270
  81. package/dist/browser-extension/safari/icon128.png +0 -0
  82. package/dist/browser-extension/safari/icon16.png +0 -0
  83. package/dist/browser-extension/safari/icon32.png +0 -0
  84. package/dist/browser-extension/safari/icon48.png +0 -0
  85. package/dist/browser-extension/safari/popup.css +0 -519
  86. package/dist/browser-extension/safari/popup.html +0 -242
  87. package/dist/browser-extension/safari/popup.js +0 -278
  88. package/dist/browser-extension/safari/sidebar.css +0 -1176
  89. package/dist/browser-extension/safari/sidebar.html +0 -280
  90. package/dist/browser-extension/safari/sidebar.js +0 -779
  91. package/dist/browser-extension/sidebar.css +0 -718
  92. package/dist/browser-extension/sidebar.html +0 -184
  93. package/dist/browser-extension/sidebar.js +0 -779
  94. package/dist/browser-extension/webgpu-ai.js +0 -495
  95. package/dist/cdp-bridge-server.js +0 -411
  96. package/dist/hanzo-ai-chrome-1.7.2.zip +0 -0
  97. package/dist/hanzo-ai-chrome-1.7.3.zip +0 -0
  98. package/dist/hanzo-ai-firefox-1.7.2.zip +0 -0
  99. package/dist/hanzo-ai-firefox-1.7.3.zip +0 -0
  100. package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.pbxproj +0 -1047
  101. package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  102. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json +0 -11
  103. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -98
  104. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png +0 -0
  105. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png +0 -0
  106. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png +0 -0
  107. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png +0 -0
  108. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png +0 -0
  109. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png +0 -0
  110. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png +0 -0
  111. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png +0 -0
  112. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png +0 -0
  113. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png +0 -0
  114. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/universal-icon-1024@1x.png +0 -0
  115. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/Contents.json +0 -6
  116. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json +0 -21
  117. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/icon128.png +0 -0
  118. package/dist/safari/Hanzo AI/Shared (App)/Resources/Base.lproj/Main.html +0 -20
  119. package/dist/safari/Hanzo AI/Shared (App)/Resources/Icon.png +0 -0
  120. package/dist/safari/Hanzo AI/Shared (App)/Resources/Script.js +0 -24
  121. package/dist/safari/Hanzo AI/Shared (App)/Resources/Style.css +0 -61
  122. package/dist/safari/Hanzo AI/Shared (App)/ViewController.swift +0 -81
  123. package/dist/safari/Hanzo AI/Shared (Extension)/SafariWebExtensionHandler.swift +0 -42
  124. package/dist/safari/Hanzo AI/iOS (App)/AppDelegate.swift +0 -24
  125. package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/LaunchScreen.storyboard +0 -36
  126. package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/Main.storyboard +0 -38
  127. package/dist/safari/Hanzo AI/iOS (App)/Info.plist +0 -27
  128. package/dist/safari/Hanzo AI/iOS (App)/SceneDelegate.swift +0 -18
  129. package/dist/safari/Hanzo AI/iOS (Extension)/Info.plist +0 -13
  130. package/dist/safari/Hanzo AI/macOS (App)/AppDelegate.swift +0 -21
  131. package/dist/safari/Hanzo AI/macOS (App)/Base.lproj/Main.storyboard +0 -124
  132. package/dist/safari/Hanzo AI/macOS (App)/Info.plist +0 -8
  133. package/dist/safari/Hanzo AI/macOS (Extension)/Info.plist +0 -13
  134. package/docs/_config.yml +0 -13
  135. package/docs/_layouts/default.html +0 -435
  136. package/docs/index.md +0 -54
  137. package/hanzo-ai-chrome-v1.7.6.zip +0 -0
  138. package/hanzo-ai-firefox-v1.7.6.zip +0 -0
  139. package/install-extension.sh +0 -75
  140. package/test/claude-integration.test.ts +0 -251
  141. package/test/server-frameworks-edge-cases.test.ts +0 -145
  142. package/test/server-frameworks.test.ts +0 -395
  143. package/test-cdp-connection.js +0 -140
  144. package/tsconfig.json +0 -19
package/src/popup.html CHANGED
@@ -20,48 +20,160 @@
20
20
  </header>
21
21
 
22
22
  <!-- Login Section -->
23
- <div id="login-section" class="section">
24
- <h2>Sign In</h2>
25
- <p class="subtitle">Connect to your Hanzo AI account</p>
26
- <button id="login-btn" class="btn btn-primary">Sign in with Hanzo</button>
27
- <p class="help-text">
28
- <a href="https://hanzo.id/register" target="_blank">Create account</a> •
29
- <a href="https://hanzo.id/forgot" target="_blank">Forgot password?</a>
30
- </p>
23
+ <div id="login-section" class="section login-section">
24
+ <div class="login-card">
25
+ <svg class="login-logo" viewBox="0 0 67 67" xmlns="http://www.w3.org/2000/svg">
26
+ <path d="M22.21 67V44.6369H0V67H22.21Z" fill="currentColor"/>
27
+ <path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="currentColor"/>
28
+ <path d="M22.21 0H0V22.3184H22.21V0Z" fill="currentColor"/>
29
+ <path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="currentColor"/>
30
+ <path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="currentColor"/>
31
+ </svg>
32
+ <h2 class="login-headline">Sign in to Hanzo AI</h2>
33
+ <p class="login-sub">Chat with AI, use browser tools, and build with agents.</p>
34
+ <button id="login-btn" class="login-signin-btn">Sign In</button>
35
+ <button id="signup-btn-popup" class="login-create-btn">Create account</button>
36
+ <p class="login-note">
37
+ Browser tools work without sign-in. <a href="https://docs.hanzo.ai" target="_blank">Learn more</a>
38
+ </p>
39
+ </div>
31
40
  </div>
32
41
 
33
42
  <!-- Main Section (shown after login) -->
34
43
  <div id="main-section" class="section hidden">
35
- <div class="user-info">
36
- <img id="user-avatar" class="avatar" src="" alt="">
37
- <div>
38
- <div id="user-name" class="user-name"></div>
39
- <div id="user-email" class="user-email"></div>
44
+ <div id="user-info-section" class="hidden">
45
+ <div class="user-info">
46
+ <img id="user-avatar" class="avatar" src="" alt="">
47
+ <div>
48
+ <div id="user-name" class="user-name"></div>
49
+ <div id="user-email" class="user-email"></div>
50
+ </div>
51
+ <button id="logout-btn" class="btn-icon" title="Sign out">
52
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
53
+ <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9"/>
54
+ </svg>
55
+ </button>
40
56
  </div>
41
- <button id="logout-btn" class="btn-icon" title="Sign out">
42
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
43
- <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9"/>
44
- </svg>
45
- </button>
57
+ <div class="divider"></div>
46
58
  </div>
47
59
 
48
- <div class="divider"></div>
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>
49
71
 
50
- <!-- Open Chat Panel -->
51
- <button id="open-panel" class="btn btn-primary" style="margin-bottom: 16px;">
72
+ <!-- Actions: single Open Chat button + on-page surface settings. -->
73
+ <button id="open-panel" class="btn btn-secondary" style="margin-bottom: 8px;">
52
74
  <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
53
75
  <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
54
76
  </svg>
55
- Open Chat Panel
56
- </button>
57
- <button id="open-page-overlay" class="btn btn-secondary" style="margin-bottom: 16px;">
58
- <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
59
- <path d="M4 4h16v12H8l-4 4V4z"/>
60
- </svg>
61
- Toggle On-Page Overlay
77
+ Open Chat
62
78
  </button>
63
79
 
80
+ <!-- On-page chat config -->
81
+ <div class="onpage-config" style="display:flex;flex-direction:column;gap:6px;margin-bottom:12px;font-size:11px;">
82
+ <div class="feature-toggle" style="display:flex;justify-content:space-between;align-items:center;">
83
+ <label style="display:flex;align-items:center;gap:6px;cursor:pointer;">
84
+ <input type="checkbox" id="overlay-enabled" checked>
85
+ <span>On-page chat panel</span>
86
+ </label>
87
+ <span style="color:var(--text-muted,#888);font-size:10px;">overlay vs new tab</span>
88
+ </div>
89
+
90
+ <div id="overlay-side-row" class="side-picker" style="display:flex;gap:6px;align-items:center;">
91
+ <span style="color:var(--text-muted,#888);">Pin:</span>
92
+ <button id="pin-left" class="btn btn-ghost" style="flex:1;padding:4px 8px;font-size:11px;">Left</button>
93
+ <button id="pin-right" class="btn btn-ghost" style="flex:1;padding:4px 8px;font-size:11px;" data-active="true">Right</button>
94
+ </div>
95
+
96
+ <div id="overlay-width-row" style="display:flex;gap:6px;align-items:center;">
97
+ <span style="color:var(--text-muted,#888);">Width:</span>
98
+ <button class="btn btn-ghost width-btn" data-width="compact" style="flex:1;padding:4px 8px;font-size:11px;">Compact</button>
99
+ <button class="btn btn-ghost width-btn" data-width="default" style="flex:1;padding:4px 8px;font-size:11px;" data-active="true">Default</button>
100
+ <button class="btn btn-ghost width-btn" data-width="wide" style="flex:1;padding:4px 8px;font-size:11px;">Wide</button>
101
+ </div>
102
+
103
+ <span style="color:var(--text-muted,#888);font-size:10px;line-height:1.4;">
104
+ FF native sidebar: View → Sidebar → Hanzo AI.<br>
105
+ Disable to fall back to a standalone tab — useful on sites with strict CSP.
106
+ </span>
107
+ </div>
108
+
109
+ <div class="divider"></div>
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
+
127
+ <!-- Tools -->
128
+ <h3>Tools</h3>
129
+ <div class="tools-grid">
130
+ <button id="tool-picker" class="tool-btn" title="Pick an element on the page">
131
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
132
+ <path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"/>
133
+ <path d="M13 13l6 6"/>
134
+ </svg>
135
+ <span>Selector</span>
136
+ </button>
137
+ <button id="tool-screenshot" class="tool-btn" title="Capture visible page">
138
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
139
+ <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
140
+ <circle cx="12" cy="13" r="4"/>
141
+ </svg>
142
+ <span>Screenshot</span>
143
+ </button>
144
+ <button id="tool-pageinfo" class="tool-btn" title="Copy page info to clipboard">
145
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
146
+ <circle cx="12" cy="12" r="10"/>
147
+ <path d="M12 16v-4M12 8h.01"/>
148
+ </svg>
149
+ <span>Page Info</span>
150
+ </button>
151
+ <button id="tool-accessibility" class="tool-btn" title="Run accessibility audit">
152
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
153
+ <circle cx="12" cy="4" r="2"/>
154
+ <path d="M12 6v6M8 8l4 2 4-2M8 22l2-6h4l2 6"/>
155
+ </svg>
156
+ <span>A11y Audit</span>
157
+ </button>
158
+ <button id="tool-performance" class="tool-btn" title="Run performance audit">
159
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
160
+ <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
161
+ </svg>
162
+ <span>Perf Audit</span>
163
+ </button>
164
+ <button id="tool-console" class="tool-btn" title="Evaluate JS in page context">
165
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
166
+ <polyline points="4 17 10 11 4 5"/>
167
+ <line x1="12" y1="19" x2="20" y2="19"/>
168
+ </svg>
169
+ <span>Console</span>
170
+ </button>
171
+ </div>
172
+
173
+ <div class="divider"></div>
174
+
64
175
  <!-- Features -->
176
+ <h3>Features</h3>
65
177
  <div class="features">
66
178
  <div class="feature-toggle">
67
179
  <label>
@@ -112,7 +224,7 @@
112
224
 
113
225
  <!-- Browser Backend -->
114
226
  <div class="setting-group backend-picker">
115
- <h3>Browser Backend</h3>
227
+ <h3>Backend</h3>
116
228
  <div class="backend-select-wrapper">
117
229
  <select id="browser-backend">
118
230
  <option value="auto">Auto (default)</option>
@@ -131,22 +243,23 @@
131
243
  <div class="divider"></div>
132
244
 
133
245
  <!-- Connection Status -->
246
+ <h3>Status</h3>
134
247
  <div class="status">
135
248
  <div class="status-item">
136
249
  <span class="status-dot" id="zap-status"></span>
137
- <span>ZAP Protocol</span>
250
+ <span>ZAP Bridge</span>
138
251
  <span id="zap-detail" class="status-detail">Discovering...</span>
139
252
  </div>
140
- <div class="status-item">
141
- <span class="status-dot" id="mcp-status"></span>
142
- <span>MCP Server</span>
143
- <span id="mcp-port" class="status-detail">Fallback</span>
144
- </div>
145
253
  <div class="status-item">
146
254
  <span class="status-dot" id="cdp-status"></span>
147
255
  <span>CDP Bridge</span>
148
256
  <span id="cdp-detail" class="status-detail">Checking...</span>
149
257
  </div>
258
+ <div class="status-item">
259
+ <span class="status-dot" id="mcp-status"></span>
260
+ <span>MCP Bridge</span>
261
+ <span id="mcp-port" class="status-detail">:9224</span>
262
+ </div>
150
263
  <div class="status-item">
151
264
  <span class="status-dot" id="gpu-status"></span>
152
265
  <span>WebGPU</span>
@@ -158,15 +271,19 @@
158
271
 
159
272
  <!-- Actions -->
160
273
  <div class="actions">
161
- <button id="test-connection" class="btn btn-secondary">Test Connection</button>
162
- <button id="open-settings" class="btn btn-secondary">Settings</button>
274
+ <button id="test-connection" class="btn btn-ghost">Test Connection</button>
275
+ <button id="open-settings" class="btn btn-ghost">Settings</button>
163
276
  </div>
164
277
 
165
278
  <!-- Quick Guide -->
166
- <div class="guide" style="margin-top: 16px;">
167
- <h3>Quick Guide</h3>
168
- <p><kbd>Alt</kbd> + <kbd>Click</kbd> any element to navigate to source</p>
169
- <p><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>H</kbd> to open Hanzo AI panel</p>
279
+ <div class="guide" style="margin-top: 12px;">
280
+ <h3 style="text-transform: none; letter-spacing: 0; color: var(--text);">Shortcuts</h3>
281
+ <p>
282
+ <kbd id="inspect-shortcut-display">Ctrl</kbd> + <kbd>Click</kbd>
283
+ any element to jump to source
284
+ <button id="record-inspect-shortcut" class="btn-link" style="margin-left:6px;font-size:11px;">edit</button>
285
+ </p>
286
+ <p><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>H</kbd> open Hanzo panel</p>
170
287
  </div>
171
288
  </div>
172
289
 
@@ -226,15 +343,37 @@
226
343
  </label>
227
344
  </div>
228
345
 
229
- <button id="save-settings" class="btn btn-primary">Save Settings</button>
346
+ <div class="setting-group">
347
+ <h3>Keyboard</h3>
348
+ <label>
349
+ Inspect modifier
350
+ <div style="display:flex;gap:8px;align-items:center;margin-top:4px;">
351
+ <kbd id="inspect-shortcut-current" style="flex:1;font-family:monospace;padding:4px 8px;background:var(--surface-2,#222);border-radius:4px;font-size:12px;">Ctrl</kbd>
352
+ <button id="inspect-shortcut-record" type="button" class="btn btn-ghost" style="padding:4px 10px;">Record</button>
353
+ <button id="inspect-shortcut-reset" type="button" class="btn btn-ghost" style="padding:4px 10px;">Reset</button>
354
+ </div>
355
+ <small style="color:var(--text-muted,#888);font-size:11px;">
356
+ Hold + click any element on a page to jump to its source. Default
357
+ is Ctrl (or ⌘ on Mac). Click "Record" then press the chord you
358
+ want — modifiers alone or modifier+letter both work.
359
+ </small>
360
+ </label>
361
+ </div>
230
362
 
231
- <p class="help-text" style="margin-top: 16px;">
232
- <a href="https://console.hanzo.ai" target="_blank">Console</a> •
233
- <a href="https://billing.hanzo.ai" target="_blank">Billing</a> •
234
- <a href="https://docs.hanzo.ai" target="_blank">Docs</a>
235
- </p>
363
+ <button id="save-settings" class="btn btn-primary">Save Settings</button>
236
364
  </div>
237
365
  </div>
366
+
367
+ <!-- Footer: version + nav links -->
368
+ <div class="footer-version" style="text-align:center;font-size:10px;color:var(--text-muted,#888);margin-top:14px;letter-spacing:0.04em;">
369
+ Hanzo AI <span id="footer-version">…</span>
370
+ </div>
371
+ <div class="footer-links">
372
+ <a href="https://docs.hanzo.ai" target="_blank">Docs</a>
373
+ <a href="https://console.hanzo.ai" target="_blank">Console</a>
374
+ <a href="https://github.com/hanzoai/extension" target="_blank">GitHub</a>
375
+ <a href="https://hanzo.ai" target="_blank">hanzo.ai</a>
376
+ </div>
238
377
  </div>
239
378
 
240
379
  <script src="popup.js"></script>
package/src/popup.js ADDED
@@ -0,0 +1,196 @@
1
+ // Hanzo AI — Popup Script
2
+ // Uses background message passing for auth (not direct storage access).
3
+
4
+ document.addEventListener('DOMContentLoaded', () => {
5
+ const loginSection = document.getElementById('login-section');
6
+ const mainSection = document.getElementById('main-section');
7
+ const settingsSection = document.getElementById('settings-section');
8
+
9
+ // Auth
10
+ const loginBtn = document.getElementById('login-btn');
11
+ const logoutBtn = document.getElementById('logout-btn');
12
+
13
+ // Open panel
14
+ const openPanel = document.getElementById('open-panel');
15
+
16
+ // Status dots
17
+ const zapStatus = document.getElementById('zap-status');
18
+ const zapDetail = document.getElementById('zap-detail');
19
+ const mcpStatus = document.getElementById('mcp-status');
20
+ const mcpPort = document.getElementById('mcp-port');
21
+ const cdpStatus = document.getElementById('cdp-status');
22
+ const cdpDetail = document.getElementById('cdp-detail');
23
+ const gpuStatus = document.getElementById('gpu-status');
24
+ const gpuDetail = document.getElementById('gpu-detail');
25
+
26
+ // Settings
27
+ const openSettings = document.getElementById('open-settings');
28
+ const backBtn = document.getElementById('back-btn');
29
+ const saveSettings = document.getElementById('save-settings');
30
+ const testConnection = document.getElementById('test-connection');
31
+
32
+ // --- Auth via background ---
33
+ function checkAuth() {
34
+ // Always show main section and status (tools work without login)
35
+ mainSection.classList.remove('hidden');
36
+ refreshStatus();
37
+
38
+ chrome.runtime.sendMessage({ action: 'auth.status' }, (response) => {
39
+ if (chrome.runtime.lastError) return;
40
+ if (response?.success && response.authenticated) {
41
+ loginSection.classList.add('hidden');
42
+ if (response.user) {
43
+ const avatar = document.getElementById('user-avatar');
44
+ const name = document.getElementById('user-name');
45
+ const email = document.getElementById('user-email');
46
+ avatar.src = response.user.picture || response.user.avatar || 'icon48.png';
47
+ name.textContent = response.user.name || response.user.displayName || 'Hanzo User';
48
+ email.textContent = response.user.email || '';
49
+ }
50
+ } else {
51
+ loginSection.classList.remove('hidden');
52
+ }
53
+ });
54
+ }
55
+
56
+ loginBtn?.addEventListener('click', () => {
57
+ loginBtn.disabled = true;
58
+ loginBtn.textContent = 'Signing in...';
59
+ chrome.runtime.sendMessage({ action: 'auth.login' }, (response) => {
60
+ loginBtn.disabled = false;
61
+ loginBtn.innerHTML = '<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4M10 17l5-5-5-5M15 12H3"/></svg> Sign in with Hanzo';
62
+ if (response?.success) {
63
+ checkAuth();
64
+ }
65
+ });
66
+ });
67
+
68
+ logoutBtn?.addEventListener('click', () => {
69
+ chrome.runtime.sendMessage({ action: 'auth.logout' }, () => {
70
+ mainSection.classList.add('hidden');
71
+ loginSection.classList.remove('hidden');
72
+ });
73
+ });
74
+
75
+ // --- Open side panel ---
76
+ openPanel?.addEventListener('click', () => {
77
+ if (chrome.sidePanel) {
78
+ chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
79
+ if (tabs[0]?.id) {
80
+ chrome.sidePanel.open({ tabId: tabs[0].id });
81
+ window.close();
82
+ }
83
+ });
84
+ } else if (typeof browser !== 'undefined' && browser.sidebarAction) {
85
+ browser.sidebarAction.open();
86
+ window.close();
87
+ } else {
88
+ chrome.tabs.create({ url: chrome.runtime.getURL('sidebar.html') });
89
+ window.close();
90
+ }
91
+ });
92
+
93
+ // --- Status ---
94
+ function refreshStatus() {
95
+ // ZAP status
96
+ chrome.runtime.sendMessage({ action: 'zap.status' }, (response) => {
97
+ if (chrome.runtime.lastError) return;
98
+ if (response?.success) {
99
+ const zap = response.zap;
100
+ if (zap.connected) {
101
+ zapStatus.classList.add('connected');
102
+ zapStatus.classList.remove('disconnected');
103
+ const mcpCount = zap.mcps?.length || 0;
104
+ const toolCount = zap.mcps?.reduce((sum, m) => sum + (m.tools?.length || 0), 0) || 0;
105
+ zapDetail.textContent = `${mcpCount} MCP(s), ${toolCount} tools`;
106
+ } else {
107
+ zapStatus.classList.remove('connected');
108
+ zapStatus.classList.add('disconnected');
109
+ zapDetail.textContent = 'Not connected';
110
+ }
111
+ }
112
+ });
113
+
114
+ // GPU status
115
+ chrome.runtime.sendMessage({ action: 'runLocalAI', prompt: '' }, (response) => {
116
+ if (chrome.runtime.lastError) return;
117
+ gpuStatus.classList.add(response?.success ? 'connected' : 'disconnected');
118
+ gpuStatus.classList.remove(response?.success ? 'disconnected' : 'connected');
119
+ gpuDetail.textContent = response?.success ? 'Available' : 'Not available';
120
+ });
121
+
122
+ // MCP/CDP — set as active for now (checked via ZAP)
123
+ mcpStatus.classList.add('connected');
124
+ mcpPort.textContent = 'Fallback';
125
+ cdpStatus.classList.add('connected');
126
+ cdpDetail.textContent = 'Active';
127
+ }
128
+
129
+ // --- Settings ---
130
+ openSettings?.addEventListener('click', () => {
131
+ mainSection.classList.add('hidden');
132
+ settingsSection.classList.remove('hidden');
133
+ loadSettings();
134
+ });
135
+
136
+ backBtn?.addEventListener('click', () => {
137
+ settingsSection.classList.add('hidden');
138
+ mainSection.classList.remove('hidden');
139
+ });
140
+
141
+ function loadSettings() {
142
+ chrome.storage.local.get(['mcpPort', 'cdpPort', 'zapPorts'], (result) => {
143
+ const mcpPortInput = document.getElementById('mcp-port-setting');
144
+ const cdpPortInput = document.getElementById('cdp-port-setting');
145
+ const zapPortsInput = document.getElementById('zap-ports-setting');
146
+
147
+ if (mcpPortInput) mcpPortInput.value = result.mcpPort || 3001;
148
+ if (cdpPortInput) cdpPortInput.value = result.cdpPort || 9223;
149
+ if (zapPortsInput) zapPortsInput.value = (result.zapPorts || [9999, 9998, 9997, 9996, 9995]).join(',');
150
+ });
151
+ }
152
+
153
+ saveSettings?.addEventListener('click', () => {
154
+ const mcpPortVal = parseInt(document.getElementById('mcp-port-setting')?.value) || 3001;
155
+ const cdpPortVal = parseInt(document.getElementById('cdp-port-setting')?.value) || 9223;
156
+ const zapPortsVal = (document.getElementById('zap-ports-setting')?.value || '')
157
+ .split(',').map(p => parseInt(p.trim())).filter(p => p > 0 && p < 65536);
158
+
159
+ chrome.storage.local.set({
160
+ mcpPort: mcpPortVal,
161
+ cdpPort: cdpPortVal,
162
+ zapPorts: zapPortsVal.length ? zapPortsVal : [9999, 9998, 9997, 9996, 9995],
163
+ }, () => {
164
+ saveSettings.textContent = 'Saved!';
165
+ setTimeout(() => { saveSettings.textContent = 'Save Settings'; }, 1500);
166
+ });
167
+ });
168
+
169
+ // --- Test Connection ---
170
+ testConnection?.addEventListener('click', () => {
171
+ testConnection.textContent = 'Testing...';
172
+ testConnection.disabled = true;
173
+
174
+ chrome.runtime.sendMessage({ action: 'zap.discover' }, () => {
175
+ refreshStatus();
176
+ testConnection.textContent = 'Test Connection';
177
+ testConnection.disabled = false;
178
+ });
179
+ });
180
+
181
+ // Feature toggles
182
+ ['source-maps', 'webgpu-ai', 'browser-control', 'tab-filesystem'].forEach(id => {
183
+ const checkbox = document.getElementById(id);
184
+ if (checkbox) {
185
+ chrome.storage.local.get([id], (result) => {
186
+ checkbox.checked = result[id] !== false; // default on
187
+ });
188
+ checkbox.addEventListener('change', () => {
189
+ chrome.storage.local.set({ [id]: checkbox.checked });
190
+ });
191
+ }
192
+ });
193
+
194
+ // Init
195
+ checkAuth();
196
+ });