clay-server 2.32.0-beta.1 → 2.32.0-beta.10
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/lib/codex-defaults.js +18 -0
- package/lib/project-connection.js +5 -4
- package/lib/project-debate.js +8 -0
- package/lib/project-mate-interaction.js +102 -16
- package/lib/project-notifications.js +9 -0
- package/lib/project-sessions.js +12 -6
- package/lib/project.js +30 -9
- package/lib/public/app.js +13 -7
- package/lib/public/css/input.css +158 -5
- package/lib/public/css/notifications-center.css +7 -0
- package/lib/public/css/tooltip.css +47 -0
- package/lib/public/index.html +34 -4
- package/lib/public/modules/app-dm.js +5 -0
- package/lib/public/modules/app-messages.js +8 -5
- package/lib/public/modules/app-notifications.js +42 -20
- package/lib/public/modules/app-panels.js +3 -3
- package/lib/public/modules/app-projects.js +2 -0
- package/lib/public/modules/context-sources.js +92 -27
- package/lib/public/modules/input.js +36 -0
- package/lib/public/modules/markdown.js +5 -1
- package/lib/public/modules/sidebar-mates.js +13 -1
- package/lib/public/modules/terminal.js +12 -0
- package/lib/public/modules/tools.js +4 -4
- package/lib/public/modules/tooltip.js +32 -5
- package/lib/sdk-bridge.js +57 -7
- package/lib/sdk-message-processor.js +28 -2
- package/lib/sessions.js +35 -2
- package/lib/yoke/adapters/claude.js +65 -0
- package/lib/yoke/adapters/codex.js +161 -8
- package/lib/yoke/adapters/gemini.js +41 -0
- package/lib/yoke/interface.js +6 -0
- package/package.json +1 -1
package/lib/public/css/input.css
CHANGED
|
@@ -746,12 +746,14 @@
|
|
|
746
746
|
display: flex;
|
|
747
747
|
align-items: center;
|
|
748
748
|
justify-content: space-between;
|
|
749
|
+
gap: 4px;
|
|
749
750
|
}
|
|
750
751
|
|
|
751
752
|
#input-bottom-right {
|
|
752
753
|
display: flex;
|
|
753
754
|
align-items: center;
|
|
754
755
|
gap: 4px;
|
|
756
|
+
flex-shrink: 0;
|
|
755
757
|
}
|
|
756
758
|
|
|
757
759
|
/* --- Vendor toggle (split toggle) --- */
|
|
@@ -812,22 +814,31 @@
|
|
|
812
814
|
.vendor-toggle-label {
|
|
813
815
|
pointer-events: none;
|
|
814
816
|
}
|
|
815
|
-
@media (max-width:
|
|
817
|
+
@media (max-width: 900px) {
|
|
816
818
|
.vendor-toggle-label { display: none; }
|
|
819
|
+
.vendor-toggle-btn { padding: 0 8px; }
|
|
817
820
|
}
|
|
818
821
|
|
|
819
822
|
/* --- Attach buttons & menu --- */
|
|
820
823
|
#attach-wrap {
|
|
821
824
|
position: relative;
|
|
822
|
-
|
|
825
|
+
min-width: 0;
|
|
823
826
|
display: flex;
|
|
824
827
|
align-items: center;
|
|
825
828
|
gap: 2px;
|
|
829
|
+
flex-wrap: nowrap;
|
|
830
|
+
overflow: hidden;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/* Allow popovers (context picker) to escape when open */
|
|
834
|
+
#attach-wrap:has(#context-sources-picker:not(.hidden)) {
|
|
835
|
+
overflow: visible;
|
|
826
836
|
}
|
|
827
837
|
|
|
828
838
|
#attach-file-btn,
|
|
829
839
|
#attach-image-btn,
|
|
830
|
-
#schedule-btn
|
|
840
|
+
#schedule-btn,
|
|
841
|
+
#input-more-btn {
|
|
831
842
|
width: 36px;
|
|
832
843
|
height: 36px;
|
|
833
844
|
border-radius: 50%;
|
|
@@ -844,11 +855,13 @@
|
|
|
844
855
|
|
|
845
856
|
#attach-file-btn .lucide,
|
|
846
857
|
#attach-image-btn .lucide,
|
|
847
|
-
#schedule-btn .lucide
|
|
858
|
+
#schedule-btn .lucide,
|
|
859
|
+
#input-more-btn .lucide { width: 20px; height: 20px; flex-shrink: 0; }
|
|
848
860
|
|
|
849
861
|
#attach-file-btn:hover,
|
|
850
862
|
#attach-image-btn:hover,
|
|
851
|
-
#schedule-btn:hover
|
|
863
|
+
#schedule-btn:hover,
|
|
864
|
+
#input-more-btn:hover { background: rgba(var(--overlay-rgb), 0.06); color: var(--text); }
|
|
852
865
|
|
|
853
866
|
#ask-mate-btn {
|
|
854
867
|
width: 36px;
|
|
@@ -1137,6 +1150,146 @@
|
|
|
1137
1150
|
body.keyboard-open #input-area {
|
|
1138
1151
|
padding-bottom: 8px;
|
|
1139
1152
|
}
|
|
1153
|
+
|
|
1154
|
+
/* Mobile visibility utilities for input toolbar */
|
|
1155
|
+
.desktop-only { display: none !important; }
|
|
1156
|
+
.mobile-only { display: inline-flex !important; }
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/* Desktop: hide mobile-only, show desktop-only */
|
|
1160
|
+
@media (min-width: 769px) {
|
|
1161
|
+
.mobile-only { display: none !important; }
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
/* ==========================================================================
|
|
1165
|
+
Input More Bottom Sheet (mobile)
|
|
1166
|
+
========================================================================== */
|
|
1167
|
+
|
|
1168
|
+
#input-more-sheet {
|
|
1169
|
+
position: fixed;
|
|
1170
|
+
inset: 0;
|
|
1171
|
+
z-index: 10000;
|
|
1172
|
+
pointer-events: none;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
#input-more-sheet.hidden {
|
|
1176
|
+
display: none;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
.input-more-backdrop {
|
|
1180
|
+
position: absolute;
|
|
1181
|
+
inset: 0;
|
|
1182
|
+
background: rgba(0, 0, 0, 0.4);
|
|
1183
|
+
opacity: 0;
|
|
1184
|
+
transition: opacity 0.2s ease;
|
|
1185
|
+
pointer-events: auto;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
#input-more-sheet.open .input-more-backdrop {
|
|
1189
|
+
opacity: 1;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
.input-more-content {
|
|
1193
|
+
position: absolute;
|
|
1194
|
+
left: 0;
|
|
1195
|
+
right: 0;
|
|
1196
|
+
bottom: 0;
|
|
1197
|
+
background: var(--bg);
|
|
1198
|
+
border-top-left-radius: 16px;
|
|
1199
|
+
border-top-right-radius: 16px;
|
|
1200
|
+
padding: 8px 0 calc(var(--safe-bottom) + 16px);
|
|
1201
|
+
transform: translateY(100%);
|
|
1202
|
+
transition: transform 0.25s ease;
|
|
1203
|
+
pointer-events: auto;
|
|
1204
|
+
box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.15);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
#input-more-sheet.open .input-more-content {
|
|
1208
|
+
transform: translateY(0);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
.input-more-handle {
|
|
1212
|
+
width: 40px;
|
|
1213
|
+
height: 4px;
|
|
1214
|
+
border-radius: 2px;
|
|
1215
|
+
background: var(--border-subtle);
|
|
1216
|
+
margin: 8px auto 12px;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.input-more-actions {
|
|
1220
|
+
display: grid;
|
|
1221
|
+
grid-template-columns: 1fr 1fr;
|
|
1222
|
+
gap: 8px;
|
|
1223
|
+
padding: 4px 16px 12px;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
.input-more-action {
|
|
1227
|
+
display: flex;
|
|
1228
|
+
flex-direction: column;
|
|
1229
|
+
align-items: center;
|
|
1230
|
+
justify-content: center;
|
|
1231
|
+
gap: 6px;
|
|
1232
|
+
padding: 16px 8px;
|
|
1233
|
+
background: var(--hover);
|
|
1234
|
+
border: 1px solid var(--border-subtle);
|
|
1235
|
+
border-radius: 10px;
|
|
1236
|
+
font-size: 13px;
|
|
1237
|
+
color: var(--text);
|
|
1238
|
+
cursor: pointer;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
.input-more-action:active {
|
|
1242
|
+
opacity: 0.7;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
.input-more-action .lucide {
|
|
1246
|
+
width: 22px;
|
|
1247
|
+
height: 22px;
|
|
1248
|
+
color: var(--text-secondary);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.input-more-divider {
|
|
1252
|
+
height: 1px;
|
|
1253
|
+
background: var(--border-subtle);
|
|
1254
|
+
margin: 0 16px;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
.input-more-section-label {
|
|
1258
|
+
display: flex;
|
|
1259
|
+
align-items: center;
|
|
1260
|
+
gap: 8px;
|
|
1261
|
+
padding: 14px 20px 6px;
|
|
1262
|
+
font-size: 13px;
|
|
1263
|
+
font-weight: 500;
|
|
1264
|
+
color: var(--text-secondary);
|
|
1265
|
+
text-transform: uppercase;
|
|
1266
|
+
letter-spacing: 0.04em;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.input-more-section-label .lucide {
|
|
1270
|
+
width: 16px;
|
|
1271
|
+
height: 16px;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
.input-more-context-body {
|
|
1275
|
+
max-height: 50vh;
|
|
1276
|
+
overflow-y: auto;
|
|
1277
|
+
padding: 0 8px 8px;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
.input-more-context-body .context-picker-item {
|
|
1281
|
+
padding: 12px 16px;
|
|
1282
|
+
font-size: 15px;
|
|
1283
|
+
border-radius: 8px;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
.input-more-context-body .context-picker-item .lucide {
|
|
1287
|
+
width: 18px;
|
|
1288
|
+
height: 18px;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
.input-more-context-body .context-picker-section-label {
|
|
1292
|
+
padding: 10px 16px 4px;
|
|
1140
1293
|
}
|
|
1141
1294
|
|
|
1142
1295
|
/* ==========================================================================
|
|
@@ -81,6 +81,13 @@
|
|
|
81
81
|
}
|
|
82
82
|
.notif-banner-icon .lucide { width: 16px; height: 16px; }
|
|
83
83
|
.notif-banner-emoji { font-size: 18px; line-height: 1; }
|
|
84
|
+
.notif-banner-avatar {
|
|
85
|
+
width: 100%;
|
|
86
|
+
height: 100%;
|
|
87
|
+
object-fit: cover;
|
|
88
|
+
border-radius: 8px;
|
|
89
|
+
display: block;
|
|
90
|
+
}
|
|
84
91
|
|
|
85
92
|
.notif-banner-body {
|
|
86
93
|
flex: 1;
|
|
@@ -18,3 +18,50 @@
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.tooltip.visible { opacity: 1; }
|
|
21
|
+
|
|
22
|
+
.tooltip.multi-line {
|
|
23
|
+
white-space: pre-line;
|
|
24
|
+
text-align: left;
|
|
25
|
+
max-width: 320px;
|
|
26
|
+
line-height: 1.5;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Context sources tooltip */
|
|
30
|
+
.ctx-tip-header {
|
|
31
|
+
font-size: 11px;
|
|
32
|
+
font-weight: 600;
|
|
33
|
+
text-transform: uppercase;
|
|
34
|
+
letter-spacing: 0.04em;
|
|
35
|
+
color: var(--text-muted);
|
|
36
|
+
margin-bottom: 6px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.ctx-tip-row {
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
gap: 8px;
|
|
43
|
+
padding: 4px 0;
|
|
44
|
+
color: var(--text);
|
|
45
|
+
font-size: 12px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.ctx-tip-row .lucide {
|
|
49
|
+
width: 14px;
|
|
50
|
+
height: 14px;
|
|
51
|
+
flex-shrink: 0;
|
|
52
|
+
color: var(--text-secondary);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.ctx-tip-favicon {
|
|
56
|
+
width: 14px;
|
|
57
|
+
height: 14px;
|
|
58
|
+
flex-shrink: 0;
|
|
59
|
+
border-radius: 2px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.ctx-tip-row span {
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
text-overflow: ellipsis;
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
max-width: 260px;
|
|
67
|
+
}
|
package/lib/public/index.html
CHANGED
|
@@ -352,6 +352,7 @@
|
|
|
352
352
|
<div class="status">
|
|
353
353
|
<button id="debate-pdf-btn" class="hidden" title="Export debate as PDF"><i data-lucide="download"></i></button>
|
|
354
354
|
<button id="find-in-session-btn" title="Search in session (Ctrl+F)"><i data-lucide="search"></i></button>
|
|
355
|
+
<button id="terminal-toggle-btn" title="Terminal"><i data-lucide="square-terminal"></i><span id="terminal-count" class="hidden"></span></button>
|
|
355
356
|
</div>
|
|
356
357
|
</div>
|
|
357
358
|
<div id="main-panels">
|
|
@@ -459,13 +460,14 @@
|
|
|
459
460
|
</div>
|
|
460
461
|
<div id="input-bottom">
|
|
461
462
|
<div id="attach-wrap">
|
|
462
|
-
<button id="
|
|
463
|
-
<button id="attach-
|
|
463
|
+
<button id="input-more-btn" type="button" aria-label="More options" title="More options" class="mobile-only"><i data-lucide="plus"></i></button>
|
|
464
|
+
<button id="attach-file-btn" type="button" aria-label="Attach file" title="Attach file" class="desktop-only"><i data-lucide="paperclip"></i></button>
|
|
465
|
+
<button id="attach-image-btn" type="button" aria-label="Attach image" title="Attach image" class="desktop-only"><i data-lucide="image"></i></button>
|
|
464
466
|
<button id="stt-btn" type="button" aria-label="Voice input" title="Voice input"><i data-lucide="mic"></i></button>
|
|
465
467
|
<button id="schedule-btn" type="button" aria-label="Schedule message" title="Schedule message"><i data-lucide="clock"></i></button>
|
|
466
468
|
<button id="ask-mate-btn" type="button" aria-label="Ask Mate" title="Ask a Mate for advice on this session"><i data-lucide="at-sign"></i></button>
|
|
467
|
-
<div id="context-sources-btn-wrap">
|
|
468
|
-
<button id="context-sources-add" type="button" title="Add context sources"><i data-lucide="
|
|
469
|
+
<div id="context-sources-btn-wrap" class="desktop-only">
|
|
470
|
+
<button id="context-sources-add" type="button" title="Add context sources"><i data-lucide="library"></i><span class="ctx-label">Context</span></button>
|
|
469
471
|
<div id="context-sources-picker" class="hidden">
|
|
470
472
|
<div class="context-picker-section" id="context-picker-email"></div>
|
|
471
473
|
<div class="context-picker-section" id="context-picker-terminals"></div>
|
|
@@ -542,6 +544,34 @@
|
|
|
542
544
|
</div>
|
|
543
545
|
</div>
|
|
544
546
|
</div>
|
|
547
|
+
<!-- Mobile input-more bottom sheet: attach / image + context sources -->
|
|
548
|
+
<div id="input-more-sheet" class="hidden">
|
|
549
|
+
<div class="input-more-backdrop"></div>
|
|
550
|
+
<div class="input-more-content">
|
|
551
|
+
<div class="input-more-handle"></div>
|
|
552
|
+
<div class="input-more-actions">
|
|
553
|
+
<button class="input-more-action" id="input-more-attach">
|
|
554
|
+
<i data-lucide="paperclip"></i>
|
|
555
|
+
<span>Attach file</span>
|
|
556
|
+
</button>
|
|
557
|
+
<button class="input-more-action" id="input-more-image">
|
|
558
|
+
<i data-lucide="image"></i>
|
|
559
|
+
<span>Image</span>
|
|
560
|
+
</button>
|
|
561
|
+
</div>
|
|
562
|
+
<div class="input-more-divider"></div>
|
|
563
|
+
<div class="input-more-section-label">
|
|
564
|
+
<i data-lucide="library"></i>
|
|
565
|
+
<span>Context sources</span>
|
|
566
|
+
</div>
|
|
567
|
+
<div class="input-more-context-body" id="input-more-context-body">
|
|
568
|
+
<div class="context-picker-section" id="context-picker-email-mobile"></div>
|
|
569
|
+
<div class="context-picker-section" id="context-picker-terminals-mobile"></div>
|
|
570
|
+
<div class="context-picker-section" id="context-picker-tabs-mobile"></div>
|
|
571
|
+
</div>
|
|
572
|
+
</div>
|
|
573
|
+
</div>
|
|
574
|
+
|
|
545
575
|
<!-- Mobile fullscreen sheet overlay (Projects / Sessions) -->
|
|
546
576
|
<div id="mobile-sheet" class="hidden">
|
|
547
577
|
<div class="mobile-sheet-backdrop"></div>
|
|
@@ -210,6 +210,8 @@ export function enterDmMode(key, targetUser, messages) {
|
|
|
210
210
|
// Close file viewer and terminal panel BEFORE switching WS (needs old WS still open)
|
|
211
211
|
try { closeFileViewer(); } catch(e) {}
|
|
212
212
|
closeTerminal();
|
|
213
|
+
var termBtn = document.getElementById("terminal-toggle-btn");
|
|
214
|
+
if (termBtn) termBtn.style.display = "none";
|
|
213
215
|
// Apply mate color to chat title bar and panels
|
|
214
216
|
var mateColor = (targetUser.profile && targetUser.profile.avatarColor) || targetUser.avatarColor || "#7c3aed";
|
|
215
217
|
document.body.style.setProperty("--mate-color", mateColor);
|
|
@@ -323,6 +325,9 @@ export function exitDmMode(skipProjectSwitch) {
|
|
|
323
325
|
hideKnowledge();
|
|
324
326
|
hideMemory();
|
|
325
327
|
if (isSchedulerOpen()) closeScheduler();
|
|
328
|
+
// Restore terminal button
|
|
329
|
+
var termBtn = document.getElementById("terminal-toggle-btn");
|
|
330
|
+
if (termBtn) termBtn.style.display = "";
|
|
326
331
|
// Reset DM header
|
|
327
332
|
var dmHeaderBar = document.getElementById("dm-header-bar");
|
|
328
333
|
if (dmHeaderBar) {
|
|
@@ -11,7 +11,7 @@ import { refreshIcons, iconHtml } from './icons.js';
|
|
|
11
11
|
import { renderMarkdown } from './markdown.js';
|
|
12
12
|
import { updatePageTitle } from './sidebar.js';
|
|
13
13
|
import { renderSessionList, updateSessionPresence, populateCliSessionList, handleSearchResults, updateSessionBadge } from './sidebar-sessions.js';
|
|
14
|
-
import { updateDmBadge, renderSidebarPresence } from './sidebar-mates.js';
|
|
14
|
+
import { updateDmBadge, renderSidebarPresence, setMentionActive, renderUserStrip } from './sidebar-mates.js';
|
|
15
15
|
import { refreshMobileChatSheet } from './sidebar-mobile.js';
|
|
16
16
|
import { renderMateSessionList, handleMateSearchResults, updateMateSidebarProfile } from './mate-sidebar.js';
|
|
17
17
|
import { renderKnowledgeList, handleKnowledgeContent } from './mate-knowledge.js';
|
|
@@ -38,7 +38,7 @@ import { handleLoopRegistryUpdated, handleScheduleRunStarted, handleScheduleRunF
|
|
|
38
38
|
|
|
39
39
|
// --- App module imports ---
|
|
40
40
|
import { scrollToBottom, addToMessages, addUserMessage, addSystemMessage, removeMatePreThinking, appendDelta, finalizeAssistantBlock, addConflictMessage, addContextOverflowMessage, addAuthRequiredMessage, showSuggestionChips } from './app-rendering.js';
|
|
41
|
-
import { setActivity, startUrgentBlink, stopUrgentBlink, blinkSessionDot } from './app-favicon.js';
|
|
41
|
+
import { setActivity, startUrgentBlink, stopUrgentBlink, blinkSessionDot, updateCrossProjectBlink } from './app-favicon.js';
|
|
42
42
|
import { setStatus } from './app-connection.js';
|
|
43
43
|
import { getModelEffortLevels, accumulateUsage, updateUsagePanel, accumulateContext, updateContextPanel, renderCtxPopover, updateStatusPanel } from './app-panels.js';
|
|
44
44
|
import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, handleBrowseDirResult, handleAddProjectResult, handleCloneProgress } from './app-projects.js';
|
|
@@ -369,9 +369,9 @@ export function processMessage(msg) {
|
|
|
369
369
|
|
|
370
370
|
case "codex_config":
|
|
371
371
|
store.set({
|
|
372
|
-
codexApproval: msg.approval
|
|
373
|
-
codexSandbox: msg.sandbox
|
|
374
|
-
codexWebSearch: msg.webSearch
|
|
372
|
+
codexApproval: msg.approval,
|
|
373
|
+
codexSandbox: msg.sandbox,
|
|
374
|
+
codexWebSearch: msg.webSearch,
|
|
375
375
|
});
|
|
376
376
|
break;
|
|
377
377
|
|
|
@@ -1171,6 +1171,7 @@ export function processMessage(msg) {
|
|
|
1171
1171
|
|
|
1172
1172
|
case "projects_updated":
|
|
1173
1173
|
updateProjectList(msg);
|
|
1174
|
+
renderUserStrip();
|
|
1174
1175
|
break;
|
|
1175
1176
|
|
|
1176
1177
|
case "project_owner_changed":
|
|
@@ -1324,6 +1325,7 @@ export function processMessage(msg) {
|
|
|
1324
1325
|
case "mention_processing":
|
|
1325
1326
|
// Broadcast: show/hide activity dot on mate avatar across all tabs
|
|
1326
1327
|
if (msg.mateId) {
|
|
1328
|
+
setMentionActive(msg.mateId, msg.active);
|
|
1327
1329
|
var mateContainers = document.querySelectorAll('.icon-strip-mate[data-user-id="' + msg.mateId + '"]');
|
|
1328
1330
|
for (var mi = 0; mi < mateContainers.length; mi++) {
|
|
1329
1331
|
var dot = mateContainers[mi].querySelector(".icon-strip-status");
|
|
@@ -1335,6 +1337,7 @@ export function processMessage(msg) {
|
|
|
1335
1337
|
mateContainers[mi].classList.remove("mention-active");
|
|
1336
1338
|
}
|
|
1337
1339
|
}
|
|
1340
|
+
updateCrossProjectBlink();
|
|
1338
1341
|
}
|
|
1339
1342
|
break;
|
|
1340
1343
|
|
|
@@ -9,6 +9,7 @@ import { getWs } from './ws-ref.js';
|
|
|
9
9
|
import { openDm } from './app-dm.js';
|
|
10
10
|
import { getCachedProjects } from './app-projects.js';
|
|
11
11
|
import { switchProject } from './app-projects.js';
|
|
12
|
+
import { mateAvatarUrl } from './avatar.js';
|
|
12
13
|
var notifications = [];
|
|
13
14
|
var unreadCount = 0;
|
|
14
15
|
var bannerContainer = null;
|
|
@@ -16,9 +17,10 @@ var bellBtn = null;
|
|
|
16
17
|
var badgeEl = null;
|
|
17
18
|
|
|
18
19
|
// --- Update available banner state ---
|
|
20
|
+
// Server pushes update_available on an hourly boundary; dismissal is
|
|
21
|
+
// per-banner-instance and doesn't need to persist. The next server push
|
|
22
|
+
// (next hour) acts as a fresh ping.
|
|
19
23
|
var pendingUpdateMsg = null;
|
|
20
|
-
var updateReshowTimer = null;
|
|
21
|
-
var UPDATE_RESHOW_INTERVAL = 60 * 60 * 1000; // 1 hour
|
|
22
24
|
|
|
23
25
|
// ========================================================
|
|
24
26
|
// Init
|
|
@@ -49,10 +51,12 @@ function showAllBanners() {
|
|
|
49
51
|
// Clear existing banners first
|
|
50
52
|
if (bannerContainer) bannerContainer.innerHTML = "";
|
|
51
53
|
|
|
52
|
-
// Re-add update banner if present
|
|
54
|
+
// Re-add update banner if present (may be suppressed by recent dismiss)
|
|
53
55
|
if (pendingUpdateMsg) showUpdateBanner(pendingUpdateMsg);
|
|
54
56
|
|
|
55
|
-
if (
|
|
57
|
+
// Check if any banner actually got rendered (update banner can be suppressed)
|
|
58
|
+
var hasVisibleBanner = bannerContainer.children.length > 0;
|
|
59
|
+
if (notifications.length === 0 && !hasVisibleBanner) {
|
|
56
60
|
showBanner({
|
|
57
61
|
id: "_empty",
|
|
58
62
|
type: "info",
|
|
@@ -79,14 +83,17 @@ function showBanner(notif, autoDismissMs) {
|
|
|
79
83
|
var projectIcon = isEmpty ? null : getProjectIcon(notif.slug);
|
|
80
84
|
var projectName = isEmpty ? "" : getProjectName(notif.slug);
|
|
81
85
|
var isPermission = notif.type === "permission_request" && notif.meta && notif.meta.requestId;
|
|
86
|
+
var mate = isEmpty ? null : getMateForNotification(notif);
|
|
82
87
|
|
|
83
88
|
var banner = document.createElement("div");
|
|
84
89
|
banner.className = "notif-banner" + (isPermission ? " notif-banner-permission" : "");
|
|
85
90
|
if (!isEmpty) banner.setAttribute("data-notif-id", notif.id);
|
|
86
91
|
|
|
87
|
-
var iconHtmlStr =
|
|
88
|
-
? '<
|
|
89
|
-
:
|
|
92
|
+
var iconHtmlStr = mate
|
|
93
|
+
? '<img class="notif-banner-avatar" src="' + escapeHtml(mateAvatarUrl(mate, 32)) + '" alt="' + escapeHtml(mate.displayName || mate.name || "Mate") + '">'
|
|
94
|
+
: projectIcon
|
|
95
|
+
? '<span class="notif-banner-emoji">' + projectIcon + '</span>'
|
|
96
|
+
: iconHtml(isEmpty ? "check-circle" : "folder");
|
|
90
97
|
|
|
91
98
|
// Format permission title as "Can I ..." style
|
|
92
99
|
if (isPermission && notif.meta) {
|
|
@@ -101,7 +108,7 @@ function showBanner(notif, autoDismissMs) {
|
|
|
101
108
|
actionsHtml =
|
|
102
109
|
'<div class="notif-banner-actions">' +
|
|
103
110
|
'<button class="notif-banner-allow">Sure</button>' +
|
|
104
|
-
'<button class="notif-banner-always">
|
|
111
|
+
'<button class="notif-banner-always">Allow for session</button>' +
|
|
105
112
|
'<button class="notif-banner-deny">No</button>' +
|
|
106
113
|
'<button class="notif-banner-goto" title="Go to session">' + iconHtml("external-link") + '</button>' +
|
|
107
114
|
'</div>';
|
|
@@ -300,8 +307,12 @@ function updateBadge() {
|
|
|
300
307
|
// ========================================================
|
|
301
308
|
|
|
302
309
|
function navigateToNotification(notif) {
|
|
303
|
-
|
|
304
|
-
|
|
310
|
+
var mateId = notif.mateId || deriveMateIdFromNotification(notif);
|
|
311
|
+
if (mateId) {
|
|
312
|
+
if (notif.sessionId) {
|
|
313
|
+
try { sessionStorage.setItem("pending-notif-session", notif.sessionId); } catch (e) {}
|
|
314
|
+
}
|
|
315
|
+
openDm(mateId);
|
|
305
316
|
return;
|
|
306
317
|
}
|
|
307
318
|
|
|
@@ -322,6 +333,25 @@ function navigateToNotification(notif) {
|
|
|
322
333
|
}
|
|
323
334
|
}
|
|
324
335
|
|
|
336
|
+
function deriveMateIdFromNotification(notif) {
|
|
337
|
+
if (!notif) return null;
|
|
338
|
+
if (typeof notif.slug === "string" && notif.slug.indexOf("mate-") === 0) {
|
|
339
|
+
return notif.slug.substring(5) || null;
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function getMateForNotification(notif) {
|
|
345
|
+
var mateId = notif && notif.meta ? notif.meta.avatarMateId : null;
|
|
346
|
+
if (!mateId) mateId = deriveMateIdFromNotification(notif);
|
|
347
|
+
if (!mateId) return null;
|
|
348
|
+
var mates = store.get('cachedMatesList') || [];
|
|
349
|
+
for (var i = 0; i < mates.length; i++) {
|
|
350
|
+
if (mates[i] && mates[i].id === mateId) return mates[i];
|
|
351
|
+
}
|
|
352
|
+
return { id: mateId };
|
|
353
|
+
}
|
|
354
|
+
|
|
325
355
|
// ========================================================
|
|
326
356
|
// Update available banner
|
|
327
357
|
// ========================================================
|
|
@@ -383,25 +413,17 @@ export function showUpdateBanner(msg) {
|
|
|
383
413
|
});
|
|
384
414
|
}
|
|
385
415
|
|
|
386
|
-
// Close button -> dismiss
|
|
416
|
+
// Close button -> dismiss. No local throttle; the server pushes a new
|
|
417
|
+
// update_available on the next hour boundary, which re-shows naturally.
|
|
387
418
|
var closeBtn = banner.querySelector(".notif-banner-close");
|
|
388
419
|
if (closeBtn) {
|
|
389
420
|
closeBtn.addEventListener("click", function (e) {
|
|
390
421
|
e.stopPropagation();
|
|
391
422
|
removeBanner(banner);
|
|
392
|
-
scheduleUpdateReshow();
|
|
393
423
|
});
|
|
394
424
|
}
|
|
395
425
|
}
|
|
396
426
|
|
|
397
|
-
function scheduleUpdateReshow() {
|
|
398
|
-
if (updateReshowTimer) clearTimeout(updateReshowTimer);
|
|
399
|
-
updateReshowTimer = setTimeout(function () {
|
|
400
|
-
updateReshowTimer = null;
|
|
401
|
-
if (pendingUpdateMsg) showUpdateBanner(pendingUpdateMsg);
|
|
402
|
-
}, UPDATE_RESHOW_INTERVAL);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
427
|
// ========================================================
|
|
406
428
|
// Helpers
|
|
407
429
|
// ========================================================
|
|
@@ -335,15 +335,15 @@ function rebuildCodexSections() {
|
|
|
335
335
|
|
|
336
336
|
if (configApprovalSection) {
|
|
337
337
|
configApprovalSection.style.display = isCodex ? "" : "none";
|
|
338
|
-
if (isCodex) buildSegmentedBar(configApprovalBar, CODEX_APPROVAL_OPTIONS, s.codexApproval
|
|
338
|
+
if (isCodex) buildSegmentedBar(configApprovalBar, CODEX_APPROVAL_OPTIONS, s.codexApproval, "set_codex_approval", "approval");
|
|
339
339
|
}
|
|
340
340
|
if (configSandboxSection) {
|
|
341
341
|
configSandboxSection.style.display = isCodex ? "" : "none";
|
|
342
|
-
if (isCodex) buildSegmentedBar(configSandboxBar, CODEX_SANDBOX_OPTIONS, s.codexSandbox
|
|
342
|
+
if (isCodex) buildSegmentedBar(configSandboxBar, CODEX_SANDBOX_OPTIONS, s.codexSandbox, "set_codex_sandbox", "sandbox");
|
|
343
343
|
}
|
|
344
344
|
if (configWebsearchSection) {
|
|
345
345
|
configWebsearchSection.style.display = isCodex ? "" : "none";
|
|
346
|
-
if (isCodex) buildSegmentedBar(configWebsearchBar, CODEX_WEBSEARCH_OPTIONS, s.codexWebSearch
|
|
346
|
+
if (isCodex) buildSegmentedBar(configWebsearchBar, CODEX_WEBSEARCH_OPTIONS, s.codexWebSearch, "set_codex_websearch", "webSearch");
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
349
|
|
|
@@ -24,6 +24,7 @@ import { connect, cancelReconnect, setStatus } from './app-connection.js';
|
|
|
24
24
|
import { setTurnCounter, setPrependAnchor, setActivityEl, setIsUserScrolledUp, hideSuggestionChips } from './app-rendering.js';
|
|
25
25
|
import { resetToolState, enableMainInput, resetTurnMetaCost } from './tools.js';
|
|
26
26
|
import { clearPendingImages } from './input.js';
|
|
27
|
+
import { clearAllMentionActive } from './sidebar-mates.js';
|
|
27
28
|
import { setRewindMode } from './rewind.js';
|
|
28
29
|
import { resetUsage, resetContext } from './app-panels.js';
|
|
29
30
|
import { resetRateLimitState } from './app-rate-limit.js';
|
|
@@ -366,6 +367,7 @@ export function resetClientState() {
|
|
|
366
367
|
store.set({ currentFullText: "" });
|
|
367
368
|
resetToolState();
|
|
368
369
|
clearPendingImages();
|
|
370
|
+
clearAllMentionActive();
|
|
369
371
|
setActivityEl(null);
|
|
370
372
|
store.set({ processing: false });
|
|
371
373
|
setTurnCounter(0);
|