clay-server 2.11.0-beta.8 → 2.11.0
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/bin/cli.js +282 -115
- package/lib/daemon.js +109 -37
- package/lib/os-users.js +58 -1
- package/lib/pages.js +31 -29
- package/lib/project.js +47 -9
- package/lib/public/app.js +158 -16
- package/lib/public/css/filebrowser.css +6 -0
- package/lib/public/css/icon-strip.css +123 -1
- package/lib/public/css/messages.css +1 -1
- package/lib/public/css/mobile-nav.css +17 -0
- package/lib/public/css/overlays.css +49 -0
- package/lib/public/css/sidebar.css +26 -0
- package/lib/public/css/sticky-notes.css +3 -0
- package/lib/public/index.html +2 -0
- package/lib/public/modules/admin.js +53 -5
- package/lib/public/modules/sidebar.js +299 -21
- package/lib/public/modules/sticky-notes.js +27 -5
- package/lib/public/modules/terminal.js +161 -25
- package/lib/sdk-bridge.js +53 -7
- package/lib/server.js +156 -17
- package/lib/sessions.js +48 -7
- package/lib/terminal-manager.js +4 -2
- package/lib/terminal.js +2 -1
- package/lib/users.js +92 -0
- package/package.json +1 -1
package/lib/public/app.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { showToast, copyToClipboard, escapeHtml } from './modules/utils.js';
|
|
2
2
|
import { refreshIcons, iconHtml, randomThinkingVerb } from './modules/icons.js';
|
|
3
3
|
import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks, closeMermaidModal, parseEmojis } from './modules/markdown.js';
|
|
4
|
-
import { initSidebar, renderSessionList, handleSearchResults, updateSessionPresence, updatePageTitle, getActiveSearchQuery, buildSearchTimeline, removeSearchTimeline, populateCliSessionList, renderIconStrip, renderSidebarPresence, initIconStrip, getEmojiCategories, renderUserStrip, setCurrentDmUser, updateDmBadge } from './modules/sidebar.js';
|
|
4
|
+
import { initSidebar, renderSessionList, handleSearchResults, updateSessionPresence, updatePageTitle, getActiveSearchQuery, buildSearchTimeline, removeSearchTimeline, populateCliSessionList, renderIconStrip, renderSidebarPresence, initIconStrip, getEmojiCategories, renderUserStrip, setCurrentDmUser, updateDmBadge, updateSessionBadge, updateProjectBadge, closeDmUserPicker, spawnDustParticles } from './modules/sidebar.js';
|
|
5
5
|
import { initRewind, setRewindMode, showRewindModal, clearPendingRewindUuid, addRewindButton } from './modules/rewind.js';
|
|
6
6
|
import { initNotifications, showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundEnabled } from './modules/notifications.js';
|
|
7
7
|
import { initInput, clearPendingImages, handleInputSync, autoResize, builtinCommands, sendMessage } from './modules/input.js';
|
|
8
8
|
import { initQrCode } from './modules/qrcode.js';
|
|
9
9
|
import { initFileBrowser, loadRootDirectory, refreshTree, handleFsList, handleFsRead, handleDirChanged, refreshIfOpen, handleFileChanged, handleFileHistory, handleGitDiff, handleFileAt, getPendingNavigate, closeFileViewer, resetFileBrowser } from './modules/filebrowser.js';
|
|
10
10
|
import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
|
|
11
|
-
import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, openArchive, closeArchive, isArchiveOpen } from './modules/sticky-notes.js';
|
|
11
|
+
import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, openArchive, closeArchive, isArchiveOpen, hideNotes, showNotes, isNotesVisible } from './modules/sticky-notes.js';
|
|
12
12
|
import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme } from './modules/theme.js';
|
|
13
13
|
import { initTools, resetToolState, saveToolState, restoreToolState, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionResolved, markPermissionCancelled, renderElicitationRequest, markElicitationResolved, renderPlanBanner, renderPlanCard, handleTodoWrite, handleTaskCreate, handleTaskUpdate, startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, addTurnMeta, enableMainInput, getTools, getPlanContent, setPlanContent, isPlanFilePath, getTodoTools, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, updateSubagentProgress, initSubagentStop, closeToolGroup, removeToolFromGroup } from './modules/tools.js';
|
|
14
14
|
import { initServerSettings, updateSettingsStats, updateSettingsModels, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved, handleGlobalClaudeMdRead, handleGlobalClaudeMdWrite } from './modules/server-settings.js';
|
|
@@ -55,6 +55,10 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
55
55
|
var dmTargetUser = null;
|
|
56
56
|
var dmUnread = {}; // { otherUserId: count }
|
|
57
57
|
var cachedAllUsers = [];
|
|
58
|
+
var cachedOnlineIds = [];
|
|
59
|
+
var cachedDmFavorites = [];
|
|
60
|
+
var cachedDmConversations = [];
|
|
61
|
+
var dmRemovedUsers = {}; // { userId: true } - users explicitly removed from favorites
|
|
58
62
|
|
|
59
63
|
// --- Home Hub ---
|
|
60
64
|
var homeHub = $("home-hub");
|
|
@@ -562,6 +566,9 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
562
566
|
// Hide home hub if visible
|
|
563
567
|
hideHomeHub();
|
|
564
568
|
|
|
569
|
+
// Hide sticky notes if visible
|
|
570
|
+
hideNotes();
|
|
571
|
+
|
|
565
572
|
// Hide project UI + sidebar, show DM UI
|
|
566
573
|
var mainCol = document.getElementById("main-column");
|
|
567
574
|
if (mainCol) mainCol.classList.add("dm-mode");
|
|
@@ -821,12 +828,16 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
821
828
|
var projectHintDismiss = $("project-hint-dismiss");
|
|
822
829
|
var cachedProjects = [];
|
|
823
830
|
var cachedProjectCount = 0;
|
|
831
|
+
var cachedRemovedProjects = [];
|
|
824
832
|
var currentProjectOwnerId = null;
|
|
825
833
|
var currentSlug = slugMatch ? slugMatch[1] : null;
|
|
826
834
|
|
|
827
835
|
function updateProjectList(msg) {
|
|
828
836
|
if (typeof msg.projectCount === "number") cachedProjectCount = msg.projectCount;
|
|
829
837
|
if (msg.projects) cachedProjects = msg.projects;
|
|
838
|
+
if (msg.removedProjects) cachedRemovedProjects = msg.removedProjects;
|
|
839
|
+
else if (msg.removedProjects === undefined) { /* keep cached */ }
|
|
840
|
+
else cachedRemovedProjects = [];
|
|
830
841
|
var count = cachedProjectCount || 0;
|
|
831
842
|
renderProjectList();
|
|
832
843
|
if (count === 1 && projectHint) {
|
|
@@ -840,13 +851,19 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
840
851
|
}
|
|
841
852
|
// Update topbar with server-wide presence
|
|
842
853
|
if (msg.serverUsers) {
|
|
854
|
+
cachedOnlineIds = msg.serverUsers.map(function (u) { return u.id; });
|
|
843
855
|
renderTopbarPresence(msg.serverUsers);
|
|
856
|
+
// Re-render user strip online dots even without allUsers update
|
|
857
|
+
if (!msg.allUsers && cachedAllUsers.length > 0) {
|
|
858
|
+
renderUserStrip(cachedAllUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers);
|
|
859
|
+
}
|
|
844
860
|
}
|
|
845
861
|
// Update user strip (DM targets) in icon strip
|
|
846
862
|
if (msg.allUsers) {
|
|
847
863
|
cachedAllUsers = msg.allUsers;
|
|
848
|
-
|
|
849
|
-
|
|
864
|
+
if (msg.dmFavorites) cachedDmFavorites = msg.dmFavorites;
|
|
865
|
+
if (msg.dmConversations) cachedDmConversations = msg.dmConversations;
|
|
866
|
+
renderUserStrip(msg.allUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers);
|
|
850
867
|
// Render my avatar (always present, hidden behind user-island)
|
|
851
868
|
var meEl = document.getElementById("icon-strip-me");
|
|
852
869
|
if (meEl && !meEl.hasChildNodes()) {
|
|
@@ -885,7 +902,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
885
902
|
function renderProjectList() {
|
|
886
903
|
// Render icon strip projects
|
|
887
904
|
var iconStripProjects = cachedProjects.map(function (p) {
|
|
888
|
-
return { slug: p.slug, name: p.title || p.project, icon: p.icon || null, isProcessing: p.isProcessing, onlineUsers: p.onlineUsers || [] };
|
|
905
|
+
return { slug: p.slug, name: p.title || p.project, icon: p.icon || null, isProcessing: p.isProcessing, onlineUsers: p.onlineUsers || [], unread: p.unread || 0 };
|
|
889
906
|
});
|
|
890
907
|
renderIconStrip(iconStripProjects, currentSlug);
|
|
891
908
|
// Update title bar project name and icon if it changed
|
|
@@ -1225,6 +1242,8 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
1225
1242
|
get projectOwnerId() { return currentProjectOwnerId; },
|
|
1226
1243
|
openDm: function (userId) { openDm(userId); },
|
|
1227
1244
|
openAddProjectModal: function () { openAddProjectModal(); },
|
|
1245
|
+
sendWs: function (msg) { if (ws && ws.readyState === 1) ws.send(JSON.stringify(msg)); },
|
|
1246
|
+
onDmRemoveUser: function (userId) { dmRemovedUsers[userId] = true; },
|
|
1228
1247
|
};
|
|
1229
1248
|
initSidebar(sidebarCtx);
|
|
1230
1249
|
initIconStrip(sidebarCtx);
|
|
@@ -2498,18 +2517,34 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
2498
2517
|
guide.textContent = "When a login URL appears in the terminal, click it to open in your browser. Do not press 'c' as it will try to open the browser on the server.";
|
|
2499
2518
|
div.appendChild(guide);
|
|
2500
2519
|
|
|
2520
|
+
var sessionHint = document.createElement("div");
|
|
2521
|
+
sessionHint.className = "auth-required-guide";
|
|
2522
|
+
sessionHint.textContent = "After logging in, start a new session to continue.";
|
|
2523
|
+
div.appendChild(sessionHint);
|
|
2524
|
+
|
|
2501
2525
|
addToMessages(div);
|
|
2502
2526
|
scrollToBottom();
|
|
2503
2527
|
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2528
|
+
// Hide input area on this session since it cannot be used
|
|
2529
|
+
var inputArea = document.getElementById("input-area");
|
|
2530
|
+
if (inputArea) inputArea.classList.add("hidden");
|
|
2531
|
+
|
|
2532
|
+
// Only auto-open terminal on live events, not history replay
|
|
2533
|
+
if (!replayingHistory) {
|
|
2534
|
+
pendingTermCommand = "claude\n";
|
|
2535
|
+
ws.send(JSON.stringify({ type: "term_create", cols: 80, rows: 24 }));
|
|
2536
|
+
openTerminal();
|
|
2537
|
+
}
|
|
2507
2538
|
} else {
|
|
2508
2539
|
// Multi-user regular user: show message only, no auto-login
|
|
2509
2540
|
hint.textContent = "Please ask an administrator to log in to Claude Code.";
|
|
2510
2541
|
div.appendChild(hint);
|
|
2511
2542
|
addToMessages(div);
|
|
2512
2543
|
scrollToBottom();
|
|
2544
|
+
|
|
2545
|
+
inputEl.disabled = true;
|
|
2546
|
+
inputEl.placeholder = "Login required. Start a new session after logging in.";
|
|
2547
|
+
sendBtn.disabled = true;
|
|
2513
2548
|
}
|
|
2514
2549
|
}
|
|
2515
2550
|
|
|
@@ -2734,12 +2769,19 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
2734
2769
|
// --- Project switching (no full reload) ---
|
|
2735
2770
|
function switchProject(slug) {
|
|
2736
2771
|
if (!slug) return;
|
|
2772
|
+
var wasDm = dmMode;
|
|
2737
2773
|
if (dmMode) exitDmMode();
|
|
2738
2774
|
if (homeHubVisible) {
|
|
2739
2775
|
hideHomeHub();
|
|
2740
2776
|
if (slug === currentSlug) return;
|
|
2741
2777
|
}
|
|
2742
|
-
if (slug === currentSlug)
|
|
2778
|
+
if (slug === currentSlug) {
|
|
2779
|
+
// Returning from DM mode to the same project: re-switch to restore session
|
|
2780
|
+
if (wasDm && ws && ws.readyState === 1) {
|
|
2781
|
+
ws.send(JSON.stringify({ type: "switch_session", id: activeSessionId }));
|
|
2782
|
+
}
|
|
2783
|
+
return;
|
|
2784
|
+
}
|
|
2743
2785
|
resetFileBrowser();
|
|
2744
2786
|
closeArchive();
|
|
2745
2787
|
if (isSchedulerOpen()) closeScheduler();
|
|
@@ -3126,6 +3168,10 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
3126
3168
|
blinkSessionDot(msg.id);
|
|
3127
3169
|
break;
|
|
3128
3170
|
|
|
3171
|
+
case "session_unread":
|
|
3172
|
+
updateSessionBadge(msg.id, msg.count);
|
|
3173
|
+
break;
|
|
3174
|
+
|
|
3129
3175
|
case "search_results":
|
|
3130
3176
|
handleSearchResults(msg);
|
|
3131
3177
|
break;
|
|
@@ -3622,6 +3668,8 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
3622
3668
|
var fromId = msg.message.from;
|
|
3623
3669
|
if (fromId && fromId !== myUserId) {
|
|
3624
3670
|
dmUnread[fromId] = (dmUnread[fromId] || 0) + 1;
|
|
3671
|
+
// Re-render strip so non-favorited sender appears
|
|
3672
|
+
renderUserStrip(cachedAllUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers);
|
|
3625
3673
|
updateDmBadge(fromId, dmUnread[fromId]);
|
|
3626
3674
|
}
|
|
3627
3675
|
}
|
|
@@ -3637,6 +3685,25 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
3637
3685
|
// Could be used for DM list view later
|
|
3638
3686
|
break;
|
|
3639
3687
|
|
|
3688
|
+
case "dm_favorites_updated":
|
|
3689
|
+
// Track users explicitly removed from favorites
|
|
3690
|
+
if (cachedDmFavorites && msg.dmFavorites) {
|
|
3691
|
+
for (var ri = 0; ri < cachedDmFavorites.length; ri++) {
|
|
3692
|
+
if (msg.dmFavorites.indexOf(cachedDmFavorites[ri]) === -1) {
|
|
3693
|
+
dmRemovedUsers[cachedDmFavorites[ri]] = true;
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
// Clear removed flag for users being added back
|
|
3698
|
+
if (msg.dmFavorites) {
|
|
3699
|
+
for (var ai = 0; ai < msg.dmFavorites.length; ai++) {
|
|
3700
|
+
delete dmRemovedUsers[msg.dmFavorites[ai]];
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
cachedDmFavorites = msg.dmFavorites || [];
|
|
3704
|
+
renderUserStrip(cachedAllUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers);
|
|
3705
|
+
break;
|
|
3706
|
+
|
|
3640
3707
|
case "daemon_config":
|
|
3641
3708
|
updateDaemonConfig(msg.config);
|
|
3642
3709
|
break;
|
|
@@ -5022,12 +5089,20 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
5022
5089
|
// Project has tasks — show dialog with options
|
|
5023
5090
|
showRemoveProjectTaskDialog(slug, name, msg.count);
|
|
5024
5091
|
} else {
|
|
5025
|
-
// No tasks —
|
|
5026
|
-
showConfirm('Remove
|
|
5027
|
-
|
|
5028
|
-
|
|
5092
|
+
// No tasks — confirm then particle burst + remove
|
|
5093
|
+
showConfirm('Remove "' + name + '"? You can re-add it later.', function () {
|
|
5094
|
+
// Find the icon strip item to anchor the particle burst
|
|
5095
|
+
var iconEl = document.querySelector('.icon-strip-item[data-slug="' + slug + '"]');
|
|
5096
|
+
if (iconEl) {
|
|
5097
|
+
var rect = iconEl.getBoundingClientRect();
|
|
5098
|
+
spawnDustParticles(rect.left + rect.width / 2, rect.top + rect.height / 2);
|
|
5029
5099
|
}
|
|
5030
|
-
|
|
5100
|
+
setTimeout(function () {
|
|
5101
|
+
if (ws && ws.readyState === 1) {
|
|
5102
|
+
ws.send(JSON.stringify({ type: "remove_project", slug: slug }));
|
|
5103
|
+
}
|
|
5104
|
+
}, 1000);
|
|
5105
|
+
}, "Remove", true);
|
|
5031
5106
|
}
|
|
5032
5107
|
pendingRemoveSlug = null;
|
|
5033
5108
|
pendingRemoveName = null;
|
|
@@ -5092,9 +5167,33 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
5092
5167
|
function handleRemoveProjectResult(msg) {
|
|
5093
5168
|
if (msg.ok) {
|
|
5094
5169
|
showToast("Project removed", "success");
|
|
5095
|
-
// If we removed the current project,
|
|
5170
|
+
// If we removed the current project, go to home hub without full reload
|
|
5096
5171
|
if (msg.slug === currentSlug) {
|
|
5097
|
-
|
|
5172
|
+
// Suppress disconnect overlay and reconnect by detaching the WS
|
|
5173
|
+
if (ws) { ws.onclose = null; ws.onerror = null; ws.close(); ws = null; }
|
|
5174
|
+
if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
|
|
5175
|
+
connected = false;
|
|
5176
|
+
connectOverlay.classList.add("hidden");
|
|
5177
|
+
// Add to cached removed projects for re-add UI
|
|
5178
|
+
var removedProj = null;
|
|
5179
|
+
for (var ri = 0; ri < cachedProjects.length; ri++) {
|
|
5180
|
+
if (cachedProjects[ri].slug === msg.slug) { removedProj = cachedProjects[ri]; break; }
|
|
5181
|
+
}
|
|
5182
|
+
if (removedProj) {
|
|
5183
|
+
cachedRemovedProjects.push({
|
|
5184
|
+
path: removedProj.path || "",
|
|
5185
|
+
title: removedProj.title || null,
|
|
5186
|
+
icon: removedProj.icon || null,
|
|
5187
|
+
removedAt: Date.now(),
|
|
5188
|
+
});
|
|
5189
|
+
}
|
|
5190
|
+
// Remove from cached projects and re-render icon strip
|
|
5191
|
+
cachedProjects = cachedProjects.filter(function (p) { return p.slug !== msg.slug; });
|
|
5192
|
+
cachedProjectCount = cachedProjects.length;
|
|
5193
|
+
currentSlug = null;
|
|
5194
|
+
renderProjectList();
|
|
5195
|
+
resetClientState();
|
|
5196
|
+
showHomeHub();
|
|
5098
5197
|
}
|
|
5099
5198
|
} else {
|
|
5100
5199
|
showToast(msg.error || "Failed to remove project", "error");
|
|
@@ -5113,6 +5212,7 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
5113
5212
|
var addProjectCancel = document.getElementById("add-project-cancel");
|
|
5114
5213
|
var addProjectModeBtns = addProjectModal.querySelectorAll(".add-project-mode-btn");
|
|
5115
5214
|
var addProjectPanels = addProjectModal.querySelectorAll(".add-project-panel");
|
|
5215
|
+
var addProjectRemoved = document.getElementById("add-project-removed");
|
|
5116
5216
|
var addProjectDebounce = null;
|
|
5117
5217
|
var addProjectActiveIdx = -1;
|
|
5118
5218
|
var addProjectMode = "existing";
|
|
@@ -5185,6 +5285,48 @@ import { initAdmin, checkAdminAccess } from './modules/admin.js';
|
|
|
5185
5285
|
existingBtn.disabled = false;
|
|
5186
5286
|
switchAddProjectMode("existing");
|
|
5187
5287
|
}
|
|
5288
|
+
// Render removed projects for re-add
|
|
5289
|
+
renderRemovedProjectsList();
|
|
5290
|
+
}
|
|
5291
|
+
|
|
5292
|
+
function renderRemovedProjectsList() {
|
|
5293
|
+
if (!addProjectRemoved) return;
|
|
5294
|
+
addProjectRemoved.innerHTML = "";
|
|
5295
|
+
if (!cachedRemovedProjects || cachedRemovedProjects.length === 0) {
|
|
5296
|
+
addProjectRemoved.classList.add("hidden");
|
|
5297
|
+
return;
|
|
5298
|
+
}
|
|
5299
|
+
addProjectRemoved.classList.remove("hidden");
|
|
5300
|
+
for (var ri = 0; ri < cachedRemovedProjects.length; ri++) {
|
|
5301
|
+
var rp = cachedRemovedProjects[ri];
|
|
5302
|
+
var item = document.createElement("div");
|
|
5303
|
+
item.className = "add-project-removed-item";
|
|
5304
|
+
item.dataset.path = rp.path;
|
|
5305
|
+
item.addEventListener("click", function () {
|
|
5306
|
+
var p = this.dataset.path;
|
|
5307
|
+
if (ws && ws.readyState === 1) {
|
|
5308
|
+
ws.send(JSON.stringify({ type: "add_project", path: p }));
|
|
5309
|
+
}
|
|
5310
|
+
closeAddProjectModal();
|
|
5311
|
+
});
|
|
5312
|
+
var iconEl = document.createElement("span");
|
|
5313
|
+
iconEl.className = "add-project-removed-icon";
|
|
5314
|
+
iconEl.textContent = rp.icon || "📁";
|
|
5315
|
+
item.appendChild(iconEl);
|
|
5316
|
+
var info = document.createElement("div");
|
|
5317
|
+
info.className = "add-project-removed-info";
|
|
5318
|
+
var nameEl = document.createElement("div");
|
|
5319
|
+
nameEl.className = "add-project-removed-name";
|
|
5320
|
+
nameEl.textContent = rp.title || rp.path.split("/").pop() || rp.path;
|
|
5321
|
+
info.appendChild(nameEl);
|
|
5322
|
+
var pathEl = document.createElement("div");
|
|
5323
|
+
pathEl.className = "add-project-removed-path";
|
|
5324
|
+
pathEl.textContent = rp.path;
|
|
5325
|
+
info.appendChild(pathEl);
|
|
5326
|
+
item.appendChild(info);
|
|
5327
|
+
addProjectRemoved.appendChild(item);
|
|
5328
|
+
}
|
|
5329
|
+
try { parseEmojis(addProjectRemoved); } catch (e) {}
|
|
5188
5330
|
}
|
|
5189
5331
|
|
|
5190
5332
|
function closeAddProjectModal() {
|
|
@@ -895,6 +895,7 @@
|
|
|
895
895
|
width: 50%;
|
|
896
896
|
max-width: 720px;
|
|
897
897
|
min-width: 360px;
|
|
898
|
+
min-height: 0;
|
|
898
899
|
border-left: 1px solid var(--border);
|
|
899
900
|
background: var(--bg);
|
|
900
901
|
display: flex;
|
|
@@ -1382,6 +1383,11 @@
|
|
|
1382
1383
|
justify-content: space-between;
|
|
1383
1384
|
padding: 10px 16px;
|
|
1384
1385
|
flex-shrink: 0;
|
|
1386
|
+
position: sticky;
|
|
1387
|
+
top: 0;
|
|
1388
|
+
z-index: 10;
|
|
1389
|
+
background: var(--bg);
|
|
1390
|
+
border-bottom: 1px solid var(--border);
|
|
1385
1391
|
}
|
|
1386
1392
|
|
|
1387
1393
|
.file-history-view-toggle {
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
position: absolute;
|
|
72
72
|
left: -12px;
|
|
73
73
|
width: 4px;
|
|
74
|
-
background:
|
|
74
|
+
background: var(--text);
|
|
75
75
|
border-radius: 0 4px 4px 0;
|
|
76
76
|
transition: height 0.2s ease, opacity 0.2s ease;
|
|
77
77
|
opacity: 0;
|
|
@@ -730,6 +730,32 @@
|
|
|
730
730
|
display: flex;
|
|
731
731
|
}
|
|
732
732
|
|
|
733
|
+
/* Project unread badge */
|
|
734
|
+
.icon-strip-project-badge {
|
|
735
|
+
position: absolute;
|
|
736
|
+
top: -2px;
|
|
737
|
+
right: -2px;
|
|
738
|
+
min-width: 18px;
|
|
739
|
+
height: 18px;
|
|
740
|
+
border-radius: 9px;
|
|
741
|
+
background: #e74c3c;
|
|
742
|
+
color: #fff;
|
|
743
|
+
font-size: 11px;
|
|
744
|
+
font-weight: 700;
|
|
745
|
+
display: none;
|
|
746
|
+
align-items: center;
|
|
747
|
+
justify-content: center;
|
|
748
|
+
padding: 0 5px;
|
|
749
|
+
line-height: 18px;
|
|
750
|
+
text-align: center;
|
|
751
|
+
box-shadow: 0 0 0 2px var(--bg);
|
|
752
|
+
z-index: 2;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.icon-strip-project-badge.has-unread {
|
|
756
|
+
display: flex;
|
|
757
|
+
}
|
|
758
|
+
|
|
733
759
|
/* Pill for user icons */
|
|
734
760
|
.icon-strip-user:hover .icon-strip-pill {
|
|
735
761
|
opacity: 1;
|
|
@@ -766,6 +792,102 @@
|
|
|
766
792
|
object-fit: cover;
|
|
767
793
|
}
|
|
768
794
|
|
|
795
|
+
/* --- DM user picker popup --- */
|
|
796
|
+
.dm-user-picker {
|
|
797
|
+
position: fixed;
|
|
798
|
+
background: var(--sidebar-bg);
|
|
799
|
+
border: 1px solid var(--border);
|
|
800
|
+
border-radius: 12px;
|
|
801
|
+
padding: 8px;
|
|
802
|
+
width: 220px;
|
|
803
|
+
box-shadow: 0 8px 24px rgba(var(--shadow-rgb), 0.5);
|
|
804
|
+
z-index: 10001;
|
|
805
|
+
animation: ctxMenuAppear 0.15s ease-out;
|
|
806
|
+
display: flex;
|
|
807
|
+
flex-direction: column;
|
|
808
|
+
gap: 4px;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
.dm-user-picker-search {
|
|
812
|
+
width: 100%;
|
|
813
|
+
padding: 7px 10px;
|
|
814
|
+
border: 1px solid var(--border);
|
|
815
|
+
border-radius: 8px;
|
|
816
|
+
background: var(--bg-alt);
|
|
817
|
+
color: var(--text);
|
|
818
|
+
font-size: 13px;
|
|
819
|
+
font-family: inherit;
|
|
820
|
+
outline: none;
|
|
821
|
+
box-sizing: border-box;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.dm-user-picker-search:focus {
|
|
825
|
+
border-color: var(--accent);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
.dm-user-picker-search::placeholder {
|
|
829
|
+
color: var(--text-dimmer);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
.dm-user-picker-list {
|
|
833
|
+
max-height: 200px;
|
|
834
|
+
overflow-y: auto;
|
|
835
|
+
overflow-x: hidden;
|
|
836
|
+
scrollbar-width: thin;
|
|
837
|
+
scrollbar-color: var(--border) transparent;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.dm-user-picker-list::-webkit-scrollbar {
|
|
841
|
+
width: 4px;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.dm-user-picker-list::-webkit-scrollbar-track {
|
|
845
|
+
background: transparent;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.dm-user-picker-list::-webkit-scrollbar-thumb {
|
|
849
|
+
background: var(--border);
|
|
850
|
+
border-radius: 2px;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
.dm-user-picker-item {
|
|
854
|
+
display: flex;
|
|
855
|
+
align-items: center;
|
|
856
|
+
gap: 8px;
|
|
857
|
+
padding: 6px 8px;
|
|
858
|
+
border-radius: 8px;
|
|
859
|
+
cursor: pointer;
|
|
860
|
+
transition: background 0.15s;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.dm-user-picker-item:hover {
|
|
864
|
+
background: rgba(var(--overlay-rgb), 0.08);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
.dm-user-picker-avatar {
|
|
868
|
+
width: 28px;
|
|
869
|
+
height: 28px;
|
|
870
|
+
border-radius: 50%;
|
|
871
|
+
object-fit: cover;
|
|
872
|
+
flex-shrink: 0;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.dm-user-picker-name {
|
|
876
|
+
font-size: 13px;
|
|
877
|
+
font-weight: 500;
|
|
878
|
+
color: var(--text);
|
|
879
|
+
white-space: nowrap;
|
|
880
|
+
overflow: hidden;
|
|
881
|
+
text-overflow: ellipsis;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
.dm-user-picker-empty {
|
|
885
|
+
padding: 12px 8px;
|
|
886
|
+
font-size: 13px;
|
|
887
|
+
color: var(--text-dimmer);
|
|
888
|
+
text-align: center;
|
|
889
|
+
}
|
|
890
|
+
|
|
769
891
|
/* --- Per-project presence avatars --- */
|
|
770
892
|
/* --- Mobile: hide icon strip --- */
|
|
771
893
|
@media (max-width: 768px) {
|
|
@@ -1472,7 +1472,7 @@ pre.mermaid-error {
|
|
|
1472
1472
|
========================================================================== */
|
|
1473
1473
|
|
|
1474
1474
|
.auth-required-msg {
|
|
1475
|
-
max-width:
|
|
1475
|
+
max-width: 420px;
|
|
1476
1476
|
margin: 12px auto;
|
|
1477
1477
|
padding: 14px 18px;
|
|
1478
1478
|
background: color-mix(in srgb, var(--warning) 8%, var(--bg));
|
|
@@ -181,6 +181,23 @@
|
|
|
181
181
|
flex-shrink: 0;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
.mobile-project-unread {
|
|
185
|
+
min-width: 18px;
|
|
186
|
+
height: 18px;
|
|
187
|
+
border-radius: 9px;
|
|
188
|
+
background: #e74c3c;
|
|
189
|
+
color: #fff;
|
|
190
|
+
font-size: 11px;
|
|
191
|
+
font-weight: 700;
|
|
192
|
+
display: flex;
|
|
193
|
+
align-items: center;
|
|
194
|
+
justify-content: center;
|
|
195
|
+
padding: 0 5px;
|
|
196
|
+
line-height: 18px;
|
|
197
|
+
flex-shrink: 0;
|
|
198
|
+
margin-left: auto;
|
|
199
|
+
}
|
|
200
|
+
|
|
184
201
|
/* ==========================================================================
|
|
185
202
|
Mobile Sheet — fullscreen overlay for Projects / Sessions
|
|
186
203
|
========================================================================== */
|
|
@@ -905,6 +905,55 @@ button.top-bar-pill.pill-accent:hover { background: color-mix(in srgb, var(--acc
|
|
|
905
905
|
.add-project-panel { display: none; }
|
|
906
906
|
.add-project-panel.active { display: block; }
|
|
907
907
|
|
|
908
|
+
/* Removed projects list in add project modal */
|
|
909
|
+
#add-project-removed { margin-bottom: 14px; padding-bottom: 14px; border-bottom: 1px solid var(--border); }
|
|
910
|
+
#add-project-removed.hidden { display: none; }
|
|
911
|
+
.add-project-removed-item {
|
|
912
|
+
display: flex;
|
|
913
|
+
align-items: center;
|
|
914
|
+
gap: 10px;
|
|
915
|
+
padding: 7px 8px;
|
|
916
|
+
border-radius: 8px;
|
|
917
|
+
margin-bottom: 2px;
|
|
918
|
+
cursor: pointer;
|
|
919
|
+
transition: background 0.15s;
|
|
920
|
+
}
|
|
921
|
+
.add-project-removed-item:last-child { margin-bottom: 0; }
|
|
922
|
+
.add-project-removed-item:hover { background: var(--sidebar-hover); }
|
|
923
|
+
.add-project-removed-icon {
|
|
924
|
+
flex-shrink: 0;
|
|
925
|
+
width: 28px;
|
|
926
|
+
height: 28px;
|
|
927
|
+
display: flex;
|
|
928
|
+
align-items: center;
|
|
929
|
+
justify-content: center;
|
|
930
|
+
border-radius: 6px;
|
|
931
|
+
background: var(--sidebar-hover);
|
|
932
|
+
font-size: 14px;
|
|
933
|
+
}
|
|
934
|
+
.add-project-removed-info {
|
|
935
|
+
flex: 1;
|
|
936
|
+
min-width: 0;
|
|
937
|
+
overflow: hidden;
|
|
938
|
+
}
|
|
939
|
+
.add-project-removed-name {
|
|
940
|
+
font-weight: 500;
|
|
941
|
+
color: var(--text);
|
|
942
|
+
white-space: nowrap;
|
|
943
|
+
overflow: hidden;
|
|
944
|
+
text-overflow: ellipsis;
|
|
945
|
+
font-size: 13px;
|
|
946
|
+
line-height: 1.3;
|
|
947
|
+
}
|
|
948
|
+
.add-project-removed-path {
|
|
949
|
+
font-size: 11px;
|
|
950
|
+
color: var(--text-muted);
|
|
951
|
+
white-space: nowrap;
|
|
952
|
+
overflow: hidden;
|
|
953
|
+
text-overflow: ellipsis;
|
|
954
|
+
line-height: 1.3;
|
|
955
|
+
}
|
|
956
|
+
|
|
908
957
|
#add-project-create-input,
|
|
909
958
|
#add-project-clone-input {
|
|
910
959
|
width: 100%;
|
|
@@ -489,6 +489,32 @@
|
|
|
489
489
|
box-shadow: 0 0 4px var(--success);
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
+
/* Session unread badge */
|
|
493
|
+
.session-unread-badge {
|
|
494
|
+
position: absolute;
|
|
495
|
+
right: 32px;
|
|
496
|
+
top: 50%;
|
|
497
|
+
transform: translateY(-50%);
|
|
498
|
+
min-width: 18px;
|
|
499
|
+
height: 18px;
|
|
500
|
+
border-radius: 9px;
|
|
501
|
+
background: #e74c3c;
|
|
502
|
+
color: #fff;
|
|
503
|
+
font-size: 11px;
|
|
504
|
+
font-weight: 700;
|
|
505
|
+
display: none;
|
|
506
|
+
align-items: center;
|
|
507
|
+
justify-content: center;
|
|
508
|
+
padding: 0 5px;
|
|
509
|
+
line-height: 18px;
|
|
510
|
+
text-align: center;
|
|
511
|
+
z-index: 2;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.session-unread-badge.has-unread {
|
|
515
|
+
display: flex;
|
|
516
|
+
}
|
|
517
|
+
|
|
492
518
|
.session-more-btn {
|
|
493
519
|
position: absolute;
|
|
494
520
|
right: 8px;
|
|
@@ -313,11 +313,14 @@
|
|
|
313
313
|
min-width: unset;
|
|
314
314
|
height: auto !important;
|
|
315
315
|
width: auto !important;
|
|
316
|
+
max-width: 200px;
|
|
316
317
|
}
|
|
317
318
|
|
|
318
319
|
.sticky-note.minimized .sticky-note-spacer {
|
|
319
320
|
color: inherit;
|
|
320
321
|
opacity: 1;
|
|
322
|
+
overflow: hidden;
|
|
323
|
+
text-overflow: ellipsis;
|
|
321
324
|
}
|
|
322
325
|
|
|
323
326
|
.sticky-note.minimized .sticky-note-header button {
|
package/lib/public/index.html
CHANGED
|
@@ -1112,6 +1112,7 @@
|
|
|
1112
1112
|
<div class="confirm-backdrop"></div>
|
|
1113
1113
|
<div class="confirm-dialog add-project-dialog">
|
|
1114
1114
|
<div class="add-project-title">Add project</div>
|
|
1115
|
+
<div id="add-project-removed" class="hidden"></div>
|
|
1115
1116
|
<div class="add-project-modes">
|
|
1116
1117
|
<button class="add-project-mode-btn active" data-mode="existing">Existing directory</button>
|
|
1117
1118
|
<button class="add-project-mode-btn" data-mode="create">New project</button>
|
|
@@ -1488,6 +1489,7 @@
|
|
|
1488
1489
|
<script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js"></script>
|
|
1489
1490
|
<script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5/lib/xterm.min.js"></script>
|
|
1490
1491
|
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0/lib/addon-fit.min.js"></script>
|
|
1492
|
+
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-web-links@0/lib/addon-web-links.min.js"></script>
|
|
1491
1493
|
<script type="module" src="app.js"></script>
|
|
1492
1494
|
<div id="pwa-install-modal" class="pwa-modal hidden">
|
|
1493
1495
|
<div class="pwa-modal-backdrop"></div>
|