@hanzo/browser-extension 1.9.35 → 1.9.36

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/browser-extension",
3
- "version": "1.9.35",
3
+ "version": "1.9.36",
4
4
  "description": "Hanzo AI Browser Extension",
5
5
  "main": "dist/background.js",
6
6
  "dependencies": {
@@ -3,6 +3,7 @@ import { createAiClient, type SearchEvent, type SearchMode, type SearchSource }
3
3
  import { fetchNews, type NewsItem } from './news.js';
4
4
  import { AUTO_MODEL, fetchModelCatalog, type ChatModel, type ModelGroup } from './model-catalog.js';
5
5
  import { renderMarkdown } from './markdown.js';
6
+ import { capture, contributeTrainingSample } from '../shared/consent.js';
6
7
 
7
8
  /**
8
9
  * Hanzo Answer Engine — the shared AI-answer surface (query → streamed answer +
@@ -321,6 +322,8 @@ export function AnswerEngine({ apiBase, getToken, signIn, initialQuery }: Answer
321
322
  setFollowUps([]);
322
323
  setError('');
323
324
  setNeedAuth(false);
325
+ void capture('answer_search', { mode, model: model.id });
326
+ let fullAnswer = '';
324
327
 
325
328
  const opts = {
326
329
  mode,
@@ -346,6 +349,7 @@ export function AnswerEngine({ apiBase, getToken, signIn, initialQuery }: Answer
346
349
  setAnswerSources(ev.sources);
347
350
  break;
348
351
  case 'text':
352
+ fullAnswer += ev.delta;
349
353
  setAnswer((a) => a + ev.delta);
350
354
  break;
351
355
  case 'follow_ups':
@@ -353,6 +357,10 @@ export function AnswerEngine({ apiBase, getToken, signIn, initialQuery }: Answer
353
357
  break;
354
358
  case 'done':
355
359
  setPhase('done');
360
+ void capture('answer_shown', { mode, model: model.id });
361
+ // Opt-in only: no-ops unless the user turned on training
362
+ // contribution (the consent module gates the send).
363
+ void contributeTrainingSample({ query: question, answer: fullAnswer, model: model.id });
356
364
  break;
357
365
  case 'error':
358
366
  if (ev.error.includes('__NO_TOKEN__') || /401|invalid api key/i.test(ev.error)) {
@@ -0,0 +1,78 @@
1
+ :root {
2
+ --bg: #0b0b0c;
3
+ --card: #131315;
4
+ --line: #26262a;
5
+ --text: #f4f4f5;
6
+ --muted: #9a9aa2;
7
+ --accent: #f4f4f5;
8
+ }
9
+ * { box-sizing: border-box; }
10
+ html, body {
11
+ margin: 0;
12
+ height: 100%;
13
+ background: var(--bg);
14
+ color: var(--text);
15
+ font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
16
+ }
17
+ body { display: grid; place-items: center; padding: 32px; }
18
+ .card {
19
+ width: 100%;
20
+ max-width: 520px;
21
+ background: var(--card);
22
+ border: 1px solid var(--line);
23
+ border-radius: 16px;
24
+ padding: 32px;
25
+ }
26
+ .brand { font-weight: 700; letter-spacing: 0.02em; opacity: 0.7; margin-bottom: 20px; }
27
+ h1 { font-size: 24px; margin: 0 0 8px; }
28
+ .lede { color: var(--muted); margin: 0 0 24px; }
29
+ .row {
30
+ display: flex;
31
+ align-items: flex-start;
32
+ gap: 12px;
33
+ padding: 14px 0;
34
+ border-top: 1px solid var(--line);
35
+ cursor: pointer;
36
+ }
37
+ .row input { position: absolute; opacity: 0; width: 0; height: 0; }
38
+ .switch {
39
+ flex: 0 0 auto;
40
+ width: 38px;
41
+ height: 22px;
42
+ border-radius: 999px;
43
+ background: #3a3a40;
44
+ position: relative;
45
+ transition: background 0.15s;
46
+ margin-top: 2px;
47
+ }
48
+ .switch::after {
49
+ content: "";
50
+ position: absolute;
51
+ top: 2px;
52
+ left: 2px;
53
+ width: 18px;
54
+ height: 18px;
55
+ border-radius: 50%;
56
+ background: #fff;
57
+ transition: transform 0.15s;
58
+ }
59
+ .row input:checked + .switch { background: var(--accent); }
60
+ .row input:checked + .switch::after { transform: translateX(16px); background: #0b0b0c; }
61
+ .text { display: flex; flex-direction: column; gap: 2px; }
62
+ .text strong { font-weight: 600; }
63
+ .text small { color: var(--muted); }
64
+ .cta {
65
+ width: 100%;
66
+ margin-top: 24px;
67
+ padding: 12px;
68
+ border: 0;
69
+ border-radius: 10px;
70
+ background: var(--accent);
71
+ color: #0b0b0c;
72
+ font-weight: 600;
73
+ font-size: 15px;
74
+ cursor: pointer;
75
+ }
76
+ .cta:active { transform: translateY(1px); }
77
+ .fine { color: var(--muted); font-size: 12px; text-align: center; margin: 16px 0 0; }
78
+ .fine a { color: var(--text); }
@@ -0,0 +1,45 @@
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" />
6
+ <title>Welcome to Hanzo</title>
7
+ <link rel="stylesheet" href="onboarding.css" />
8
+ </head>
9
+ <body>
10
+ <main class="card">
11
+ <div class="brand">Hanzo</div>
12
+ <h1>Welcome to Hanzo AI</h1>
13
+ <p class="lede">
14
+ Search, research and browse with Hanzo's own models. Before you start,
15
+ choose what you'd like to share — you can change this anytime in settings
16
+ or on your Hanzo account.
17
+ </p>
18
+
19
+ <label class="row">
20
+ <input type="checkbox" id="ob-insights" checked />
21
+ <span class="switch"></span>
22
+ <span class="text">
23
+ <strong>Anonymous usage insights</strong>
24
+ <small>Helps us improve Hanzo. No search text, no personal data — just a random per-install id.</small>
25
+ </span>
26
+ </label>
27
+
28
+ <label class="row">
29
+ <input type="checkbox" id="ob-training" />
30
+ <span class="switch"></span>
31
+ <span class="text">
32
+ <strong>Contribute to training Hanzo's open models</strong>
33
+ <small>Share your own searches &amp; answers so Hanzo's open models get better. Opt in — off unless you turn it on.</small>
34
+ </span>
35
+ </label>
36
+
37
+ <button id="ob-continue" class="cta">Get started</button>
38
+ <p class="fine">
39
+ Signed in? These choices save to your Hanzo account and stay in sync
40
+ everywhere. <a href="https://hanzo.ai/privacy" target="_blank" rel="noopener">Privacy</a>
41
+ </p>
42
+ </main>
43
+ <script src="onboarding.js"></script>
44
+ </body>
45
+ </html>
package/src/popup.html CHANGED
@@ -222,6 +222,34 @@
222
222
 
223
223
  <div class="divider"></div>
224
224
 
225
+ <!-- Privacy & data -->
226
+ <h3>Privacy &amp; data</h3>
227
+ <div class="features">
228
+ <div class="feature-toggle">
229
+ <label>
230
+ <input type="checkbox" id="insights-enabled" checked>
231
+ <span class="toggle"></span>
232
+ <div class="feature-info">
233
+ <strong>Usage insights</strong>
234
+ <small>Anonymous, helps improve Hanzo. Never your search text.</small>
235
+ </div>
236
+ </label>
237
+ </div>
238
+
239
+ <div class="feature-toggle">
240
+ <label>
241
+ <input type="checkbox" id="share-training">
242
+ <span class="toggle"></span>
243
+ <div class="feature-info">
244
+ <strong>Contribute to training</strong>
245
+ <small>Opt in to share your searches &amp; answers to train Hanzo's open models. Off by default.</small>
246
+ </div>
247
+ </label>
248
+ </div>
249
+ </div>
250
+
251
+ <div class="divider"></div>
252
+
225
253
  <!-- Browser Backend -->
226
254
  <div class="setting-group backend-picker">
227
255
  <h3>Backend</h3>