clay-server 2.14.0 → 2.15.0-beta.1

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.
@@ -795,8 +795,8 @@
795
795
  height: 16px;
796
796
  }
797
797
 
798
- /* Knowledge editor/preview panel (overlays main content) */
799
- #mate-knowledge-container {
798
+ /* Knowledge editor panel (overlays main content) */
799
+ #mate-knowledge-editor {
800
800
  position: absolute;
801
801
  inset: 0;
802
802
  z-index: 100;
@@ -805,7 +805,61 @@
805
805
  flex-direction: column;
806
806
  overflow: hidden;
807
807
  }
808
- #mate-knowledge-container.hidden {
808
+ #mate-knowledge-editor.hidden {
809
+ display: none;
810
+ }
811
+
812
+ /* --- Knowledge viewer (side panel, mirrors #file-viewer) --- */
813
+ @media (min-width: 1024px) {
814
+ #mate-knowledge-viewer {
815
+ width: 50%;
816
+ max-width: 720px;
817
+ min-width: 360px;
818
+ border-left: 1px solid var(--border);
819
+ background: var(--bg);
820
+ display: flex;
821
+ flex-direction: column;
822
+ overflow: hidden;
823
+ flex-shrink: 0;
824
+ }
825
+ #mate-knowledge-viewer.hidden { display: none; }
826
+ }
827
+ @media (max-width: 1023px) {
828
+ #mate-knowledge-viewer {
829
+ position: fixed;
830
+ inset: 0;
831
+ background: var(--bg);
832
+ z-index: 300;
833
+ display: flex;
834
+ flex-direction: column;
835
+ overflow: hidden;
836
+ }
837
+ #mate-knowledge-viewer.hidden { display: none; }
838
+ }
839
+ .mate-knowledge-viewer-header {
840
+ display: flex;
841
+ align-items: center;
842
+ gap: 8px;
843
+ padding: 10px 16px;
844
+ border-bottom: 1px solid var(--border-subtle);
845
+ flex-shrink: 0;
846
+ min-height: 44px;
847
+ }
848
+ .mate-knowledge-viewer-body {
849
+ flex: 1;
850
+ overflow-y: auto;
851
+ padding: 20px 24px;
852
+ }
853
+
854
+ /* Knowledge editor (full overlay) */
855
+ .mate-knowledge-editor {
856
+ display: flex;
857
+ flex-direction: column;
858
+ flex: 1;
859
+ min-height: 0;
860
+ overflow: hidden;
861
+ }
862
+ .mate-knowledge-editor.hidden {
809
863
  display: none;
810
864
  }
811
865
 
@@ -876,23 +930,25 @@
876
930
  .mate-knowledge-file-list {
877
931
  flex: 1;
878
932
  overflow-y: auto;
879
- padding: 4px 0;
933
+ padding: 4px 6px;
880
934
  }
881
935
  .mate-knowledge-file-item {
882
936
  display: flex;
883
937
  align-items: center;
884
938
  gap: 6px;
885
- padding: 6px 12px;
939
+ padding: 5px 8px;
940
+ border-radius: 8px;
886
941
  cursor: pointer;
887
942
  font-size: 13px;
888
943
  color: var(--text-secondary);
889
- transition: background 0.1s;
944
+ transition: background 0.15s, color 0.15s;
890
945
  }
891
946
  .mate-knowledge-file-item:hover {
892
- background: rgba(var(--overlay-rgb), 0.06);
947
+ background: var(--sidebar-hover);
948
+ color: var(--text);
893
949
  }
894
950
  .mate-knowledge-file-item.active {
895
- background: rgba(var(--overlay-rgb), 0.1);
951
+ background: var(--sidebar-active);
896
952
  color: var(--text);
897
953
  font-weight: 600;
898
954
  }
@@ -922,6 +978,85 @@
922
978
  flex-shrink: 0;
923
979
  }
924
980
 
981
+ /* Common knowledge section headers */
982
+ .mate-knowledge-section-header {
983
+ font-size: 10px;
984
+ font-weight: 700;
985
+ text-transform: uppercase;
986
+ letter-spacing: 0.8px;
987
+ color: var(--text-dimmer);
988
+ padding: 10px 12px 4px;
989
+ }
990
+ .mate-knowledge-file-badge.common {
991
+ background: rgba(0, 184, 148, 0.15);
992
+ color: #00b894;
993
+ }
994
+ .mate-knowledge-file-badge.promoted {
995
+ background: rgba(0, 184, 148, 0.15);
996
+ color: #00b894;
997
+ }
998
+ .mate-knowledge-dots-btn {
999
+ display: none;
1000
+ background: none;
1001
+ border: none;
1002
+ cursor: pointer;
1003
+ padding: 2px;
1004
+ margin-left: auto;
1005
+ color: var(--text-dimmer);
1006
+ flex-shrink: 0;
1007
+ opacity: 0.5;
1008
+ transition: opacity 0.15s;
1009
+ }
1010
+ .mate-knowledge-dots-btn .lucide {
1011
+ width: 14px;
1012
+ height: 14px;
1013
+ }
1014
+ .mate-knowledge-file-item:hover .mate-knowledge-dots-btn {
1015
+ display: flex;
1016
+ }
1017
+ .mate-knowledge-dots-btn:hover {
1018
+ opacity: 1;
1019
+ }
1020
+ .mate-knowledge-file-menu {
1021
+ position: fixed;
1022
+ z-index: 9999;
1023
+ background: var(--sidebar-bg);
1024
+ border: 1px solid var(--border);
1025
+ border-radius: 10px;
1026
+ padding: 4px 0;
1027
+ min-width: 140px;
1028
+ box-shadow: 0 4px 16px rgba(var(--shadow-rgb), 0.4);
1029
+ }
1030
+ .mate-knowledge-file-menu-item {
1031
+ display: flex;
1032
+ align-items: center;
1033
+ gap: 8px;
1034
+ width: 100%;
1035
+ padding: 8px 12px;
1036
+ background: none;
1037
+ border: none;
1038
+ font-family: inherit;
1039
+ cursor: pointer;
1040
+ color: var(--text-secondary);
1041
+ font-size: 13px;
1042
+ white-space: nowrap;
1043
+ transition: background 0.15s;
1044
+ }
1045
+ .mate-knowledge-file-menu-item:hover {
1046
+ background: rgba(var(--overlay-rgb), 0.05);
1047
+ }
1048
+ .mate-knowledge-file-menu-item .lucide {
1049
+ width: 14px;
1050
+ height: 14px;
1051
+ flex-shrink: 0;
1052
+ }
1053
+ .mate-knowledge-file-menu-item.menu-item-danger {
1054
+ color: var(--error);
1055
+ }
1056
+ .mate-knowledge-file-menu-item.menu-item-danger:hover {
1057
+ background: var(--error-8);
1058
+ }
1059
+
925
1060
  /* JSONL table view */
926
1061
  .mate-knowledge-jsonl-table {
927
1062
  width: 100%;
@@ -1329,6 +1464,7 @@
1329
1464
 
1330
1465
  /* Match panel header heights to sidebar header (48px) */
1331
1466
  body.mate-dm-active .mate-knowledge-header-bar,
1467
+ body.mate-dm-active .mate-knowledge-viewer-header,
1332
1468
  body.mate-dm-active .scheduler-top-bar,
1333
1469
  body.mate-dm-active .notes-archive-header {
1334
1470
  height: 48px;
@@ -1336,7 +1472,7 @@ body.mate-dm-active .notes-archive-header {
1336
1472
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
1337
1473
  }
1338
1474
 
1339
- /* Knowledge header bar */
1475
+ /* Knowledge editor header bar (full mate color, overrides whole area) */
1340
1476
  body.mate-dm-active .mate-knowledge-header-bar {
1341
1477
  background: var(--mate-color);
1342
1478
  color: #fff;
@@ -1361,15 +1497,33 @@ body.mate-dm-active .mate-knowledge-header-bar .mate-knowledge-header-btn:hover
1361
1497
  background: rgba(255, 255, 255, 0.15);
1362
1498
  }
1363
1499
  body.mate-dm-active .mate-knowledge-header-bar .mate-knowledge-header-btn:disabled {
1364
- color: rgba(255, 255, 255, 0.3);
1500
+ color: rgba(255, 255, 255, 0.4);
1365
1501
  }
1366
1502
  body.mate-dm-active .mate-knowledge-header-bar .mate-knowledge-header-btn:disabled:hover {
1367
1503
  background: none;
1368
- color: rgba(255, 255, 255, 0.3);
1504
+ color: rgba(255, 255, 255, 0.4);
1369
1505
  }
1370
1506
  body.mate-dm-active .mate-knowledge-header-bar #mate-knowledge-editor-delete:hover {
1371
- color: #fff;
1372
- background: rgba(255, 80, 80, 0.4);
1507
+ color: #ff5555;
1508
+ background: rgba(255, 85, 85, 0.15);
1509
+ }
1510
+
1511
+ /* Knowledge viewer header bar (side panel, light tint via --mate-color + 0a) */
1512
+ body.mate-dm-active .mate-knowledge-viewer-header {
1513
+ background: var(--mate-color-tint, var(--bg-secondary));
1514
+ color: var(--text-main);
1515
+ border-bottom: 1px solid var(--border-subtle);
1516
+ }
1517
+ body.mate-dm-active .mate-knowledge-viewer-header .mate-knowledge-header-icon,
1518
+ body.mate-dm-active .mate-knowledge-viewer-header .mate-knowledge-active-name {
1519
+ color: var(--text-main);
1520
+ }
1521
+ body.mate-dm-active .mate-knowledge-viewer-header .file-viewer-btn {
1522
+ color: var(--text-dim);
1523
+ }
1524
+ body.mate-dm-active .mate-knowledge-viewer-header .file-viewer-btn:hover {
1525
+ color: var(--text-main);
1526
+ background: rgba(var(--overlay-rgb), 0.08);
1373
1527
  }
1374
1528
 
1375
1529
  /* Scheduler top bar (main header) */
@@ -127,6 +127,15 @@ mark.session-search-highlight-active {
127
127
  pointer-events: none;
128
128
  }
129
129
 
130
+ .search-blink {
131
+ animation: searchBlink 0.4s ease-in-out 3;
132
+ }
133
+
134
+ @keyframes searchBlink {
135
+ 0%, 100% { box-shadow: none; }
136
+ 50% { box-shadow: 0 0 0 2px var(--accent); border-radius: 12px; }
137
+ }
138
+
130
139
  /* Mobile */
131
140
  @media (max-width: 768px) {
132
141
  #find-in-session-btn {
@@ -384,23 +384,6 @@
384
384
  padding: 0 1px;
385
385
  }
386
386
 
387
- /* --- Search hit timeline (right-side markers) --- */
388
- .search-timeline {
389
- position: absolute;
390
- right: 8px;
391
- z-index: 10;
392
- pointer-events: none;
393
- }
394
-
395
- .search-blink {
396
- animation: searchBlink 0.4s ease-in-out 3;
397
- }
398
-
399
- @keyframes searchBlink {
400
- 0%, 100% { box-shadow: none; }
401
- 50% { box-shadow: 0 0 0 2px var(--accent); border-radius: 12px; }
402
- }
403
-
404
387
  #session-list {
405
388
  padding: 2px 8px;
406
389
  }
@@ -232,7 +232,8 @@
232
232
  </div>
233
233
 
234
234
  <div id="main-column">
235
- <div id="mate-knowledge-container" class="hidden">
235
+ <!-- Knowledge editor (full overlay, shown on Edit) -->
236
+ <div id="mate-knowledge-editor" class="mate-knowledge-editor hidden">
236
237
  <div class="mate-knowledge-header-bar">
237
238
  <i data-lucide="file-text" class="mate-knowledge-header-icon"></i>
238
239
  <span id="mate-knowledge-active-name" class="mate-knowledge-active-name">No file selected</span>
@@ -462,6 +463,19 @@
462
463
  </div>
463
464
  <div class="file-viewer-body" id="file-viewer-body"></div>
464
465
  </div>
466
+ <!-- Knowledge viewer (side panel, like file-viewer) -->
467
+ <div id="mate-knowledge-viewer" class="hidden">
468
+ <div class="mate-knowledge-viewer-header">
469
+ <i data-lucide="file-text" class="mate-knowledge-header-icon"></i>
470
+ <span id="mate-knowledge-viewer-name" class="mate-knowledge-active-name">No file selected</span>
471
+ <div class="mate-knowledge-toolbar-spacer"></div>
472
+ <button id="mate-knowledge-viewer-edit-btn" class="file-viewer-btn" title="Edit"><i data-lucide="pencil"></i></button>
473
+ <button id="mate-knowledge-viewer-close-btn" class="file-viewer-btn" title="Close"><i data-lucide="x"></i></button>
474
+ </div>
475
+ <div class="mate-knowledge-viewer-body">
476
+ <div id="mate-knowledge-viewer-content" class="mate-knowledge-preview-content md-content"></div>
477
+ </div>
478
+ </div>
465
479
  <div id="project-settings" class="hidden panel-fullscreen">
466
480
  <div class="project-settings-layout">
467
481
  <div class="project-settings-nav">
@@ -12,16 +12,13 @@ var items = [];
12
12
  var debounceTimer = null;
13
13
  var abortCtrl = null;
14
14
  var pendingNav = null;
15
- var mode = "home"; // "home" or "search"
16
15
  var cachedHomeData = null;
17
16
  var cachedVersion = null;
18
17
 
19
18
  // --- Commands registry ---
20
19
  var commands = [
21
- { id: "search", label: "Search sessions", desc: "Search across all projects", icon: "search", action: "enterSearch" },
22
20
  { id: "create-mate", label: "Create Mate", desc: "Create a new AI teammate", icon: "user-plus", action: "createMate" },
23
21
  { id: "settings", label: "Server settings", desc: "Configure server", icon: "settings", action: "openSettings" },
24
- { id: "home", label: "Home", desc: "Go to home hub", icon: "home", action: "showHome" },
25
22
  ];
26
23
 
27
24
  export function initCommandPalette(_ctx) {
@@ -59,7 +56,6 @@ export function isCommandPaletteOpen() {
59
56
 
60
57
  export function openCommandPalette() {
61
58
  if (!paletteEl) return;
62
- mode = "home";
63
59
  paletteEl.classList.remove("hidden");
64
60
  var searchbar = document.getElementById("cmd-palette-btn");
65
61
  if (searchbar) searchbar.style.visibility = "hidden";
@@ -82,7 +78,6 @@ export function closeCommandPalette() {
82
78
  resultsEl.innerHTML = "";
83
79
  items = [];
84
80
  activeIndex = -1;
85
- mode = "home";
86
81
  if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }
87
82
  if (abortCtrl) { abortCtrl.abort(); abortCtrl = null; }
88
83
  }
@@ -136,36 +131,18 @@ function buildDOM() {
136
131
  inputEl.addEventListener("input", function () {
137
132
  var q = inputEl.value;
138
133
  if (debounceTimer) clearTimeout(debounceTimer);
139
- if (mode === "search") {
134
+ renderHome(q.trim());
135
+ if (q.trim()) {
140
136
  debounceTimer = setTimeout(function () {
141
- fetchSearchResults(q.trim());
142
- }, 250);
143
- } else {
144
- renderHome(q.trim());
137
+ fetchHomeSearchResults(q.trim());
138
+ }, 300);
145
139
  }
146
140
  });
147
141
 
148
142
  inputEl.addEventListener("keydown", function (e) {
149
143
  if (e.key === "Escape") {
150
144
  e.preventDefault();
151
- if (mode === "search") {
152
- // Back to home mode
153
- mode = "home";
154
- inputEl.value = "";
155
- inputEl.placeholder = "Type a command or search...";
156
- updateFooter();
157
- renderHome("");
158
- } else {
159
- closeCommandPalette();
160
- }
161
- return;
162
- }
163
- if (e.key === "Backspace" && mode === "search" && inputEl.value === "") {
164
- e.preventDefault();
165
- mode = "home";
166
- inputEl.placeholder = "Type a command or search...";
167
- updateFooter();
168
- renderHome("");
145
+ closeCommandPalette();
169
146
  return;
170
147
  }
171
148
  if (e.key === "ArrowDown") {
@@ -193,17 +170,9 @@ function buildDOM() {
193
170
  }
194
171
 
195
172
  function updateFooter() {
196
- var shortcuts = '';
197
- if (mode === "search") {
198
- shortcuts =
199
- '<span><kbd>&uarr;</kbd> <kbd>&darr;</kbd> navigate</span>' +
200
- '<span><kbd>Enter</kbd> open</span>' +
201
- '<span><kbd>Esc</kbd> back</span>';
202
- } else {
203
- shortcuts =
204
- '<span><kbd>&uarr;</kbd> <kbd>&darr;</kbd> navigate</span>' +
205
- '<span><kbd>Enter</kbd> select</span>';
206
- }
173
+ var shortcuts =
174
+ '<span><kbd>&uarr;</kbd> <kbd>&darr;</kbd> navigate</span>' +
175
+ '<span><kbd>Enter</kbd> select</span>';
207
176
  var versionText = cachedVersion ? "v" + cachedVersion : "";
208
177
  footerEl.innerHTML =
209
178
  '<a href="https://github.com/chadbyte/clay" target="_blank" rel="noopener" class="cmd-palette-brand"><img src="favicon-banded.png" width="13" height="13" alt="">Clay ' + versionText + '</a>' +
@@ -359,7 +328,7 @@ function renderHome(filter) {
359
328
  }
360
329
  }
361
330
 
362
- if (items.length === 0) {
331
+ if (items.length === 0 && !f) {
363
332
  html = '<div class="cmd-palette-empty">No matching results</div>';
364
333
  }
365
334
 
@@ -370,80 +339,65 @@ function renderHome(filter) {
370
339
  }
371
340
 
372
341
  // ==========================================
373
- // SEARCH MODE: cross-project session content search
342
+ // HOME MODE: inline session search (server-side)
374
343
  // ==========================================
375
344
 
376
- function enterSearchMode() {
377
- mode = "search";
378
- inputEl.value = "";
379
- inputEl.placeholder = "Search session titles and content...";
380
- resultsEl.innerHTML = '<div class="cmd-palette-empty">Type to search across all projects</div>';
381
- items = [];
382
- activeIndex = -1;
383
- updateFooter();
384
- inputEl.focus();
385
- }
345
+ var homeSearchQuery = "";
386
346
 
387
- function fetchSearchResults(query) {
388
- if (!query) {
389
- resultsEl.innerHTML = '<div class="cmd-palette-empty">Type to search across all projects</div>';
390
- items = [];
391
- activeIndex = -1;
392
- return;
393
- }
347
+ function fetchHomeSearchResults(query) {
348
+ homeSearchQuery = query;
394
349
  if (abortCtrl) { abortCtrl.abort(); abortCtrl = null; }
395
350
  abortCtrl = new AbortController();
396
- resultsEl.innerHTML = '<div class="cmd-palette-loading">Searching...</div>';
397
351
  fetch("/api/palette/search?q=" + encodeURIComponent(query), { signal: abortCtrl.signal })
398
352
  .then(function (res) { return res.json(); })
399
353
  .then(function (data) {
400
354
  abortCtrl = null;
401
- renderSearchResults(data.results || [], query);
355
+ if (homeSearchQuery !== query) return;
356
+ appendHomeSearchResults(data.results || [], query);
402
357
  })
403
358
  .catch(function (err) {
404
359
  if (err.name === "AbortError") return;
405
360
  abortCtrl = null;
406
- resultsEl.innerHTML = '<div class="cmd-palette-empty">Search failed</div>';
407
361
  });
408
362
  }
409
363
 
410
- function renderSearchResults(results, query) {
411
- items = [];
412
- activeIndex = -1;
413
-
414
- if (results.length === 0) {
415
- resultsEl.innerHTML = '<div class="cmd-palette-empty">No results found</div>';
416
- return;
417
- }
364
+ function appendHomeSearchResults(results, query) {
365
+ if (results.length === 0) return;
418
366
 
419
- // Group by project
420
- var groups = [];
421
- var groupMap = {};
422
- for (var i = 0; i < results.length; i++) {
423
- var r = results[i];
424
- if (!groupMap[r.projectSlug]) {
425
- groupMap[r.projectSlug] = { slug: r.projectSlug, title: r.projectTitle, icon: r.projectIcon, items: [] };
426
- groups.push(groupMap[r.projectSlug]);
367
+ // Deduplicate: exclude sessions already shown in the Recent section
368
+ var existingIds = {};
369
+ for (var e = 0; e < items.length; e++) {
370
+ if (items[e].type === "session" && items[e].data.sessionId) {
371
+ existingIds[items[e].data.projectSlug + ":" + items[e].data.sessionId] = true;
427
372
  }
428
- groupMap[r.projectSlug].items.push(r);
429
373
  }
430
-
431
- var html = "";
432
- var flatIndex = 0;
433
- for (var g = 0; g < groups.length; g++) {
434
- var group = groups[g];
435
- var label = escapeHtml(group.icon ? group.icon + " " + (group.title || group.slug) : (group.title || group.slug));
436
- html += '<div class="cmd-palette-group-label">' + label + '</div>';
437
- for (var j = 0; j < group.items.length; j++) {
438
- var item = group.items[j];
439
- items.push({ type: "search-result", data: item, query: query });
440
- var snippet = item.snippet ? escapeHtml(item.snippet) : "";
441
- html += renderItem(flatIndex, group.icon || '<i data-lucide="message-square"></i>', escapeHtml(item.sessionTitle || "New Session"), null, snippet);
442
- flatIndex++;
443
- }
374
+ var newResults = results.filter(function (r) {
375
+ return !existingIds[r.projectSlug + ":" + r.sessionId];
376
+ });
377
+ if (newResults.length === 0) return;
378
+
379
+ // Remove "No matching results" if present
380
+ var emptyEl = resultsEl.querySelector(".cmd-palette-empty");
381
+ if (emptyEl) emptyEl.remove();
382
+
383
+ // Build HTML and append
384
+ var html = '<div class="cmd-palette-group-label cmd-palette-search-results-label">Session search results</div>';
385
+ var flatIndex = items.length;
386
+ for (var i = 0; i < newResults.length; i++) {
387
+ var r = newResults[i];
388
+ items.push({ type: "search-result", data: r, query: query });
389
+ var projLabel = (r.projectIcon || "") + " " + escapeHtml(r.projectTitle || r.projectSlug);
390
+ var snippet = r.snippet ? escapeHtml(r.snippet) : "";
391
+ html += renderItem(flatIndex, r.projectIcon || '<i data-lucide="message-square"></i>', escapeHtml(r.sessionTitle || "New Session"), projLabel.trim(), snippet);
392
+ flatIndex++;
444
393
  }
445
394
 
446
- resultsEl.innerHTML = html;
395
+ // Append to results
396
+ var frag = document.createElement("div");
397
+ frag.innerHTML = html;
398
+ while (frag.firstChild) {
399
+ resultsEl.appendChild(frag.firstChild);
400
+ }
447
401
  refreshIcons();
448
402
  bindItemEvents();
449
403
  }
@@ -514,10 +468,6 @@ function activateItem(entry) {
514
468
  }
515
469
 
516
470
  function executeCommand(cmd) {
517
- if (cmd.action === "enterSearch") {
518
- enterSearchMode();
519
- return;
520
- }
521
471
  closeCommandPalette();
522
472
  switch (cmd.action) {
523
473
  case "createMate":
@@ -526,9 +476,6 @@ function executeCommand(cmd) {
526
476
  case "openSettings":
527
477
  ctx.runAction("openSettings");
528
478
  break;
529
- case "showHome":
530
- ctx.runAction("showHome");
531
- break;
532
479
  }
533
480
  }
534
481