total-recall-brain 3.2.2 → 3.2.3

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.
@@ -131,4 +131,19 @@
131
131
 
132
132
  // Wait 2 seconds after page load to avoid interfering with page rendering
133
133
  setTimeout(queryBrain, 2000);
134
+
135
+ // ---- Listen for page context requests ----
136
+ chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
137
+ if (msg.type === 'GET_PAGE_TEXT') {
138
+ const selection = window.getSelection().toString().trim();
139
+ const pageText = document.body.innerText.slice(0, 10000); // limit to 10k chars to avoid token blowout
140
+ sendResponse({
141
+ url: location.href,
142
+ title: document.title,
143
+ selection,
144
+ pageText
145
+ });
146
+ }
147
+ return true;
148
+ });
134
149
  })();
@@ -39,9 +39,27 @@ async function search(query, topK = 3) {
39
39
  });
40
40
  }
41
41
 
42
- async function healthCheck() {
43
- return brainFetch('/health');
42
+ async function chat(messages, options = {}) {
43
+ const { brainUrl, pat } = await getConfig();
44
+ const url = `${brainUrl}/v1/chat/completions`;
45
+ const headers = { 'Content-Type': 'application/json' };
46
+ if (pat) headers['Authorization'] = `Bearer ${pat}`;
47
+ if (options.sessionId) headers['x-session-id'] = options.sessionId;
48
+
49
+ const res = await fetch(url, {
50
+ method: 'POST',
51
+ headers,
52
+ body: JSON.stringify({
53
+ messages,
54
+ model: options.model || 'gemini',
55
+ brainId: options.brainId || 'global',
56
+ groundingNodes: options.groundingNodes || []
57
+ })
58
+ });
59
+ if (res.status === 401) throw new Error('Authentication failed — check your PAT token');
60
+ if (!res.ok) throw new Error(`Brain API error: ${res.status}`);
61
+ return res.json();
44
62
  }
45
63
 
46
64
  // Expose as a global namespace for non-module contexts (service worker, popup, etc.)
47
- self.BrainClient = { getConfig, brainFetch, share, search, healthCheck };
65
+ self.BrainClient = { getConfig, brainFetch, share, search, healthCheck, chat };
@@ -115,6 +115,12 @@ body {
115
115
  transform: scale(0.97);
116
116
  }
117
117
 
118
+ .btn:disabled, .btn.loading {
119
+ opacity: 0.6;
120
+ cursor: not-allowed;
121
+ transform: none !important;
122
+ }
123
+
118
124
  .btn.primary {
119
125
  background: #89b4fa;
120
126
  color: #11111b;
@@ -52,6 +52,11 @@
52
52
 
53
53
  // ---- Remember ----
54
54
  btnRemember.addEventListener('click', async () => {
55
+ if (btnRemember.disabled) return;
56
+ const originalText = btnRemember.innerHTML;
57
+ btnRemember.innerHTML = '⏳ Remembering...';
58
+ btnRemember.disabled = true;
59
+ btnRemember.classList.add('loading');
55
60
  try {
56
61
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
57
62
  const payload = {
@@ -67,11 +72,20 @@
67
72
  noteInput.value = '';
68
73
  } catch (err) {
69
74
  showStatus('Error: ' + err.message, true);
75
+ } finally {
76
+ btnRemember.innerHTML = originalText;
77
+ btnRemember.disabled = false;
78
+ btnRemember.classList.remove('loading');
70
79
  }
71
80
  });
72
81
 
73
82
  // ---- Research ----
74
83
  btnResearch.addEventListener('click', async () => {
84
+ if (btnResearch.disabled) return;
85
+ const originalText = btnResearch.innerHTML;
86
+ btnResearch.innerHTML = '⏳ Researching...';
87
+ btnResearch.disabled = true;
88
+ btnResearch.classList.add('loading');
75
89
  try {
76
90
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
77
91
  const payload = {
@@ -87,6 +101,10 @@
87
101
  noteInput.value = '';
88
102
  } catch (err) {
89
103
  showStatus('Error: ' + err.message, true);
104
+ } finally {
105
+ btnResearch.innerHTML = originalText;
106
+ btnResearch.disabled = false;
107
+ btnResearch.classList.remove('loading');
90
108
  }
91
109
  });
92
110
 
@@ -11,8 +11,8 @@ body {
11
11
  background: #11111b;
12
12
  color: #cdd6f4;
13
13
  width: 100%;
14
- min-height: 100vh;
15
- overflow-x: hidden;
14
+ height: 100vh;
15
+ overflow: hidden;
16
16
  }
17
17
 
18
18
  .panel {
@@ -23,19 +23,18 @@ body {
23
23
 
24
24
  /* ---- Header ---- */
25
25
  .panel-header {
26
- position: sticky;
27
- top: 0;
28
- z-index: 10;
26
+ position: relative;
29
27
  display: flex;
30
28
  align-items: center;
31
29
  justify-content: space-between;
32
30
  padding: 14px 16px;
33
31
  background: #181825;
34
32
  border-bottom: 1px solid #313244;
33
+ flex-shrink: 0;
35
34
  }
36
35
 
37
36
  .panel-header h1 {
38
- font-size: 16px;
37
+ font-size: 15px;
39
38
  font-weight: 700;
40
39
  letter-spacing: 0.3px;
41
40
  }
@@ -58,9 +57,75 @@ body {
58
57
  box-shadow: 0 0 6px #f38ba8;
59
58
  }
60
59
 
60
+ .badge {
61
+ font-size: 10px;
62
+ font-weight: 600;
63
+ background: #313244;
64
+ color: #cba6f7;
65
+ padding: 2px 8px;
66
+ border-radius: 6px;
67
+ text-transform: capitalize;
68
+ border: 1px solid #45475a;
69
+ }
70
+
71
+ /* ---- Tab Navigation Bar ---- */
72
+ .tab-bar {
73
+ display: flex;
74
+ background: #181825;
75
+ border-bottom: 1px solid #313244;
76
+ flex-shrink: 0;
77
+ }
78
+
79
+ .tab-btn {
80
+ flex: 1;
81
+ padding: 12px 6px;
82
+ background: transparent;
83
+ border: none;
84
+ border-bottom: 2px solid transparent;
85
+ color: #a6adc8;
86
+ font-size: 12px;
87
+ font-weight: 600;
88
+ cursor: pointer;
89
+ transition: all 0.2s ease;
90
+ }
91
+
92
+ .tab-btn:hover {
93
+ color: #cdd6f4;
94
+ background: rgba(255, 255, 255, 0.02);
95
+ }
96
+
97
+ .tab-btn.active {
98
+ color: #cba6f7;
99
+ border-bottom-color: #cba6f7;
100
+ }
101
+
102
+ /* ---- Tab Panels Container ---- */
103
+ .tab-content-container {
104
+ flex: 1;
105
+ min-height: 0;
106
+ position: relative;
107
+ display: flex;
108
+ flex-direction: column;
109
+ }
110
+
111
+ .tab-panel {
112
+ display: none;
113
+ width: 100%;
114
+ height: 100%;
115
+ flex-direction: column;
116
+ overflow: hidden;
117
+ }
118
+
119
+ .tab-panel.active {
120
+ display: flex;
121
+ }
122
+
123
+ /* ==================== PANEL 1: MEMORIES ==================== */
124
+
61
125
  /* ---- Search ---- */
62
126
  .search-box {
63
127
  padding: 12px 16px 8px;
128
+ flex-shrink: 0;
64
129
  }
65
130
 
66
131
  .search-box input {
@@ -80,7 +145,7 @@ body {
80
145
  }
81
146
 
82
147
  .search-box input:focus {
83
- border-color: #89b4fa;
148
+ border-color: #cba6f7;
84
149
  }
85
150
 
86
151
  /* ---- Memories List ---- */
@@ -101,7 +166,7 @@ body {
101
166
  }
102
167
 
103
168
  .memory-card:hover {
104
- border-color: #89b4fa;
169
+ border-color: #cba6f7;
105
170
  transform: translateY(-1px);
106
171
  }
107
172
 
@@ -153,7 +218,7 @@ body {
153
218
 
154
219
  .memories-empty {
155
220
  text-align: center;
156
- color: #585b70;
221
+ color: #6c7086;
157
222
  font-size: 13px;
158
223
  padding: 24px 0;
159
224
  }
@@ -164,11 +229,13 @@ body {
164
229
  gap: 8px;
165
230
  padding: 12px 16px;
166
231
  border-top: 1px solid #313244;
232
+ flex-shrink: 0;
233
+ background: #11111b;
167
234
  }
168
235
 
169
236
  .action-btn {
170
237
  flex: 1;
171
- padding: 8px 6px;
238
+ padding: 10px 6px;
172
239
  font-size: 12px;
173
240
  font-weight: 600;
174
241
  background: #1e1e2e;
@@ -176,28 +243,50 @@ body {
176
243
  border: 1px solid #313244;
177
244
  border-radius: 10px;
178
245
  cursor: pointer;
179
- transition: background 0.2s ease, border-color 0.2s ease;
246
+ transition: background 0.2s ease, border-color 0.2s ease, transform 0.1s ease, opacity 0.2s ease;
180
247
  }
181
248
 
182
249
  .action-btn:hover {
183
250
  background: #313244;
184
- border-color: #89b4fa;
251
+ border-color: #cba6f7;
252
+ }
253
+
254
+ .action-btn:active {
255
+ transform: scale(0.96);
256
+ }
257
+
258
+ .action-btn:disabled, .action-btn.loading {
259
+ opacity: 0.6;
260
+ cursor: not-allowed;
261
+ transform: none !important;
185
262
  }
186
263
 
187
264
  .action-btn.accent {
188
- background: #89b4fa;
265
+ background: #cba6f7;
189
266
  color: #11111b;
190
- border-color: #89b4fa;
267
+ border-color: #cba6f7;
191
268
  }
192
269
 
193
270
  .action-btn.accent:hover {
194
- background: #74c7ec;
195
- border-color: #74c7ec;
271
+ background: #f5c2e7;
272
+ border-color: #f5c2e7;
273
+ }
274
+
275
+ .action-btn.error {
276
+ background: rgba(243, 139, 168, 0.1);
277
+ color: #f38ba8;
278
+ border-color: rgba(243, 139, 168, 0.3);
279
+ }
280
+
281
+ .action-btn.error:hover {
282
+ background: rgba(243, 139, 168, 0.2);
283
+ border-color: #f38ba8;
196
284
  }
197
285
 
198
286
  /* ---- Note Area ---- */
199
287
  .note-area {
200
288
  padding: 0 16px 12px;
289
+ flex-shrink: 0;
201
290
  }
202
291
 
203
292
  .note-area textarea {
@@ -216,7 +305,7 @@ body {
216
305
  }
217
306
 
218
307
  .note-area textarea:focus {
219
- border-color: #89b4fa;
308
+ border-color: #cba6f7;
220
309
  }
221
310
 
222
311
  .note-actions {
@@ -229,10 +318,168 @@ body {
229
318
  display: none !important;
230
319
  }
231
320
 
232
- /* ---- Research Feed ---- */
233
- .research-feed {
234
- padding: 12px 16px 16px;
321
+ /* ==================== PANEL 2: CO-PILOT CHAT ==================== */
322
+
323
+ .chat-messages {
324
+ flex: 1;
325
+ overflow-y: auto;
326
+ padding: 16px;
327
+ display: flex;
328
+ flex-direction: column;
329
+ gap: 12px;
330
+ }
331
+
332
+ .chat-bubble {
333
+ max-width: 85%;
334
+ padding: 10px 14px;
335
+ border-radius: 14px;
336
+ font-size: 13px;
337
+ line-height: 1.5;
338
+ overflow-wrap: break-word;
339
+ white-space: pre-wrap;
340
+ }
341
+
342
+ .chat-bubble.user {
343
+ align-self: flex-end;
344
+ background: #cba6f7;
345
+ color: #11111b;
346
+ border-bottom-right-radius: 4px;
347
+ font-weight: 500;
348
+ }
349
+
350
+ .chat-bubble.assistant {
351
+ align-self: flex-start;
352
+ background: #1e1e2e;
353
+ color: #cdd6f4;
354
+ border-bottom-left-radius: 4px;
355
+ border: 1px solid #313244;
356
+ }
357
+
358
+ .chat-bubble.system {
359
+ align-self: center;
360
+ background: transparent;
361
+ color: #fab387;
362
+ font-size: 11px;
363
+ font-weight: 600;
364
+ text-align: center;
365
+ max-width: 100%;
366
+ }
367
+
368
+ .chat-suggestions {
369
+ display: flex;
370
+ gap: 6px;
371
+ padding: 8px 16px;
372
+ overflow-x: auto;
373
+ flex-shrink: 0;
374
+ background: #11111b;
375
+ }
376
+
377
+ .suggestion-btn {
378
+ padding: 6px 12px;
379
+ background: #181825;
380
+ color: #a6adc8;
381
+ border: 1px solid #313244;
382
+ border-radius: 8px;
383
+ font-size: 11px;
384
+ font-weight: 500;
385
+ cursor: pointer;
386
+ white-space: nowrap;
387
+ transition: all 0.15s ease;
388
+ }
389
+
390
+ .suggestion-btn:hover {
391
+ background: #1e1e2e;
392
+ border-color: #cba6f7;
393
+ color: #cdd6f4;
394
+ }
395
+
396
+ .chat-grounding-row {
397
+ padding: 6px 16px 2px;
398
+ flex-shrink: 0;
399
+ }
400
+
401
+ .grounding-checkbox-label {
402
+ display: flex;
403
+ align-items: center;
404
+ gap: 6px;
405
+ font-size: 11px;
406
+ font-weight: 600;
407
+ color: #89b4fa;
408
+ cursor: pointer;
409
+ user-select: none;
410
+ }
411
+
412
+ .grounding-checkbox-label input {
413
+ cursor: pointer;
414
+ accent-color: #89b4fa;
415
+ }
416
+
417
+ .chat-input-bar {
418
+ display: flex;
419
+ gap: 8px;
420
+ padding: 10px 16px 14px;
421
+ background: #11111b;
235
422
  border-top: 1px solid #313244;
423
+ flex-shrink: 0;
424
+ align-items: center;
425
+ }
426
+
427
+ .chat-input-bar textarea {
428
+ flex: 1;
429
+ background: #1e1e2e;
430
+ color: #cdd6f4;
431
+ border: 1px solid #313244;
432
+ border-radius: 10px;
433
+ padding: 10px 12px;
434
+ font-size: 13px;
435
+ outline: none;
436
+ font-family: inherit;
437
+ resize: none;
438
+ height: 40px;
439
+ max-height: 40px;
440
+ transition: border-color 0.2s ease;
441
+ }
442
+
443
+ .chat-input-bar textarea:focus {
444
+ border-color: #cba6f7;
445
+ }
446
+
447
+ .chat-send-btn {
448
+ width: 40px;
449
+ height: 40px;
450
+ border-radius: 10px;
451
+ background: #cba6f7;
452
+ color: #11111b;
453
+ border: none;
454
+ cursor: pointer;
455
+ display: flex;
456
+ align-items: center;
457
+ justify-content: center;
458
+ transition: background 0.2s ease, transform 0.1s ease;
459
+ }
460
+
461
+ .chat-send-btn:hover {
462
+ background: #f5c2e7;
463
+ }
464
+
465
+ .chat-send-btn:active {
466
+ transform: scale(0.94);
467
+ }
468
+
469
+ .chat-send-btn:disabled {
470
+ background: #313244;
471
+ color: #585b70;
472
+ cursor: not-allowed;
473
+ transform: none;
474
+ }
475
+
476
+ /* ==================== PANEL 3: RESEARCH ==================== */
477
+
478
+ .research-feed {
479
+ padding: 16px;
480
+ display: flex;
481
+ flex-direction: column;
482
+ height: 100%;
236
483
  }
237
484
 
238
485
  .research-feed h3 {
@@ -240,19 +487,41 @@ body {
240
487
  font-weight: 700;
241
488
  text-transform: uppercase;
242
489
  letter-spacing: 0.8px;
243
- color: #585b70;
244
- margin-bottom: 10px;
490
+ color: #6c7086;
491
+ }
492
+
493
+ .refresh-btn {
494
+ background: transparent;
495
+ border: none;
496
+ color: #89b4fa;
497
+ font-size: 11px;
498
+ font-weight: 600;
499
+ cursor: pointer;
500
+ }
501
+
502
+ .refresh-btn:hover {
503
+ text-decoration: underline;
504
+ }
505
+
506
+ #research-list {
507
+ flex: 1;
508
+ overflow-y: auto;
245
509
  }
246
510
 
247
511
  .research-item {
248
512
  display: flex;
249
513
  align-items: center;
250
514
  gap: 8px;
251
- padding: 8px 10px;
515
+ padding: 10px 12px;
252
516
  background: #1e1e2e;
253
517
  border-radius: 10px;
254
- margin-bottom: 6px;
518
+ margin-bottom: 8px;
255
519
  border: 1px solid #313244;
520
+ transition: border-color 0.2s ease;
521
+ }
522
+
523
+ .research-item:hover {
524
+ border-color: #89b4fa;
256
525
  }
257
526
 
258
527
  .research-item .spinner {
@@ -262,6 +531,7 @@ body {
262
531
  border-top-color: #89b4fa;
263
532
  border-radius: 50%;
264
533
  animation: spin 0.8s linear infinite;
534
+ flex-shrink: 0;
265
535
  }
266
536
 
267
537
  @keyframes spin {
@@ -270,7 +540,7 @@ body {
270
540
 
271
541
  .research-item .topic {
272
542
  font-size: 12px;
273
- color: #a6adc8;
543
+ color: #cdd6f4;
274
544
  flex: 1;
275
545
  overflow: hidden;
276
546
  text-overflow: ellipsis;
@@ -278,18 +548,142 @@ body {
278
548
  }
279
549
 
280
550
  .research-item .status-badge {
281
- font-size: 10px;
551
+ font-size: 9px;
552
+ font-weight: 600;
282
553
  padding: 2px 6px;
283
554
  border-radius: 999px;
284
555
  background: rgba(137, 180, 250, 0.15);
285
556
  color: #89b4fa;
557
+ text-transform: uppercase;
558
+ flex-shrink: 0;
559
+ }
560
+
561
+ .research-item .steer-btn {
562
+ background: none;
563
+ border: none;
564
+ color: #f38ba8;
565
+ cursor: pointer;
566
+ padding: 2px;
567
+ font-size: 13px;
568
+ display: flex;
569
+ align-items: center;
570
+ justify-content: center;
571
+ flex-shrink: 0;
572
+ }
573
+
574
+ .research-item .steer-btn:hover {
575
+ color: #efa6b2;
286
576
  }
287
577
 
288
578
  .research-empty {
289
579
  font-size: 12px;
290
- color: #585b70;
580
+ color: #6c7086;
291
581
  text-align: center;
292
- padding: 8px 0;
582
+ padding: 24px 0;
583
+ }
584
+
585
+ /* ==================== PANEL 4: SETTINGS ==================== */
586
+
587
+ .settings-panel {
588
+ padding: 16px;
589
+ display: flex;
590
+ flex-direction: column;
591
+ gap: 16px;
592
+ height: 100%;
593
+ overflow-y: auto;
594
+ }
595
+
596
+ .settings-panel h3 {
597
+ font-size: 13px;
598
+ font-weight: 700;
599
+ text-transform: uppercase;
600
+ letter-spacing: 0.8px;
601
+ color: #6c7086;
602
+ border-bottom: 1px solid #313244;
603
+ padding-bottom: 8px;
604
+ margin-bottom: 4px;
605
+ }
606
+
607
+ .settings-group {
608
+ display: flex;
609
+ flex-direction: column;
610
+ gap: 6px;
611
+ }
612
+
613
+ .settings-group label {
614
+ font-size: 11px;
615
+ font-weight: 700;
616
+ text-transform: uppercase;
617
+ color: #6c7086;
618
+ letter-spacing: 0.5px;
619
+ }
620
+
621
+ .settings-select {
622
+ width: 100%;
623
+ padding: 10px 12px;
624
+ background: #1e1e2e;
625
+ border: 1px solid #313244;
626
+ border-radius: 10px;
627
+ color: #cdd6f4;
628
+ font-size: 13px;
629
+ outline: none;
630
+ cursor: pointer;
631
+ transition: border-color 0.2s ease;
632
+ }
633
+
634
+ .settings-select:focus {
635
+ border-color: #cba6f7;
636
+ }
637
+
638
+ .settings-help {
639
+ font-size: 10px;
640
+ color: #6c7086;
641
+ line-height: 1.4;
642
+ }
643
+
644
+ /* ---- Toggle / Switch ---- */
645
+ .switch {
646
+ position: relative;
647
+ display: inline-block;
648
+ width: 36px;
649
+ height: 20px;
650
+ flex-shrink: 0;
651
+ }
652
+
653
+ .switch input {
654
+ opacity: 0;
655
+ width: 0;
656
+ height: 0;
657
+ }
658
+
659
+ .slider {
660
+ position: absolute;
661
+ cursor: pointer;
662
+ inset: 0;
663
+ background: #313244;
664
+ border-radius: 20px;
665
+ transition: background 0.3s ease;
666
+ }
667
+
668
+ .slider::before {
669
+ content: '';
670
+ position: absolute;
671
+ height: 14px;
672
+ width: 14px;
673
+ left: 3px;
674
+ bottom: 3px;
675
+ background: #6c7086;
676
+ border-radius: 50%;
677
+ transition: transform 0.3s ease, background 0.3s ease;
678
+ }
679
+
680
+ .switch input:checked + .slider {
681
+ background: rgba(203, 166, 247, 0.3);
682
+ }
683
+
684
+ .switch input:checked + .slider::before {
685
+ transform: translateX(16px);
686
+ background: #cba6f7;
293
687
  }
294
688
 
295
689
  /* ---- Toast Notification ---- */
@@ -307,8 +701,10 @@ body {
307
701
  font-weight: 600;
308
702
  opacity: 0;
309
703
  transition: transform 0.3s ease, opacity 0.3s ease;
310
- z-index: 100;
704
+ z-index: 1000;
311
705
  pointer-events: none;
706
+ text-align: center;
707
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
312
708
  }
313
709
 
314
710
  .toast.show {
@@ -324,6 +720,7 @@ body {
324
720
  /* ---- Scrollbar ---- */
325
721
  ::-webkit-scrollbar {
326
722
  width: 6px;
723
+ height: 6px;
327
724
  }
328
725
 
329
726
  ::-webkit-scrollbar-track {