clay-server 2.31.0 → 2.32.0-beta.2

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 (74) hide show
  1. package/lib/browser-mcp-server.js +32 -44
  2. package/lib/debate-mcp-server.js +14 -31
  3. package/lib/mcp-local.js +31 -1
  4. package/lib/project-connection.js +4 -2
  5. package/lib/project-filesystem.js +47 -1
  6. package/lib/project-http.js +75 -8
  7. package/lib/project-mcp.js +4 -0
  8. package/lib/project-sessions.js +88 -51
  9. package/lib/project-user-message.js +12 -7
  10. package/lib/project.js +204 -90
  11. package/lib/public/app.js +123 -448
  12. package/lib/public/codex-avatar.png +0 -0
  13. package/lib/public/css/debate.css +3 -2
  14. package/lib/public/css/filebrowser.css +91 -1
  15. package/lib/public/css/icon-strip.css +21 -5
  16. package/lib/public/css/input.css +181 -100
  17. package/lib/public/css/mates.css +43 -0
  18. package/lib/public/css/mention.css +48 -4
  19. package/lib/public/css/menus.css +1 -1
  20. package/lib/public/css/messages.css +2 -0
  21. package/lib/public/css/notifications-center.css +19 -0
  22. package/lib/public/index.html +46 -24
  23. package/lib/public/modules/app-connection.js +138 -37
  24. package/lib/public/modules/app-cursors.js +18 -17
  25. package/lib/public/modules/app-debate-ui.js +9 -9
  26. package/lib/public/modules/app-dm.js +170 -131
  27. package/lib/public/modules/app-favicon.js +28 -26
  28. package/lib/public/modules/app-header.js +79 -68
  29. package/lib/public/modules/app-home-hub.js +55 -47
  30. package/lib/public/modules/app-loop-ui.js +34 -18
  31. package/lib/public/modules/app-loop-wizard.js +6 -6
  32. package/lib/public/modules/app-messages.js +195 -152
  33. package/lib/public/modules/app-misc.js +23 -12
  34. package/lib/public/modules/app-notifications.js +97 -3
  35. package/lib/public/modules/app-panels.js +203 -49
  36. package/lib/public/modules/app-projects.js +159 -150
  37. package/lib/public/modules/app-rate-limit.js +5 -4
  38. package/lib/public/modules/app-rendering.js +149 -101
  39. package/lib/public/modules/app-skills-install.js +4 -4
  40. package/lib/public/modules/context-sources.js +12 -41
  41. package/lib/public/modules/dom-refs.js +21 -0
  42. package/lib/public/modules/filebrowser.js +173 -2
  43. package/lib/public/modules/input.js +86 -0
  44. package/lib/public/modules/mate-sidebar.js +38 -0
  45. package/lib/public/modules/mention.js +24 -6
  46. package/lib/public/modules/scheduler.js +1 -1
  47. package/lib/public/modules/sidebar-mates.js +66 -34
  48. package/lib/public/modules/sidebar-mobile.js +34 -30
  49. package/lib/public/modules/sidebar-projects.js +60 -57
  50. package/lib/public/modules/sidebar-sessions.js +75 -69
  51. package/lib/public/modules/sidebar.js +12 -20
  52. package/lib/public/modules/skills.js +8 -9
  53. package/lib/public/modules/sticky-notes.js +1 -2
  54. package/lib/public/modules/store.js +9 -2
  55. package/lib/public/modules/stt.js +4 -1
  56. package/lib/public/modules/tools.js +14 -9
  57. package/lib/sdk-bridge.js +511 -1113
  58. package/lib/sdk-message-processor.js +123 -134
  59. package/lib/sdk-worker.js +4 -0
  60. package/lib/server-dm.js +1 -0
  61. package/lib/server.js +86 -1
  62. package/lib/sessions.js +47 -36
  63. package/lib/ws-schema.js +2 -0
  64. package/lib/yoke/adapters/claude-worker.js +559 -0
  65. package/lib/yoke/adapters/claude.js +1418 -0
  66. package/lib/yoke/adapters/codex.js +968 -0
  67. package/lib/yoke/adapters/gemini.js +668 -0
  68. package/lib/yoke/codex-app-server.js +307 -0
  69. package/lib/yoke/index.js +199 -0
  70. package/lib/yoke/instructions.js +62 -0
  71. package/lib/yoke/interface.js +92 -0
  72. package/lib/yoke/mcp-bridge-server.js +294 -0
  73. package/lib/yoke/package.json +7 -0
  74. package/package.json +3 -1
@@ -179,6 +179,35 @@ export function initFileBrowser(_ctx) {
179
179
  closeFileViewer();
180
180
  }
181
181
  });
182
+
183
+ // --- File search ---
184
+ var fbSearchInput = document.getElementById("fb-search-input");
185
+ var searchDebounce = null;
186
+
187
+ if (fbSearchInput) {
188
+ fbSearchInput.addEventListener("input", function () {
189
+ var q = fbSearchInput.value.trim();
190
+ if (searchDebounce) clearTimeout(searchDebounce);
191
+ if (!q) {
192
+ renderTree();
193
+ restoreExpanded({});
194
+ return;
195
+ }
196
+ searchDebounce = setTimeout(function () {
197
+ if (ctx.ws && ctx.connected) {
198
+ ctx.ws.send(JSON.stringify({ type: "fs_search", query: q }));
199
+ }
200
+ }, 200);
201
+ });
202
+ fbSearchInput.addEventListener("keydown", function (e) {
203
+ if (e.key === "Escape" && fbSearchInput.value) {
204
+ e.stopPropagation();
205
+ fbSearchInput.value = "";
206
+ renderTree();
207
+ restoreExpanded({});
208
+ }
209
+ });
210
+ }
182
211
  }
183
212
 
184
213
  // --- File watch helpers ---
@@ -232,10 +261,8 @@ export function resetFileBrowser() {
232
261
  // Hide the file browser panel, show sessions panel
233
262
  var filesPanel = document.getElementById("sidebar-panel-files");
234
263
  var sessionsPanel = document.getElementById("sidebar-panel-sessions");
235
- var filesHeaderContent = document.getElementById("files-header-content");
236
264
  var sessionsHeaderContent = document.getElementById("sessions-header-content");
237
265
  if (filesPanel) filesPanel.classList.add("hidden");
238
- if (filesHeaderContent) filesHeaderContent.classList.add("hidden");
239
266
  if (sessionsPanel) sessionsPanel.classList.remove("hidden");
240
267
  if (sessionsHeaderContent) sessionsHeaderContent.classList.remove("hidden");
241
268
  }
@@ -341,6 +368,150 @@ export function refreshIfOpen(filePath) {
341
368
 
342
369
  // --- WS handlers ---
343
370
 
371
+ export function handleFsSearch(msg) {
372
+ var entries = msg.entries || [];
373
+ var query = (msg.query || "").trim().toLowerCase();
374
+ if (!query) return;
375
+
376
+ ctx.fileTreeEl.innerHTML = "";
377
+
378
+ if (entries.length === 0) {
379
+ ctx.fileTreeEl.innerHTML = '<div class="fb-search-empty">No files found</div>';
380
+ return;
381
+ }
382
+
383
+ // Build a tree structure from flat search results
384
+ var tree = {};
385
+ for (var i = 0; i < entries.length; i++) {
386
+ var entry = entries[i];
387
+ var parts = entry.path.split("/");
388
+ var node = tree;
389
+ for (var j = 0; j < parts.length; j++) {
390
+ if (!node[parts[j]]) node[parts[j]] = {};
391
+ if (j === parts.length - 1) {
392
+ node[parts[j]]._entry = entry;
393
+ } else {
394
+ node = node[parts[j]];
395
+ }
396
+ }
397
+ }
398
+
399
+ renderFilteredTree(ctx.fileTreeEl, tree, 0, query);
400
+ refreshIcons();
401
+ }
402
+
403
+ function renderFilteredTree(container, tree, depth, query) {
404
+ var keys = Object.keys(tree);
405
+ var dirs = [];
406
+ var files = [];
407
+ for (var i = 0; i < keys.length; i++) {
408
+ if (keys[i] === "_entry") continue;
409
+ var node = tree[keys[i]];
410
+ var entry = node._entry;
411
+ if (entry && entry.type === "file") {
412
+ files.push(keys[i]);
413
+ } else {
414
+ dirs.push(keys[i]);
415
+ }
416
+ }
417
+ dirs.sort(function (a, b) {
418
+ var aH = a.charAt(0) === ".";
419
+ var bH = b.charAt(0) === ".";
420
+ if (aH !== bH) return aH ? 1 : -1;
421
+ return a.localeCompare(b);
422
+ });
423
+ files.sort(function (a, b) {
424
+ var aH = a.charAt(0) === ".";
425
+ var bH = b.charAt(0) === ".";
426
+ if (aH !== bH) return aH ? 1 : -1;
427
+ return a.localeCompare(b);
428
+ });
429
+
430
+ var allKeys = dirs.concat(files);
431
+ for (var k = 0; k < allKeys.length; k++) {
432
+ var name = allKeys[k];
433
+ var node = tree[name];
434
+ var entry = node._entry;
435
+ var isDir = !entry || entry.type === "dir";
436
+
437
+ var row = document.createElement("div");
438
+ row.className = "file-tree-item" + (isDir ? " expanded" : "");
439
+ row.style.paddingLeft = (8 + depth * 16) + "px";
440
+ if (entry) {
441
+ row.draggable = true;
442
+ row.dataset.path = entry.path;
443
+ row.addEventListener("dragstart", function (e) {
444
+ var cwd = ctx.cwd || "";
445
+ var rel = this.dataset.path;
446
+ var abs = cwd ? cwd.replace(/\/$/, "") + "/" + rel : rel;
447
+ e.dataTransfer.setData("text/plain", abs);
448
+ e.dataTransfer.effectAllowed = "copy";
449
+ });
450
+ }
451
+
452
+ var nameHtml = highlightMatch(name, query);
453
+
454
+ if (isDir) {
455
+ row.innerHTML =
456
+ '<span class="file-tree-chevron">' + iconHtml("chevron-right") + '</span>' +
457
+ '<span class="file-tree-icon file-tree-folder-icon"></span>' +
458
+ '<span class="file-tree-name">' + nameHtml + '</span>';
459
+
460
+ (function (iconEl, n) {
461
+ getFolderIconSvg(n, true, function (svg) { iconEl.innerHTML = svg; });
462
+ })(row.querySelector(".file-tree-folder-icon"), name);
463
+
464
+ var childContainer = document.createElement("div");
465
+ childContainer.className = "file-tree-children";
466
+
467
+ // Toggle expand/collapse on click
468
+ (function (rowEl, childEl, folderName) {
469
+ rowEl.addEventListener("click", function (e) {
470
+ e.stopPropagation();
471
+ var isExpanded = rowEl.classList.contains("expanded");
472
+ rowEl.classList.toggle("expanded");
473
+ childEl.classList.toggle("hidden", isExpanded);
474
+ var folderIconEl = rowEl.querySelector(".file-tree-folder-icon");
475
+ if (folderIconEl) {
476
+ getFolderIconSvg(folderName, !isExpanded, function (svg) { folderIconEl.innerHTML = svg; });
477
+ }
478
+ });
479
+ })(row, childContainer, name);
480
+
481
+ container.appendChild(row);
482
+ container.appendChild(childContainer);
483
+ renderFilteredTree(childContainer, node, depth + 1, query);
484
+ } else {
485
+ row.innerHTML =
486
+ '<span class="file-tree-spacer"></span>' +
487
+ '<span class="file-tree-icon">' + getFileIconSvg(name) + '</span>' +
488
+ '<span class="file-tree-name">' + nameHtml + '</span>';
489
+
490
+ (function (filePath, rowEl) {
491
+ rowEl.addEventListener("click", function (e) {
492
+ e.stopPropagation();
493
+ var prev = ctx.fileTreeEl.querySelector(".file-tree-item.active");
494
+ if (prev) prev.classList.remove("active");
495
+ rowEl.classList.add("active");
496
+ requestFileContent(filePath);
497
+ if (window.innerWidth <= 768) closeSidebar();
498
+ });
499
+ })(entry.path, row);
500
+
501
+ container.appendChild(row);
502
+ }
503
+ }
504
+ }
505
+
506
+ function highlightMatch(text, query) {
507
+ var lower = text.toLowerCase();
508
+ var idx = lower.indexOf(query);
509
+ if (idx === -1) return escapeHtml(text);
510
+ return escapeHtml(text.substring(0, idx)) +
511
+ '<mark>' + escapeHtml(text.substring(idx, idx + query.length)) + '</mark>' +
512
+ escapeHtml(text.substring(idx + query.length));
513
+ }
514
+
344
515
  export function handleFsList(msg) {
345
516
  var dirPath = msg.path || ".";
346
517
  treeData[dirPath] = { loaded: true, children: msg.entries || [] };
@@ -1,6 +1,8 @@
1
1
  import { iconHtml, refreshIcons } from './icons.js';
2
2
  import { setRewindMode, isRewindMode } from './rewind.js';
3
3
  import { checkForMention, showMentionMenu, hideMentionMenu, isMentionMenuVisible, mentionMenuKeydown, setMentionAtIdx, parseMentionFromInput, clearMentionState, stickyReapplyMention, sendMention, renderMentionUser, removeMentionChip } from './mention.js';
4
+ import { store } from './store.js';
5
+ import { mateAvatarUrl } from './avatar.js';
4
6
 
5
7
  var ctx;
6
8
 
@@ -217,8 +219,15 @@ export function sendMessage() {
217
219
  if (pastes.length > 0) {
218
220
  payload.pastes = pastes;
219
221
  }
222
+ // Include selected vendor for session binding (server uses on first message)
223
+ var _selVendor = store.get("currentVendor") || null;
224
+ if (_selVendor) payload.vendor = _selVendor;
220
225
  ctx.ws.send(JSON.stringify(payload));
221
226
 
227
+ // Hide vendor toggle after first message (vendor is locked to this session)
228
+ var _vtw2 = document.getElementById("vendor-toggle-wrap");
229
+ if (_vtw2) { _vtw2.classList.remove("hidden"); _vtw2.classList.add("locked"); }
230
+
222
231
  // Show pre-thinking dots before server responds
223
232
  if (ctx.isMateDm && ctx.isMateDm()) {
224
233
  ctx.showMatePreThinking();
@@ -770,6 +779,69 @@ export function initInput(_ctx) {
770
779
  // Trigger the mention detection
771
780
  inputEl.dispatchEvent(new Event("input", { bubbles: true }));
772
781
  });
782
+
783
+ // Mate avatar overlay on @ button — rotate random mate faces
784
+ var _lastOverlayIdx = -1;
785
+ var _overlayInterval = null;
786
+
787
+ function getAvailableMates() {
788
+ var mates = store.get('cachedMatesList') || [];
789
+ return mates.filter(function (m) { return m.status !== 'interviewing'; });
790
+ }
791
+
792
+ function pickNextMate(available) {
793
+ if (available.length === 0) return null;
794
+ if (available.length === 1) return available[0];
795
+ var idx = Math.floor(Math.random() * available.length);
796
+ if (idx === _lastOverlayIdx) idx = (idx + 1) % available.length;
797
+ _lastOverlayIdx = idx;
798
+ return available[idx];
799
+ }
800
+
801
+ function setOverlayAvatar(mate) {
802
+ var img = askMateBtn.querySelector('.ask-mate-avatar');
803
+ if (!mate) {
804
+ if (img) img.remove();
805
+ return;
806
+ }
807
+ var url = mateAvatarUrl(mate, 20);
808
+ if (!img) {
809
+ img = document.createElement('img');
810
+ img.className = 'ask-mate-avatar fade-in';
811
+ img.width = 20;
812
+ img.height = 20;
813
+ img.alt = '';
814
+ img.src = url;
815
+ askMateBtn.appendChild(img);
816
+ return;
817
+ }
818
+ // Fade out, swap, fade in
819
+ img.classList.remove('fade-in');
820
+ img.classList.add('fade-out');
821
+ setTimeout(function () {
822
+ img.src = url;
823
+ img.classList.remove('fade-out');
824
+ img.classList.add('fade-in');
825
+ }, 300);
826
+ }
827
+
828
+ function rotateMateOverlay() {
829
+ var available = getAvailableMates();
830
+ setOverlayAvatar(pickNextMate(available));
831
+ }
832
+
833
+ function startOverlayRotation() {
834
+ if (_overlayInterval) clearInterval(_overlayInterval);
835
+ rotateMateOverlay();
836
+ _overlayInterval = setInterval(rotateMateOverlay, 10000);
837
+ }
838
+
839
+ // Update overlay when mate list changes
840
+ store.subscribe(function (state, prev) {
841
+ if (state.cachedMatesList !== prev.cachedMatesList) {
842
+ startOverlayRotation();
843
+ }
844
+ });
773
845
  }
774
846
 
775
847
  // Paste handler
@@ -930,6 +1002,12 @@ export function initInput(_ctx) {
930
1002
  return;
931
1003
  }
932
1004
  e.preventDefault();
1005
+ // If input is empty but ghost suggestion is showing, adopt it
1006
+ var ghost = ctx.getGhostSuggestion ? ctx.getGhostSuggestion() : "";
1007
+ if (!ctx.inputEl.value.trim() && ghost) {
1008
+ ctx.inputEl.value = ghost;
1009
+ if (ctx.hideSuggestionChips) ctx.hideSuggestionChips();
1010
+ }
933
1011
  sendMessage();
934
1012
  }
935
1013
  });
@@ -941,6 +1019,14 @@ export function initInput(_ctx) {
941
1019
 
942
1020
  // Send/Stop button — if sendable content exists, always send; otherwise stop
943
1021
  ctx.sendBtn.addEventListener("click", function () {
1022
+ // Adopt ghost suggestion if input is empty
1023
+ var ghost = ctx.getGhostSuggestion ? ctx.getGhostSuggestion() : "";
1024
+ if (!hasSendableContent() && ghost) {
1025
+ ctx.inputEl.value = ghost;
1026
+ if (ctx.hideSuggestionChips) ctx.hideSuggestionChips();
1027
+ sendMessage();
1028
+ return;
1029
+ }
944
1030
  if (hasSendableContent()) {
945
1031
  sendMessage();
946
1032
  return;
@@ -1,6 +1,7 @@
1
1
  import { avatarUrl, mateAvatarUrl } from './avatar.js';
2
2
  import { escapeHtml } from './utils.js';
3
3
  import { iconHtml, refreshIcons } from './icons.js';
4
+ import { store } from './store.js';
4
5
  import { hideKnowledge } from './mate-knowledge.js';
5
6
  import { isSchedulerOpen, closeScheduler } from './scheduler.js';
6
7
  import { hideNotes } from './sticky-notes.js';
@@ -150,6 +151,43 @@ export function showMateSidebar(mateId, mateData) {
150
151
  if (avatarEl) avatarEl.src = mateAvUrl;
151
152
  if (nameEl) nameEl.textContent = displayName;
152
153
 
154
+ // Vendor toggle in header
155
+ var mateVendorWrap = document.getElementById("mate-vendor-toggle");
156
+ if (mateVendorWrap) {
157
+ var available = store.get('availableVendors') || [];
158
+ var mateVendor = mateData.vendor || "claude";
159
+ var vendorIcons = { claude: "/claude-code-avatar.png", codex: "/codex-avatar.png" };
160
+ var vendorNames = { claude: "Claude Code", codex: "Codex" };
161
+ var vendorKeys = ["claude", "codex"];
162
+ mateVendorWrap.innerHTML = "";
163
+ for (var vi = 0; vi < vendorKeys.length; vi++) {
164
+ var vk = vendorKeys[vi];
165
+ var vBtn = document.createElement("button");
166
+ vBtn.className = "mate-vendor-btn" + (vk === mateVendor ? " active" : "");
167
+ if (available.indexOf(vk) === -1) vBtn.classList.add("disabled");
168
+ vBtn.dataset.vendor = vk;
169
+ vBtn.innerHTML = '<img src="' + vendorIcons[vk] + '" class="mate-vendor-icon" alt="' + vendorNames[vk] + '"><span class="mate-vendor-label">' + vendorNames[vk] + '</span>';
170
+ vBtn.addEventListener("click", function() {
171
+ var v = this.dataset.vendor;
172
+ var avail = store.get('availableVendors') || [];
173
+ if (avail.indexOf(v) === -1) return;
174
+ if (v === (currentMate && currentMate.vendor || "claude")) return;
175
+ if (!currentMateId) return;
176
+ var ws = getWs();
177
+ if (ws) ws.send(JSON.stringify({ type: "mate_update", mateId: currentMateId, updates: { vendor: v } }));
178
+ // Update UI immediately
179
+ mateVendorWrap.querySelectorAll(".mate-vendor-btn").forEach(function(b) {
180
+ b.classList.toggle("active", b.dataset.vendor === v);
181
+ });
182
+ if (currentMate) currentMate.vendor = v;
183
+ // If current session is new (no history), sync vendor to input toggle
184
+ var _hTotal = store.get('historyTotal') || 0;
185
+ if (_hTotal === 0) store.set({ currentVendor: v });
186
+ });
187
+ mateVendorWrap.appendChild(vBtn);
188
+ }
189
+ }
190
+
153
191
  // Also populate collapsed header info
154
192
  var collapsedAvatar = document.getElementById("mate-collapsed-avatar");
155
193
  var collapsedName = document.getElementById("mate-collapsed-name");
@@ -2,6 +2,7 @@ import { mateAvatarUrl, userAvatarUrl } from './avatar.js';
2
2
  import { renderMarkdown, highlightCodeBlocks } from './markdown.js';
3
3
  import { escapeHtml, copyToClipboard } from './utils.js';
4
4
  import { iconHtml, refreshIcons } from './icons.js';
5
+ import { store } from './store.js';
5
6
 
6
7
  var ctx;
7
8
 
@@ -77,13 +78,17 @@ export function showMentionMenu(query) {
77
78
  var menuEl = document.getElementById("mention-menu");
78
79
  if (!menuEl) return;
79
80
 
80
- menuEl.innerHTML = mentionFiltered.map(function (m, i) {
81
+ menuEl.innerHTML = '<div class="mention-hint">Mention a Mate to get advice on your current session<button class="mention-close-btn" aria-label="Close">&times;</button></div>' +
82
+ mentionFiltered.map(function (m, i) {
81
83
  var name = (m.profile && m.profile.displayName) || m.name || "Mate";
82
84
  var color = (m.profile && m.profile.avatarColor) || "#6c5ce7";
83
85
  var bio = m.bio || (m.profile && m.profile.bio) || "";
84
86
  var avatarSrc = mateAvatarUrl(m, 24);
87
+ var mVendor = m.vendor || "claude";
88
+ var vendorIcons = { claude: "/claude-code-avatar.png", codex: "/codex-avatar.png" };
89
+ var vendorBadge = vendorIcons[mVendor] ? '<img class="mention-item-vendor-badge" src="' + vendorIcons[mVendor] + '" alt="' + mVendor + '">' : '';
85
90
  return '<div class="mention-item' + (i === 0 ? ' active' : '') + '" data-idx="' + i + '">' +
86
- '<img class="mention-item-avatar" src="' + escapeHtml(avatarSrc) + '" width="24" height="24" />' +
91
+ '<div class="mention-item-avatar-wrap"><img class="mention-item-avatar" src="' + escapeHtml(avatarSrc) + '" width="24" height="24" />' + vendorBadge + '</div>' +
87
92
  '<div class="mention-item-info">' +
88
93
  '<span class="mention-item-name">' + escapeHtml(name) +
89
94
  (m.primary ? ' <span class="mention-item-badge">SYSTEM</span>' : '') +
@@ -95,6 +100,18 @@ export function showMentionMenu(query) {
95
100
  }).join("");
96
101
  menuEl.classList.add("visible");
97
102
 
103
+ var closeBtn = menuEl.querySelector(".mention-close-btn");
104
+ if (closeBtn) closeBtn.addEventListener("click", function (e) {
105
+ e.preventDefault();
106
+ e.stopPropagation();
107
+ hideMentionMenu();
108
+ clearMentionState();
109
+ if (ctx && ctx.inputEl) {
110
+ ctx.inputEl.value = ctx.inputEl.value.replace(/@\S*$/, "");
111
+ ctx.inputEl.focus();
112
+ }
113
+ });
114
+
98
115
  menuEl.querySelectorAll(".mention-item").forEach(function (el) {
99
116
  el.addEventListener("click", function (e) {
100
117
  e.preventDefault();
@@ -215,10 +232,11 @@ function showInputMentionChip(name, color, avatarSrc) {
215
232
  '<button class="input-mention-chip-remove" type="button" aria-label="Remove mention">&times;</button>';
216
233
  chip.style.setProperty("--chip-color", color);
217
234
 
218
- // Insert before the textarea inside input-row
235
+ // Insert before the textarea wrapper inside input-row
219
236
  var inputRow = document.getElementById("input-row");
220
- if (inputRow && ctx.inputEl) {
221
- inputRow.insertBefore(chip, ctx.inputEl);
237
+ var textareaWrap = document.getElementById("input-textarea-wrap");
238
+ if (inputRow && textareaWrap) {
239
+ inputRow.insertBefore(chip, textareaWrap);
222
240
  }
223
241
 
224
242
  chip.querySelector(".input-mention-chip-remove").addEventListener("click", function (e) {
@@ -713,7 +731,7 @@ export function renderMentionUser(entry) {
713
731
  '<span class="msg-action-time">' + ts2 + '</span>' +
714
732
  '<button class="msg-action-btn msg-action-copy" type="button" title="Copy">' + iconHtml("copy") + '</button>' +
715
733
  '<button class="msg-action-btn msg-action-fork" type="button" title="Fork">' + iconHtml("git-branch") + '</button>' +
716
- '<button class="msg-action-btn msg-action-rewind msg-user-rewind-btn" type="button" title="Rewind">' + iconHtml("rotate-ccw") + '</button>' +
734
+ (((store.get('vendorCapabilities') || {}).rewind !== false) ? '<button class="msg-action-btn msg-action-rewind msg-user-rewind-btn" type="button" title="Rewind">' + iconHtml("rotate-ccw") + '</button>' : '') +
717
735
  '<button class="msg-action-btn msg-action-hidden msg-action-edit" type="button" title="Edit">' + iconHtml("pencil") + '</button>';
718
736
  div.appendChild(actions);
719
737
 
@@ -790,7 +790,7 @@ function renderModelTab(bodyEl, rec) {
790
790
  }
791
791
 
792
792
  var opts = {
793
- models: store.getState().currentModels || [],
793
+ models: store.get('currentModels') || [],
794
794
  currentModel: settings.model || "",
795
795
  currentMode: settings.permissionMode || "default",
796
796
  currentEffort: settings.effort || "medium",