clay-server 2.26.0-beta.8 → 2.26.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/lib/browser-mcp-server.js +4 -4
- package/lib/daemon.js +1 -1
- package/lib/debate-mcp-server.js +94 -0
- package/lib/mates.js +12 -24
- package/lib/project-debate.js +304 -166
- package/lib/project-mate-interaction.js +10 -5
- package/lib/project.js +128 -39
- package/lib/public/app.js +452 -127
- package/lib/public/css/debate.css +230 -2
- package/lib/public/css/filebrowser.css +41 -4
- package/lib/public/css/icon-strip.css +10 -10
- package/lib/public/css/input.css +107 -19
- package/lib/public/css/mates.css +56 -57
- package/lib/public/css/mention.css +7 -4
- package/lib/public/css/messages.css +17 -0
- package/lib/public/css/mobile-nav.css +3 -1
- package/lib/public/css/rewind.css +17 -4
- package/lib/public/index.html +23 -15
- package/lib/public/modules/context-sources.js +21 -6
- package/lib/public/modules/debate.js +298 -97
- package/lib/public/modules/input.js +18 -1
- package/lib/public/modules/mate-knowledge.js +11 -11
- package/lib/public/modules/mate-memory.js +5 -5
- package/lib/public/modules/mate-sidebar.js +13 -9
- package/lib/public/modules/mention.js +40 -2
- package/lib/public/modules/sidebar.js +105 -26
- package/lib/public/modules/terminal.js +62 -6
- package/lib/public/modules/theme.js +2 -1
- package/lib/public/modules/tools.js +47 -23
- package/lib/sdk-bridge.js +134 -21
- package/lib/sessions.js +2 -2
- package/package.json +1 -1
package/lib/public/app.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { avatarUrl, userAvatarUrl, mateAvatarUrl } from './modules/avatar.js';
|
|
2
2
|
import { showToast, copyToClipboard, escapeHtml } from './modules/utils.js';
|
|
3
|
-
import { refreshIcons, iconHtml
|
|
3
|
+
import { refreshIcons, iconHtml } from './modules/icons.js';
|
|
4
4
|
import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks, closeMermaidModal, parseEmojis } from './modules/markdown.js';
|
|
5
|
-
import { initSidebar, renderSessionList, handleSearchResults, updateSessionPresence, updatePageTitle, populateCliSessionList, renderIconStrip, renderSidebarPresence, initIconStrip, getEmojiCategories, renderUserStrip, setCurrentDmUser, updateDmBadge, updateSessionBadge, updateProjectBadge, closeDmUserPicker, spawnDustParticles, openMobileSheet, setMobileSheetMateData } from './modules/sidebar.js';
|
|
5
|
+
import { initSidebar, renderSessionList, handleSearchResults, updateSessionPresence, updatePageTitle, populateCliSessionList, renderIconStrip, renderSidebarPresence, initIconStrip, getEmojiCategories, renderUserStrip, setCurrentDmUser, updateDmBadge, updateSessionBadge, updateProjectBadge, closeDmUserPicker, spawnDustParticles, openMobileSheet, setMobileSheetMateData, refreshMobileChatSheet } from './modules/sidebar.js';
|
|
6
6
|
import { initMateSidebar, showMateSidebar, hideMateSidebar, renderMateSessionList, updateMateSidebarProfile, handleMateSearchResults } from './modules/mate-sidebar.js';
|
|
7
7
|
import { initMateKnowledge, requestKnowledgeList, renderKnowledgeList, handleKnowledgeContent, hideKnowledge } from './modules/mate-knowledge.js';
|
|
8
8
|
import { initMateMemory, renderMemoryList, hideMemory } from './modules/mate-memory.js';
|
|
@@ -14,7 +14,7 @@ import { initFileBrowser, loadRootDirectory, refreshTree, handleFsList, handleFs
|
|
|
14
14
|
import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
|
|
15
15
|
import { initContextSources, updateTerminalList, updateBrowserTabList, handleContextSourcesState, getActiveSources, hasActiveSources } from './modules/context-sources.js';
|
|
16
16
|
import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, openArchive, closeArchive, isArchiveOpen, hideNotes, showNotes, isNotesVisible } from './modules/sticky-notes.js';
|
|
17
|
-
import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme } from './modules/theme.js';
|
|
17
|
+
import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme, getChatLayout } from './modules/theme.js';
|
|
18
18
|
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, resetTurnMetaCost, enableMainInput, getTools, getPlanContent, setPlanContent, isPlanFilePath, getTodoTools, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, updateSubagentProgress, initSubagentStop, closeToolGroup, removeToolFromGroup } from './modules/tools.js';
|
|
19
19
|
import { initServerSettings, updateSettingsStats, updateSettingsModels, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleAutoContinueChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved, handleGlobalClaudeMdRead, handleGlobalClaudeMdWrite } from './modules/server-settings.js';
|
|
20
20
|
import { initProjectSettings, handleInstructionsRead, handleInstructionsWrite, handleProjectEnv, handleProjectEnvSaved, isProjectSettingsOpen, handleProjectSharedEnv, handleProjectSharedEnvSaved, handleProjectOwnerChanged } from './modules/project-settings.js';
|
|
@@ -32,7 +32,7 @@ import { initMateWizard, openMateWizard, closeMateWizard, handleMateCreated } fr
|
|
|
32
32
|
import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } from './modules/command-palette.js';
|
|
33
33
|
import { initLongPress } from './modules/longpress.js';
|
|
34
34
|
import { initMention, handleMentionStart, handleMentionStream, handleMentionDone, handleMentionError, handleMentionActivity, renderMentionUser, renderMentionResponse } from './modules/mention.js';
|
|
35
|
-
import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateResumed, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, handleDebateEnded, handleDebateError, renderDebateStarted, renderDebateTurnDone, renderDebateEnded, renderDebateCommentInjected, renderDebateUserResume, openDebateModal, closeDebateModal, handleDebateBriefReady, renderDebateBriefReady, isDebateActive, resetDebateState } from './modules/debate.js';
|
|
35
|
+
import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateResumed, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, handleDebateEnded, handleDebateError, renderDebateStarted, renderDebateTurnDone, renderDebateEnded, renderDebateCommentInjected, renderDebateUserResume, openDebateModal, closeDebateModal, handleDebateBriefReady, renderDebateBriefReady, isDebateActive, resetDebateState, exportDebateAsPdf, renderMcpDebateProposal } from './modules/debate.js';
|
|
36
36
|
|
|
37
37
|
// --- Base path for multi-project routing ---
|
|
38
38
|
var slugMatch = location.pathname.match(/^\/p\/([a-z0-9_-]+)/);
|
|
@@ -565,6 +565,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
565
565
|
// --- DM Mode Functions ---
|
|
566
566
|
function openDm(targetUserId) {
|
|
567
567
|
if (!ws || ws.readyState !== 1) return;
|
|
568
|
+
// Persist DM state for refresh recovery
|
|
569
|
+
try { localStorage.setItem("clay-active-dm", targetUserId); } catch (e) {}
|
|
568
570
|
// Check mate skill updates before opening mate DM
|
|
569
571
|
if (typeof targetUserId === "string" && targetUserId.indexOf("mate_") === 0) {
|
|
570
572
|
showMateOnboarding(function () {
|
|
@@ -816,6 +818,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
816
818
|
dmMode = false;
|
|
817
819
|
dmKey = null;
|
|
818
820
|
dmTargetUser = null;
|
|
821
|
+
try { localStorage.removeItem("clay-active-dm"); } catch (e) {}
|
|
819
822
|
setCurrentDmUser(null);
|
|
820
823
|
|
|
821
824
|
var mainCol = document.getElementById("main-column");
|
|
@@ -1798,9 +1801,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1798
1801
|
};
|
|
1799
1802
|
initSidebar(sidebarCtx);
|
|
1800
1803
|
initIconStrip(sidebarCtx);
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
+
var wsGetter = function () { return ws; };
|
|
1805
|
+
initMateSidebar(wsGetter);
|
|
1806
|
+
initMateKnowledge(wsGetter);
|
|
1807
|
+
initMateMemory(wsGetter, { onShow: function () { hideKnowledge(); hideNotes(); } });
|
|
1804
1808
|
initMateWizard(
|
|
1805
1809
|
function (msg) { if (ws && ws.readyState === 1) ws.send(JSON.stringify(msg)); },
|
|
1806
1810
|
function (mate) { handleMateCreatedInApp(mate); }
|
|
@@ -2083,12 +2087,9 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
2083
2087
|
activityEl = document.createElement("div");
|
|
2084
2088
|
activityEl.className = "activity-inline";
|
|
2085
2089
|
activityEl.innerHTML =
|
|
2086
|
-
'<
|
|
2087
|
-
'<span class="activity-text"></span>';
|
|
2090
|
+
'<div class="mate-thinking-dots"><span></span><span></span><span></span></div>';
|
|
2088
2091
|
addToMessages(activityEl);
|
|
2089
|
-
refreshIcons();
|
|
2090
2092
|
}
|
|
2091
|
-
activityEl.querySelector(".activity-text").textContent = text;
|
|
2092
2093
|
scrollToBottom();
|
|
2093
2094
|
} else {
|
|
2094
2095
|
if (activityEl) {
|
|
@@ -2098,9 +2099,14 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
2098
2099
|
}
|
|
2099
2100
|
}
|
|
2100
2101
|
|
|
2101
|
-
// ---
|
|
2102
|
+
// --- Pre-thinking (instant dots before server responds) ---
|
|
2102
2103
|
var matePreThinkingEl = null;
|
|
2103
2104
|
var matePreThinkingTimer = null;
|
|
2105
|
+
function showClaudePreThinking() {
|
|
2106
|
+
if (getChatLayout() !== "channel") return;
|
|
2107
|
+
var claudeAvatar = CLAUDE_CODE_AVATAR;
|
|
2108
|
+
doShowMatePreThinking("Claude Code", claudeAvatar);
|
|
2109
|
+
}
|
|
2104
2110
|
function showMatePreThinking() {
|
|
2105
2111
|
removeMatePreThinking();
|
|
2106
2112
|
var mateName = dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate";
|
|
@@ -2114,10 +2120,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
2114
2120
|
'<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' + escapeHtml(mateAvatar) + '" alt="" style="display:block">' +
|
|
2115
2121
|
'<div class="dm-bubble-content">' +
|
|
2116
2122
|
'<div class="dm-bubble-header"><span class="dm-bubble-name">' + escapeHtml(mateName) + '</span></div>' +
|
|
2117
|
-
'<div class="
|
|
2118
|
-
'<span class="activity-icon">' + iconHtml("sparkles") + '</span>' +
|
|
2119
|
-
'<span class="activity-text">' + randomThinkingVerb() + '...</span>' +
|
|
2120
|
-
'</div>' +
|
|
2123
|
+
'<div class="mate-thinking-dots"><span></span><span></span><span></span></div>' +
|
|
2121
2124
|
'</div>';
|
|
2122
2125
|
if (activityEl && activityEl.parentNode) {
|
|
2123
2126
|
activityEl.parentNode.insertBefore(matePreThinkingEl, activityEl);
|
|
@@ -3020,6 +3023,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3020
3023
|
isMateDm: function () { return dmMode && dmTargetUser && dmTargetUser.isMate; },
|
|
3021
3024
|
getMateName: function () { return dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate"; },
|
|
3022
3025
|
getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
|
|
3026
|
+
getClaudeAvatar: function () { return CLAUDE_CODE_AVATAR; },
|
|
3023
3027
|
getMateById: function (id) {
|
|
3024
3028
|
if (!id || !cachedMatesList) return null;
|
|
3025
3029
|
for (var i = 0; i < cachedMatesList.length; i++) {
|
|
@@ -3040,6 +3044,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3040
3044
|
var div = document.createElement("div");
|
|
3041
3045
|
div.className = "msg-user" + (isOtherUser ? " msg-user-other" : "");
|
|
3042
3046
|
div.dataset.turn = ++turnCounter;
|
|
3047
|
+
if (shouldGroupMessage("msg-user")) div.classList.add("grouped");
|
|
3043
3048
|
var bubble = document.createElement("div");
|
|
3044
3049
|
bubble.className = "bubble";
|
|
3045
3050
|
bubble.dir = "auto";
|
|
@@ -3130,8 +3135,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3130
3135
|
header.appendChild(nameSpan);
|
|
3131
3136
|
var timeSpan = document.createElement("span");
|
|
3132
3137
|
timeSpan.className = "dm-bubble-time";
|
|
3133
|
-
|
|
3134
|
-
timeSpan.textContent = String(nowH.getHours()).padStart(2, "0") + ":" + String(nowH.getMinutes()).padStart(2, "0");
|
|
3138
|
+
timeSpan.textContent = getMsgTime();
|
|
3135
3139
|
header.appendChild(timeSpan);
|
|
3136
3140
|
contentWrap.appendChild(header);
|
|
3137
3141
|
contentWrap.appendChild(bubble);
|
|
@@ -3140,10 +3144,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3140
3144
|
// Action bar below bubble (icons visible on hover)
|
|
3141
3145
|
var actions = document.createElement("div");
|
|
3142
3146
|
actions.className = "msg-actions";
|
|
3143
|
-
var now = new Date();
|
|
3144
|
-
var timeStr = String(now.getHours()).padStart(2, "0") + ":" + String(now.getMinutes()).padStart(2, "0");
|
|
3145
3147
|
actions.innerHTML =
|
|
3146
|
-
'<span class="msg-action-time">' +
|
|
3148
|
+
'<span class="msg-action-time">' + getMsgTime() + '</span>' +
|
|
3147
3149
|
'<button class="msg-action-btn msg-action-copy" type="button" title="Copy">' + iconHtml("copy") + '</button>' +
|
|
3148
3150
|
'<button class="msg-action-btn msg-action-fork" type="button" title="Fork">' + iconHtml("git-branch") + '</button>' +
|
|
3149
3151
|
'<button class="msg-action-btn msg-action-rewind msg-user-rewind-btn" type="button" title="Rewind">' + iconHtml("rotate-ccw") + '</button>' +
|
|
@@ -3164,11 +3166,33 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3164
3166
|
forceScrollToBottom();
|
|
3165
3167
|
}
|
|
3166
3168
|
|
|
3169
|
+
// Track the timestamp of the current message being processed (from history _ts or now)
|
|
3170
|
+
var currentMsgTs = null;
|
|
3171
|
+
|
|
3172
|
+
function getMsgTime() {
|
|
3173
|
+
var d = currentMsgTs ? new Date(currentMsgTs) : new Date();
|
|
3174
|
+
return String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
|
|
3175
|
+
}
|
|
3176
|
+
|
|
3177
|
+
function shouldGroupMessage(senderClass) {
|
|
3178
|
+
// Skip grouping during history replay if no timestamp data
|
|
3179
|
+
if (replayingHistory && !currentMsgTs) return false;
|
|
3180
|
+
var prev = messagesEl.lastElementChild;
|
|
3181
|
+
if (!prev || !prev.classList.contains(senderClass)) return false;
|
|
3182
|
+
var prevTime = prev.querySelector(".dm-bubble-time");
|
|
3183
|
+
if (!prevTime) return false;
|
|
3184
|
+
return prevTime.textContent === getMsgTime();
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3167
3187
|
function ensureAssistantBlock() {
|
|
3168
3188
|
if (!currentMsgEl) {
|
|
3169
3189
|
currentMsgEl = document.createElement("div");
|
|
3170
3190
|
currentMsgEl.className = "msg-assistant";
|
|
3171
3191
|
currentMsgEl.dataset.turn = turnCounter;
|
|
3192
|
+
|
|
3193
|
+
var grouped = shouldGroupMessage("msg-assistant");
|
|
3194
|
+
if (grouped) currentMsgEl.classList.add("grouped");
|
|
3195
|
+
|
|
3172
3196
|
// Always render avatar + header structure (CSS controls visibility)
|
|
3173
3197
|
var _isDm2 = document.body.classList.contains("mate-dm-active") && document.body.dataset.mateAvatarUrl;
|
|
3174
3198
|
var avi = document.createElement("img");
|
|
@@ -3187,8 +3211,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3187
3211
|
header.appendChild(nameSpan);
|
|
3188
3212
|
var timeSpan = document.createElement("span");
|
|
3189
3213
|
timeSpan.className = "dm-bubble-time";
|
|
3190
|
-
|
|
3191
|
-
timeSpan.textContent = String(nowA.getHours()).padStart(2, "0") + ":" + String(nowA.getMinutes()).padStart(2, "0");
|
|
3214
|
+
timeSpan.textContent = getMsgTime();
|
|
3192
3215
|
header.appendChild(timeSpan);
|
|
3193
3216
|
contentWrap.appendChild(header);
|
|
3194
3217
|
|
|
@@ -3692,7 +3715,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3692
3715
|
// Auto-switch input to schedule mode: any message typed will be queued for after reset
|
|
3693
3716
|
var delayUntilReset = msg.resetsAt - Date.now();
|
|
3694
3717
|
if (delayUntilReset > 0) {
|
|
3695
|
-
setScheduleDelayMs(delayUntilReset +
|
|
3718
|
+
setScheduleDelayMs(delayUntilReset + 60000); // +1min buffer after reset
|
|
3696
3719
|
}
|
|
3697
3720
|
rateLimitResetTimer = setTimeout(function () {
|
|
3698
3721
|
rateLimitResetsAt = null;
|
|
@@ -3716,42 +3739,134 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3716
3739
|
|
|
3717
3740
|
function addScheduledMessageBubble(text, resetsAt) {
|
|
3718
3741
|
removeScheduledMessageBubble();
|
|
3742
|
+
var isChannel = document.body.classList.contains("wide-view");
|
|
3719
3743
|
var wrap = document.createElement("div");
|
|
3720
3744
|
wrap.className = "msg-user scheduled-msg-wrap";
|
|
3721
3745
|
wrap.id = "scheduled-msg-bubble";
|
|
3722
3746
|
|
|
3723
|
-
var
|
|
3724
|
-
|
|
3747
|
+
var countdownEl;
|
|
3748
|
+
var cancelBtn;
|
|
3725
3749
|
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3750
|
+
if (isChannel) {
|
|
3751
|
+
// Channel mode: avatar + header with scheduled badge + message
|
|
3752
|
+
var _me = cachedAllUsers.find(function (u) { return u.id === myUserId; });
|
|
3753
|
+
if (!_me) { try { _me = JSON.parse(localStorage.getItem("clay_my_user") || "null"); } catch(e) {} }
|
|
3754
|
+
var _myName = document.body.dataset.myDisplayName || (_me && (_me.displayName || _me.username)) || "Me";
|
|
3729
3755
|
|
|
3730
|
-
|
|
3731
|
-
|
|
3756
|
+
var avi = document.createElement("img");
|
|
3757
|
+
avi.className = "dm-bubble-avatar dm-bubble-avatar-me";
|
|
3758
|
+
avi.src = document.body.dataset.myAvatarUrl || userAvatarUrl(_me || { id: myUserId }, 36);
|
|
3759
|
+
wrap.appendChild(avi);
|
|
3732
3760
|
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
clockIcon.innerHTML = iconHtml("clock");
|
|
3736
|
-
metaEl.appendChild(clockIcon);
|
|
3761
|
+
var content = document.createElement("div");
|
|
3762
|
+
content.className = "dm-bubble-content";
|
|
3737
3763
|
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
metaEl.appendChild(countdownEl);
|
|
3764
|
+
var header = document.createElement("div");
|
|
3765
|
+
header.className = "dm-bubble-header";
|
|
3741
3766
|
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3767
|
+
var nameSpan = document.createElement("span");
|
|
3768
|
+
nameSpan.className = "dm-bubble-name";
|
|
3769
|
+
nameSpan.textContent = _myName;
|
|
3770
|
+
header.appendChild(nameSpan);
|
|
3771
|
+
|
|
3772
|
+
var badge = document.createElement("span");
|
|
3773
|
+
badge.className = "scheduled-msg-badge";
|
|
3774
|
+
badge.innerHTML = iconHtml("clock");
|
|
3775
|
+
countdownEl = document.createElement("span");
|
|
3776
|
+
countdownEl.className = "scheduled-msg-countdown";
|
|
3777
|
+
badge.appendChild(countdownEl);
|
|
3778
|
+
header.appendChild(badge);
|
|
3779
|
+
|
|
3780
|
+
var actions = document.createElement("span");
|
|
3781
|
+
actions.className = "scheduled-msg-actions";
|
|
3782
|
+
|
|
3783
|
+
var sendNowBtn = document.createElement("button");
|
|
3784
|
+
sendNowBtn.className = "scheduled-msg-send-now";
|
|
3785
|
+
sendNowBtn.textContent = "Send now";
|
|
3786
|
+
sendNowBtn.addEventListener("click", function () {
|
|
3787
|
+
if (ws && ws.readyState === 1) {
|
|
3788
|
+
ws.send(JSON.stringify({ type: "send_scheduled_now" }));
|
|
3789
|
+
}
|
|
3790
|
+
});
|
|
3791
|
+
actions.appendChild(sendNowBtn);
|
|
3792
|
+
|
|
3793
|
+
var sep = document.createElement("span");
|
|
3794
|
+
sep.className = "scheduled-msg-sep";
|
|
3795
|
+
sep.textContent = "\u00b7";
|
|
3796
|
+
actions.appendChild(sep);
|
|
3797
|
+
|
|
3798
|
+
cancelBtn = document.createElement("button");
|
|
3799
|
+
cancelBtn.className = "scheduled-msg-cancel";
|
|
3800
|
+
cancelBtn.textContent = "Cancel";
|
|
3801
|
+
cancelBtn.addEventListener("click", function () {
|
|
3802
|
+
if (ws && ws.readyState === 1) {
|
|
3803
|
+
ws.send(JSON.stringify({ type: "cancel_scheduled_message" }));
|
|
3804
|
+
}
|
|
3805
|
+
});
|
|
3806
|
+
actions.appendChild(cancelBtn);
|
|
3807
|
+
|
|
3808
|
+
header.appendChild(actions);
|
|
3809
|
+
|
|
3810
|
+
content.appendChild(header);
|
|
3811
|
+
|
|
3812
|
+
var bubble = document.createElement("div");
|
|
3813
|
+
bubble.className = "bubble scheduled-msg-bubble";
|
|
3814
|
+
var textEl = document.createElement("span");
|
|
3815
|
+
textEl.textContent = text;
|
|
3816
|
+
bubble.appendChild(textEl);
|
|
3817
|
+
content.appendChild(bubble);
|
|
3818
|
+
|
|
3819
|
+
wrap.appendChild(content);
|
|
3820
|
+
} else {
|
|
3821
|
+
// Bubble mode: original layout
|
|
3822
|
+
var bubble = document.createElement("div");
|
|
3823
|
+
bubble.className = "bubble scheduled-msg-bubble";
|
|
3824
|
+
|
|
3825
|
+
var textEl = document.createElement("span");
|
|
3826
|
+
textEl.textContent = text;
|
|
3827
|
+
bubble.appendChild(textEl);
|
|
3828
|
+
|
|
3829
|
+
var metaEl = document.createElement("div");
|
|
3830
|
+
metaEl.className = "scheduled-msg-meta";
|
|
3831
|
+
|
|
3832
|
+
var clockIcon = document.createElement("span");
|
|
3833
|
+
clockIcon.className = "scheduled-msg-icon";
|
|
3834
|
+
clockIcon.innerHTML = iconHtml("clock");
|
|
3835
|
+
metaEl.appendChild(clockIcon);
|
|
3836
|
+
|
|
3837
|
+
countdownEl = document.createElement("span");
|
|
3838
|
+
countdownEl.className = "scheduled-msg-countdown";
|
|
3839
|
+
metaEl.appendChild(countdownEl);
|
|
3840
|
+
|
|
3841
|
+
var sendNowBtn2 = document.createElement("button");
|
|
3842
|
+
sendNowBtn2.className = "scheduled-msg-send-now";
|
|
3843
|
+
sendNowBtn2.textContent = "Send now";
|
|
3844
|
+
sendNowBtn2.addEventListener("click", function () {
|
|
3845
|
+
if (ws && ws.readyState === 1) {
|
|
3846
|
+
ws.send(JSON.stringify({ type: "send_scheduled_now" }));
|
|
3847
|
+
}
|
|
3848
|
+
});
|
|
3849
|
+
metaEl.appendChild(sendNowBtn2);
|
|
3850
|
+
|
|
3851
|
+
var sep2 = document.createElement("span");
|
|
3852
|
+
sep2.className = "scheduled-msg-sep";
|
|
3853
|
+
sep2.textContent = "\u00b7";
|
|
3854
|
+
metaEl.appendChild(sep2);
|
|
3855
|
+
|
|
3856
|
+
cancelBtn = document.createElement("button");
|
|
3857
|
+
cancelBtn.className = "scheduled-msg-cancel";
|
|
3858
|
+
cancelBtn.textContent = "Cancel";
|
|
3859
|
+
cancelBtn.addEventListener("click", function () {
|
|
3860
|
+
if (ws && ws.readyState === 1) {
|
|
3861
|
+
ws.send(JSON.stringify({ type: "cancel_scheduled_message" }));
|
|
3862
|
+
}
|
|
3863
|
+
});
|
|
3864
|
+
metaEl.appendChild(cancelBtn);
|
|
3865
|
+
|
|
3866
|
+
wrap.appendChild(bubble);
|
|
3867
|
+
wrap.appendChild(metaEl);
|
|
3868
|
+
}
|
|
3752
3869
|
|
|
3753
|
-
wrap.appendChild(bubble);
|
|
3754
|
-
wrap.appendChild(metaEl);
|
|
3755
3870
|
addToMessages(wrap);
|
|
3756
3871
|
scheduledMsgEl = wrap;
|
|
3757
3872
|
scrollToBottom();
|
|
@@ -4028,6 +4143,31 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4028
4143
|
|
|
4029
4144
|
// Session restore is now server-driven (user-presence.json).
|
|
4030
4145
|
// Mate DM restore is also server-driven via "restore_mate_dm" message.
|
|
4146
|
+
// Fallback: if server doesn't restore DM within 2s, try localStorage
|
|
4147
|
+
var savedDm = null;
|
|
4148
|
+
try { savedDm = localStorage.getItem("clay-active-dm"); } catch (e) {}
|
|
4149
|
+
if (savedDm && !dmMode && !mateProjectSlug) {
|
|
4150
|
+
var dmFallbackTimer = setTimeout(function () {
|
|
4151
|
+
if (!dmMode && savedDm) {
|
|
4152
|
+
console.log("[dm-restore] Server did not restore DM, using localStorage fallback:", savedDm);
|
|
4153
|
+
openDm(savedDm);
|
|
4154
|
+
}
|
|
4155
|
+
}, 2000);
|
|
4156
|
+
// Cancel fallback if server restores DM first
|
|
4157
|
+
var origHandler = ws.onmessage;
|
|
4158
|
+
var patchedOnce = false;
|
|
4159
|
+
var checkRestore = function (evt) {
|
|
4160
|
+
try {
|
|
4161
|
+
var d = JSON.parse(evt.data);
|
|
4162
|
+
if (d.type === "restore_mate_dm" && !patchedOnce) {
|
|
4163
|
+
patchedOnce = true;
|
|
4164
|
+
clearTimeout(dmFallbackTimer);
|
|
4165
|
+
}
|
|
4166
|
+
} catch (e) {}
|
|
4167
|
+
};
|
|
4168
|
+
ws.addEventListener("message", checkRestore);
|
|
4169
|
+
setTimeout(function () { ws.removeEventListener("message", checkRestore); }, 3000);
|
|
4170
|
+
}
|
|
4031
4171
|
// Safety: clear returningFromMateDm after initial messages settle
|
|
4032
4172
|
// (handles case where we connect to a non-main project that won't send restore_mate_dm)
|
|
4033
4173
|
if (returningFromMateDm) {
|
|
@@ -4126,6 +4266,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4126
4266
|
}
|
|
4127
4267
|
|
|
4128
4268
|
function processMessage(msg) {
|
|
4269
|
+
// Preserve original timestamp from history replay
|
|
4270
|
+
currentMsgTs = msg._ts || null;
|
|
4129
4271
|
var isMateDm = dmMode && dmTargetUser && dmTargetUser.isMate;
|
|
4130
4272
|
|
|
4131
4273
|
// DEBUG: trace session/history loading
|
|
@@ -4140,6 +4282,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4140
4282
|
if (isMateDm) {
|
|
4141
4283
|
if (msg.type === "session_list") {
|
|
4142
4284
|
renderMateSessionList(msg.sessions || []);
|
|
4285
|
+
refreshMobileChatSheet();
|
|
4143
4286
|
// Override title bar with mate name and re-apply color
|
|
4144
4287
|
var _mdn = (dmTargetUser.displayName || "New Mate");
|
|
4145
4288
|
if (headerTitleEl) headerTitleEl.textContent = _mdn;
|
|
@@ -4245,6 +4388,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4245
4388
|
if (dhBar) dhBar.remove();
|
|
4246
4389
|
var dbBadges = document.querySelectorAll(".debate-header-badge");
|
|
4247
4390
|
for (var dbi = 0; dbi < dbBadges.length; dbi++) dbBadges[dbi].remove();
|
|
4391
|
+
// Clean up ended mode banner if debate is not active on this session
|
|
4392
|
+
if (debateEndedMode) exitDebateEndedMode();
|
|
4248
4393
|
}
|
|
4249
4394
|
scrollToBottom();
|
|
4250
4395
|
// Scroll to tool element if navigating from file edit history
|
|
@@ -4485,9 +4630,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4485
4630
|
break;
|
|
4486
4631
|
|
|
4487
4632
|
case "session_list":
|
|
4488
|
-
|
|
4489
|
-
renderMateSessionList(msg.sessions || []);
|
|
4490
|
-
}
|
|
4633
|
+
renderMateSessionList(msg.sessions || []);
|
|
4491
4634
|
renderSessionList(msg.sessions || []);
|
|
4492
4635
|
handlePaletteSessionSwitch();
|
|
4493
4636
|
break;
|
|
@@ -4578,6 +4721,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4578
4721
|
break;
|
|
4579
4722
|
|
|
4580
4723
|
case "user_message":
|
|
4724
|
+
if (msg._internal) break;
|
|
4581
4725
|
resetThinkingGroup();
|
|
4582
4726
|
if (msg.planContent) {
|
|
4583
4727
|
setPlanContent(msg.planContent);
|
|
@@ -4599,7 +4743,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4599
4743
|
header.className = "context-card-header";
|
|
4600
4744
|
var icon = document.createElement("span");
|
|
4601
4745
|
icon.className = "context-card-icon";
|
|
4602
|
-
icon.
|
|
4746
|
+
icon.innerHTML = iconHtml("globe");
|
|
4603
4747
|
header.appendChild(icon);
|
|
4604
4748
|
var label = document.createElement("span");
|
|
4605
4749
|
label.textContent = "Viewing tab";
|
|
@@ -4623,6 +4767,15 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4623
4767
|
if (tabTitle || tabDomain) {
|
|
4624
4768
|
var meta = document.createElement("div");
|
|
4625
4769
|
meta.className = "context-card-meta";
|
|
4770
|
+
if (msg.tab.favIconUrl) {
|
|
4771
|
+
var fav = document.createElement("img");
|
|
4772
|
+
fav.className = "context-card-favicon";
|
|
4773
|
+
fav.src = msg.tab.favIconUrl;
|
|
4774
|
+
fav.width = 14;
|
|
4775
|
+
fav.height = 14;
|
|
4776
|
+
fav.onerror = function () { this.style.display = "none"; };
|
|
4777
|
+
meta.appendChild(fav);
|
|
4778
|
+
}
|
|
4626
4779
|
var titleEl = document.createElement("span");
|
|
4627
4780
|
titleEl.className = "context-card-title";
|
|
4628
4781
|
titleEl.textContent = tabTitle;
|
|
@@ -4644,17 +4797,17 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4644
4797
|
case "status":
|
|
4645
4798
|
if (msg.status === "processing") {
|
|
4646
4799
|
setStatus("processing");
|
|
4647
|
-
if (!(dmMode && dmTargetUser && dmTargetUser.isMate)) {
|
|
4648
|
-
setActivity(
|
|
4800
|
+
if (!(dmMode && dmTargetUser && dmTargetUser.isMate) && !matePreThinkingEl) {
|
|
4801
|
+
setActivity("thinking");
|
|
4649
4802
|
}
|
|
4650
4803
|
}
|
|
4651
4804
|
break;
|
|
4652
4805
|
|
|
4653
4806
|
case "compacting":
|
|
4654
4807
|
if (msg.active) {
|
|
4655
|
-
setActivity("
|
|
4808
|
+
setActivity("compacting");
|
|
4656
4809
|
} else if (!(dmMode && dmTargetUser && dmTargetUser.isMate)) {
|
|
4657
|
-
setActivity(
|
|
4810
|
+
setActivity("thinking");
|
|
4658
4811
|
}
|
|
4659
4812
|
break;
|
|
4660
4813
|
|
|
@@ -4670,7 +4823,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4670
4823
|
case "thinking_stop":
|
|
4671
4824
|
stopThinking(msg.duration);
|
|
4672
4825
|
if (!(dmMode && dmTargetUser && dmTargetUser.isMate)) {
|
|
4673
|
-
setActivity(
|
|
4826
|
+
setActivity("thinking");
|
|
4674
4827
|
}
|
|
4675
4828
|
break;
|
|
4676
4829
|
|
|
@@ -4696,6 +4849,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4696
4849
|
}
|
|
4697
4850
|
renderPlanBanner("exit");
|
|
4698
4851
|
getTools()[msg.id] = { el: null, name: msg.name, input: null, done: true, hidden: true };
|
|
4852
|
+
} else if (msg.name === "propose_debate" || (msg.name && msg.name.indexOf("propose_debate") !== -1)) {
|
|
4853
|
+
getTools()[msg.id] = { el: null, name: msg.name, input: null, done: true, hidden: true };
|
|
4699
4854
|
} else if (getTodoTools()[msg.name]) {
|
|
4700
4855
|
getTools()[msg.id] = { el: null, name: msg.name, input: null, done: true, hidden: true };
|
|
4701
4856
|
} else {
|
|
@@ -4704,7 +4859,18 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4704
4859
|
break;
|
|
4705
4860
|
|
|
4706
4861
|
case "tool_executing":
|
|
4707
|
-
if (msg.name === "
|
|
4862
|
+
if ((msg.name === "propose_debate" || (msg.name && msg.name.indexOf("propose_debate") !== -1)) && msg.input) {
|
|
4863
|
+
var _dpTool = getTools()[msg.id];
|
|
4864
|
+
if (_dpTool) {
|
|
4865
|
+
if (_dpTool.el) _dpTool.el.style.display = "none";
|
|
4866
|
+
_dpTool.done = true;
|
|
4867
|
+
_dpTool.hidden = true;
|
|
4868
|
+
removeToolFromGroup(msg.id);
|
|
4869
|
+
}
|
|
4870
|
+
finalizeAssistantBlock();
|
|
4871
|
+
renderMcpDebateProposal(msg.id, msg.input);
|
|
4872
|
+
startUrgentBlink();
|
|
4873
|
+
} else if (msg.name === "AskUserQuestion" && msg.input && msg.input.questions) {
|
|
4708
4874
|
var askTool = getTools()[msg.id];
|
|
4709
4875
|
if (askTool) {
|
|
4710
4876
|
if (askTool.el) askTool.el.style.display = "none";
|
|
@@ -5261,6 +5427,23 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5261
5427
|
break;
|
|
5262
5428
|
|
|
5263
5429
|
// --- @Mention ---
|
|
5430
|
+
case "mention_processing":
|
|
5431
|
+
// Broadcast: show/hide activity dot on mate avatar across all tabs
|
|
5432
|
+
if (msg.mateId) {
|
|
5433
|
+
var mateContainers = document.querySelectorAll('.icon-strip-mate[data-user-id="' + msg.mateId + '"]');
|
|
5434
|
+
for (var mi = 0; mi < mateContainers.length; mi++) {
|
|
5435
|
+
var dot = mateContainers[mi].querySelector(".icon-strip-status");
|
|
5436
|
+
if (msg.active) {
|
|
5437
|
+
if (dot) dot.classList.add("processing");
|
|
5438
|
+
mateContainers[mi].classList.add("mention-active");
|
|
5439
|
+
} else {
|
|
5440
|
+
if (dot) dot.classList.remove("processing");
|
|
5441
|
+
mateContainers[mi].classList.remove("mention-active");
|
|
5442
|
+
}
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5445
|
+
break;
|
|
5446
|
+
|
|
5264
5447
|
case "mention_start":
|
|
5265
5448
|
handleMentionStart(msg);
|
|
5266
5449
|
break;
|
|
@@ -5338,6 +5521,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5338
5521
|
}
|
|
5339
5522
|
break;
|
|
5340
5523
|
|
|
5524
|
+
case "debate_hand_raised":
|
|
5525
|
+
// Visual feedback: hand is raised, waiting for floor
|
|
5526
|
+
break;
|
|
5527
|
+
|
|
5341
5528
|
case "debate_comment_queued":
|
|
5342
5529
|
handleDebateCommentQueued(msg);
|
|
5343
5530
|
break;
|
|
@@ -5354,6 +5541,14 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5354
5541
|
showDebateConcludeConfirm(msg);
|
|
5355
5542
|
break;
|
|
5356
5543
|
|
|
5544
|
+
case "debate_user_floor":
|
|
5545
|
+
showDebateUserFloor(msg);
|
|
5546
|
+
break;
|
|
5547
|
+
|
|
5548
|
+
case "debate_user_floor_done":
|
|
5549
|
+
renderDebateUserFloorDone(msg);
|
|
5550
|
+
break;
|
|
5551
|
+
|
|
5357
5552
|
case "debate_user_resume":
|
|
5358
5553
|
renderDebateUserResume(msg);
|
|
5359
5554
|
break;
|
|
@@ -5699,10 +5894,17 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5699
5894
|
isDmMode: function () { return dmMode && !(dmTargetUser && dmTargetUser.isMate); },
|
|
5700
5895
|
getDmKey: function () { return dmKey; },
|
|
5701
5896
|
handleDmSend: function () { handleDmSend(); },
|
|
5897
|
+
isDebateEndedMode: function () { return debateEndedMode; },
|
|
5898
|
+
handleDebateEndedSend: function () { handleDebateEndedSend(); },
|
|
5899
|
+
isDebateConcludeMode: function () { return false; },
|
|
5900
|
+
handleDebateConcludeSend: null,
|
|
5901
|
+
isDebateFloorMode: function () { return debateFloorMode; },
|
|
5902
|
+
handleDebateFloorSend: function () { handleDebateFloorSend(); },
|
|
5702
5903
|
isMateDm: function () { return dmMode && dmTargetUser && dmTargetUser.isMate; },
|
|
5703
5904
|
getMateName: function () { return dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate"; },
|
|
5704
5905
|
getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
|
|
5705
5906
|
showMatePreThinking: function () { showMatePreThinking(); },
|
|
5907
|
+
showClaudePreThinking: function () { showClaudePreThinking(); },
|
|
5706
5908
|
});
|
|
5707
5909
|
|
|
5708
5910
|
// --- @Mention module ---
|
|
@@ -5724,13 +5926,16 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5724
5926
|
// --- Debate module ---
|
|
5725
5927
|
initDebate({
|
|
5726
5928
|
get ws() { return ws; },
|
|
5929
|
+
sendWs: function (obj) { if (ws && ws.readyState === 1) ws.send(JSON.stringify(obj)); },
|
|
5727
5930
|
messagesEl: messagesEl,
|
|
5931
|
+
addToMessages: function (el) { addToMessages(el); },
|
|
5728
5932
|
scrollToBottom: scrollToBottom,
|
|
5729
5933
|
addCopyHandler: addCopyHandler,
|
|
5730
5934
|
matesList: function () { return cachedMatesList || []; },
|
|
5731
5935
|
availableBuiltins: function () { return cachedAvailableBuiltins || []; },
|
|
5732
5936
|
currentMateId: function () { return (dmTargetUser && dmTargetUser.isMate) ? dmTargetUser.id : null; },
|
|
5733
5937
|
requireSkills: requireSkills,
|
|
5938
|
+
showDebateEndedMode: function (msg) { showDebateEndedMode(msg); },
|
|
5734
5939
|
});
|
|
5735
5940
|
|
|
5736
5941
|
// --- STT module (voice input via Web Speech API) ---
|
|
@@ -7021,6 +7226,159 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7021
7226
|
scrollToBottom();
|
|
7022
7227
|
}
|
|
7023
7228
|
|
|
7229
|
+
var debateFloorMode = false;
|
|
7230
|
+
|
|
7231
|
+
var debateEndedMode = false;
|
|
7232
|
+
|
|
7233
|
+
function showDebateEndedMode(msg) {
|
|
7234
|
+
debateEndedMode = true;
|
|
7235
|
+
removeDebateBottomBar();
|
|
7236
|
+
var inputArea = document.getElementById("input-area");
|
|
7237
|
+
if (inputArea) {
|
|
7238
|
+
inputArea.classList.add("debate-floor-mode");
|
|
7239
|
+
inputArea.style.display = "";
|
|
7240
|
+
}
|
|
7241
|
+
var existingBanner = document.getElementById("debate-floor-banner");
|
|
7242
|
+
if (existingBanner) existingBanner.remove();
|
|
7243
|
+
var banner = document.createElement("div");
|
|
7244
|
+
banner.id = "debate-floor-banner";
|
|
7245
|
+
banner.className = "debate-floor-banner";
|
|
7246
|
+
banner.innerHTML = iconHtml("check-circle") + " <span>Debate ended</span>" +
|
|
7247
|
+
'<button class="debate-floor-done-btn" id="debate-ended-resume-btn">Resume</button>' +
|
|
7248
|
+
'<button class="debate-floor-done-btn" id="debate-ended-pdf-btn">' + iconHtml("download") + ' PDF</button>';
|
|
7249
|
+
if (inputArea && inputArea.parentNode) {
|
|
7250
|
+
inputArea.parentNode.insertBefore(banner, inputArea);
|
|
7251
|
+
}
|
|
7252
|
+
refreshIcons();
|
|
7253
|
+
// Resume button
|
|
7254
|
+
var resumeBtn = document.getElementById("debate-ended-resume-btn");
|
|
7255
|
+
if (resumeBtn) {
|
|
7256
|
+
resumeBtn.addEventListener("click", function () {
|
|
7257
|
+
handleDebateEndedSend();
|
|
7258
|
+
});
|
|
7259
|
+
}
|
|
7260
|
+
// PDF button
|
|
7261
|
+
var pdfBtn = document.getElementById("debate-ended-pdf-btn");
|
|
7262
|
+
if (pdfBtn) {
|
|
7263
|
+
pdfBtn.addEventListener("click", function () {
|
|
7264
|
+
pdfBtn.disabled = true;
|
|
7265
|
+
exportDebateAsPdf().then(function () { pdfBtn.disabled = false; }).catch(function () { pdfBtn.disabled = false; });
|
|
7266
|
+
});
|
|
7267
|
+
}
|
|
7268
|
+
var inputEl2 = document.getElementById("input");
|
|
7269
|
+
if (inputEl2) {
|
|
7270
|
+
inputEl2._origPlaceholder = inputEl2._origPlaceholder || inputEl2.placeholder;
|
|
7271
|
+
inputEl2.placeholder = "Continue with a new direction...";
|
|
7272
|
+
}
|
|
7273
|
+
scrollToBottom();
|
|
7274
|
+
}
|
|
7275
|
+
|
|
7276
|
+
function exitDebateEndedMode() {
|
|
7277
|
+
debateEndedMode = false;
|
|
7278
|
+
var inputArea = document.getElementById("input-area");
|
|
7279
|
+
if (inputArea) inputArea.classList.remove("debate-floor-mode");
|
|
7280
|
+
var banner = document.getElementById("debate-floor-banner");
|
|
7281
|
+
if (banner) banner.remove();
|
|
7282
|
+
var inputEl2 = document.getElementById("input");
|
|
7283
|
+
if (inputEl2 && inputEl2._origPlaceholder) {
|
|
7284
|
+
inputEl2.placeholder = inputEl2._origPlaceholder;
|
|
7285
|
+
delete inputEl2._origPlaceholder;
|
|
7286
|
+
}
|
|
7287
|
+
}
|
|
7288
|
+
|
|
7289
|
+
function handleDebateEndedSend() {
|
|
7290
|
+
var text = inputEl.value.trim();
|
|
7291
|
+
if (ws && ws.readyState === 1) {
|
|
7292
|
+
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "continue", text: text }));
|
|
7293
|
+
}
|
|
7294
|
+
inputEl.value = "";
|
|
7295
|
+
exitDebateEndedMode();
|
|
7296
|
+
}
|
|
7297
|
+
|
|
7298
|
+
function showDebateUserFloor(msg) {
|
|
7299
|
+
debateFloorMode = true;
|
|
7300
|
+
// Remove debate bottom bar and show input area in floor mode
|
|
7301
|
+
removeDebateBottomBar();
|
|
7302
|
+
var inputArea = document.getElementById("input-area");
|
|
7303
|
+
if (inputArea) {
|
|
7304
|
+
inputArea.classList.add("debate-floor-mode");
|
|
7305
|
+
inputArea.style.display = "";
|
|
7306
|
+
}
|
|
7307
|
+
// Add floor banner above input
|
|
7308
|
+
var existingBanner = document.getElementById("debate-floor-banner");
|
|
7309
|
+
if (existingBanner) existingBanner.remove();
|
|
7310
|
+
var banner = document.createElement("div");
|
|
7311
|
+
banner.id = "debate-floor-banner";
|
|
7312
|
+
banner.className = "debate-floor-banner";
|
|
7313
|
+
banner.innerHTML = iconHtml("mic") + " <span>You have the floor</span>" +
|
|
7314
|
+
'<button class="debate-floor-done-btn" id="debate-floor-done-btn">Pass</button>';
|
|
7315
|
+
if (inputArea && inputArea.parentNode) {
|
|
7316
|
+
inputArea.parentNode.insertBefore(banner, inputArea);
|
|
7317
|
+
}
|
|
7318
|
+
refreshIcons();
|
|
7319
|
+
// Done button: exit floor mode without sending
|
|
7320
|
+
var doneBtn = document.getElementById("debate-floor-done-btn");
|
|
7321
|
+
if (doneBtn) {
|
|
7322
|
+
doneBtn.addEventListener("click", function () {
|
|
7323
|
+
// Pass without speaking: resume debate
|
|
7324
|
+
if (ws && ws.readyState === 1) {
|
|
7325
|
+
ws.send(JSON.stringify({ type: "debate_user_floor_response", text: "(The user passed without speaking)" }));
|
|
7326
|
+
}
|
|
7327
|
+
exitDebateFloorMode();
|
|
7328
|
+
showDebateBottomBar("live");
|
|
7329
|
+
});
|
|
7330
|
+
}
|
|
7331
|
+
// Update placeholder
|
|
7332
|
+
var inputEl = document.getElementById("input");
|
|
7333
|
+
if (inputEl) {
|
|
7334
|
+
inputEl._origPlaceholder = inputEl.placeholder;
|
|
7335
|
+
inputEl.placeholder = "Share your thoughts with the panel...";
|
|
7336
|
+
inputEl.focus();
|
|
7337
|
+
}
|
|
7338
|
+
scrollToBottom();
|
|
7339
|
+
}
|
|
7340
|
+
|
|
7341
|
+
function exitDebateFloorMode() {
|
|
7342
|
+
debateFloorMode = false;
|
|
7343
|
+
var inputArea = document.getElementById("input-area");
|
|
7344
|
+
if (inputArea) inputArea.classList.remove("debate-floor-mode");
|
|
7345
|
+
var banner = document.getElementById("debate-floor-banner");
|
|
7346
|
+
if (banner) banner.remove();
|
|
7347
|
+
var inputEl = document.getElementById("input");
|
|
7348
|
+
if (inputEl && inputEl._origPlaceholder) {
|
|
7349
|
+
inputEl.placeholder = inputEl._origPlaceholder;
|
|
7350
|
+
delete inputEl._origPlaceholder;
|
|
7351
|
+
}
|
|
7352
|
+
}
|
|
7353
|
+
|
|
7354
|
+
function handleDebateFloorSend() {
|
|
7355
|
+
var text = inputEl.value.trim();
|
|
7356
|
+
if (!text) return;
|
|
7357
|
+
if (ws && ws.readyState === 1) {
|
|
7358
|
+
ws.send(JSON.stringify({ type: "debate_user_floor_response", text: text }));
|
|
7359
|
+
}
|
|
7360
|
+
inputEl.value = "";
|
|
7361
|
+
exitDebateFloorMode();
|
|
7362
|
+
showDebateBottomBar("live");
|
|
7363
|
+
}
|
|
7364
|
+
|
|
7365
|
+
function renderDebateUserFloorDone(msg) {
|
|
7366
|
+
if (!messagesEl) return;
|
|
7367
|
+
var el = document.createElement("div");
|
|
7368
|
+
el.className = "debate-user-comment";
|
|
7369
|
+
var label = document.createElement("span");
|
|
7370
|
+
label.className = "debate-comment-label";
|
|
7371
|
+
label.innerHTML = iconHtml("mic") + " User:";
|
|
7372
|
+
var textEl = document.createElement("div");
|
|
7373
|
+
textEl.className = "debate-comment-text";
|
|
7374
|
+
textEl.textContent = msg.text || "";
|
|
7375
|
+
el.appendChild(label);
|
|
7376
|
+
el.appendChild(textEl);
|
|
7377
|
+
messagesEl.appendChild(el);
|
|
7378
|
+
refreshIcons();
|
|
7379
|
+
scrollToBottom();
|
|
7380
|
+
}
|
|
7381
|
+
|
|
7024
7382
|
// Legacy handler kept for compatibility
|
|
7025
7383
|
function showDebateSticky(phase, msg) {
|
|
7026
7384
|
if (phase === "ended" || phase === "hide") {
|
|
@@ -7043,7 +7401,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7043
7401
|
return;
|
|
7044
7402
|
}
|
|
7045
7403
|
|
|
7046
|
-
//
|
|
7404
|
+
// Show bottom bar regardless of header availability
|
|
7405
|
+
if (phase === "live") {
|
|
7406
|
+
debateHandRaiseOpen = false;
|
|
7407
|
+
showDebateBottomBar("live");
|
|
7408
|
+
}
|
|
7409
|
+
|
|
7410
|
+
// Add badges next to header title (optional, may not exist on mobile)
|
|
7047
7411
|
var headerTitle = document.getElementById("header-title");
|
|
7048
7412
|
if (!headerTitle) return;
|
|
7049
7413
|
|
|
@@ -7063,9 +7427,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7063
7427
|
roundBadge.id = "debate-header-round";
|
|
7064
7428
|
roundBadge.textContent = "R" + ((msg && msg.round) || 1);
|
|
7065
7429
|
liveBadge.after(roundBadge);
|
|
7066
|
-
|
|
7067
|
-
debateHandRaiseOpen = false;
|
|
7068
|
-
showDebateBottomBar("live");
|
|
7069
7430
|
}
|
|
7070
7431
|
}
|
|
7071
7432
|
|
|
@@ -7084,6 +7445,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7084
7445
|
bar.innerHTML =
|
|
7085
7446
|
'<div class="debate-bottom-inner">' +
|
|
7086
7447
|
'<button class="debate-bottom-hand" id="debate-bottom-hand">' + iconHtml("hand") + ' Raise hand</button>' +
|
|
7448
|
+
'<span class="debate-bottom-waiting hidden" id="debate-bottom-waiting">' + iconHtml("loader") + ' You will get the floor after the current speaker</span>' +
|
|
7087
7449
|
'<button class="debate-bottom-stop" id="debate-bottom-stop">' + iconHtml("square") + ' Stop</button>' +
|
|
7088
7450
|
'</div>';
|
|
7089
7451
|
|
|
@@ -7091,6 +7453,14 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7091
7453
|
inputArea.style.display = "none";
|
|
7092
7454
|
refreshIcons();
|
|
7093
7455
|
|
|
7456
|
+
// Restore raised state if hand was already raised
|
|
7457
|
+
if (debateHandRaiseOpen) {
|
|
7458
|
+
var handBtn = document.getElementById("debate-bottom-hand");
|
|
7459
|
+
var waitingEl = document.getElementById("debate-bottom-waiting");
|
|
7460
|
+
if (handBtn) { handBtn.classList.add("raised"); handBtn.classList.add("hidden"); }
|
|
7461
|
+
if (waitingEl) waitingEl.classList.remove("hidden");
|
|
7462
|
+
}
|
|
7463
|
+
|
|
7094
7464
|
document.getElementById("debate-bottom-hand").addEventListener("click", function () {
|
|
7095
7465
|
toggleDebateHandRaise();
|
|
7096
7466
|
});
|
|
@@ -7130,16 +7500,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7130
7500
|
showDebateBottomBar("live");
|
|
7131
7501
|
});
|
|
7132
7502
|
if (textArea) {
|
|
7133
|
-
textArea.focus();
|
|
7134
7503
|
textArea.addEventListener("keydown", function (e) {
|
|
7135
7504
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
7136
7505
|
e.preventDefault();
|
|
7137
7506
|
document.getElementById("debate-bottom-continue").click();
|
|
7138
7507
|
}
|
|
7139
7508
|
});
|
|
7140
|
-
textArea.addEventListener("input", function () {
|
|
7141
|
-
debateAutoResize(textArea, 12);
|
|
7142
|
-
});
|
|
7143
7509
|
}
|
|
7144
7510
|
}
|
|
7145
7511
|
}
|
|
@@ -7160,74 +7526,33 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7160
7526
|
var handBar = document.getElementById("debate-hand-raise-bar");
|
|
7161
7527
|
if (handBar) handBar.remove();
|
|
7162
7528
|
debateHandRaiseOpen = false;
|
|
7529
|
+
// Clean up floor/ended modes
|
|
7530
|
+
if (debateFloorMode) exitDebateFloorMode();
|
|
7531
|
+
if (debateEndedMode) exitDebateEndedMode();
|
|
7163
7532
|
// Restore input area
|
|
7164
7533
|
var inputArea = document.getElementById("input-area");
|
|
7165
7534
|
if (inputArea) inputArea.style.display = "";
|
|
7166
7535
|
}
|
|
7167
7536
|
|
|
7168
7537
|
function toggleDebateHandRaise(forceState) {
|
|
7169
|
-
var
|
|
7170
|
-
debateHandRaiseOpen =
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
if (
|
|
7180
|
-
|
|
7181
|
-
}
|
|
7182
|
-
|
|
7183
|
-
// Create hand raise bar above input area
|
|
7184
|
-
var bar = document.createElement("div");
|
|
7185
|
-
bar.id = "debate-hand-raise-bar";
|
|
7186
|
-
bar.className = "debate-hand-raise-bar";
|
|
7187
|
-
bar.innerHTML =
|
|
7188
|
-
'<div class="debate-hand-raise-inner">' +
|
|
7189
|
-
'<span class="debate-hand-raise-label">' + iconHtml("hand") + ' Your comment:</span>' +
|
|
7190
|
-
'<textarea class="debate-hand-input" rows="1" placeholder="Type your comment..."></textarea>' +
|
|
7191
|
-
'<button class="debate-hand-send">Send</button>' +
|
|
7192
|
-
'<button class="debate-hand-cancel">Cancel</button>' +
|
|
7193
|
-
'</div>';
|
|
7194
|
-
|
|
7195
|
-
var inputArea = document.getElementById("input-area");
|
|
7196
|
-
if (inputArea && inputArea.parentNode) {
|
|
7197
|
-
inputArea.parentNode.insertBefore(bar, inputArea);
|
|
7198
|
-
}
|
|
7199
|
-
refreshIcons();
|
|
7200
|
-
|
|
7201
|
-
var textarea = bar.querySelector(".debate-hand-input");
|
|
7202
|
-
var sendBtn = bar.querySelector(".debate-hand-send");
|
|
7203
|
-
var cancelBtn = bar.querySelector(".debate-hand-cancel");
|
|
7204
|
-
|
|
7205
|
-
if (textarea) {
|
|
7206
|
-
textarea.focus();
|
|
7207
|
-
textarea.addEventListener("input", function () {
|
|
7208
|
-
debateAutoResize(textarea, 12);
|
|
7209
|
-
});
|
|
7538
|
+
var raise = typeof forceState === "boolean" ? forceState : !debateHandRaiseOpen;
|
|
7539
|
+
debateHandRaiseOpen = raise;
|
|
7540
|
+
|
|
7541
|
+
// Update UI: hide hand button, show waiting message
|
|
7542
|
+
var handBtn = document.getElementById("debate-bottom-hand");
|
|
7543
|
+
var waitingEl = document.getElementById("debate-bottom-waiting");
|
|
7544
|
+
if (raise) {
|
|
7545
|
+
if (handBtn) { handBtn.classList.add("raised"); handBtn.classList.add("hidden"); }
|
|
7546
|
+
if (waitingEl) waitingEl.classList.remove("hidden");
|
|
7547
|
+
} else {
|
|
7548
|
+
if (handBtn) { handBtn.classList.remove("raised"); handBtn.classList.remove("hidden"); }
|
|
7549
|
+
if (waitingEl) waitingEl.classList.add("hidden");
|
|
7210
7550
|
}
|
|
7211
7551
|
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
if (!text) return;
|
|
7215
|
-
if (ws && ws.readyState === 1) {
|
|
7216
|
-
ws.send(JSON.stringify({ type: "debate_comment", text: text }));
|
|
7217
|
-
}
|
|
7218
|
-
toggleDebateHandRaise(false);
|
|
7219
|
-
});
|
|
7220
|
-
|
|
7221
|
-
cancelBtn.addEventListener("click", function () {
|
|
7222
|
-
toggleDebateHandRaise(false);
|
|
7223
|
-
});
|
|
7224
|
-
|
|
7225
|
-
if (textarea) {
|
|
7226
|
-
textarea.addEventListener("keydown", function (e) {
|
|
7227
|
-
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendBtn.click(); }
|
|
7228
|
-
if (e.key === "Escape") { toggleDebateHandRaise(false); }
|
|
7229
|
-
});
|
|
7552
|
+
if (raise && ws && ws.readyState === 1) {
|
|
7553
|
+
ws.send(JSON.stringify({ type: "debate_hand_raise" }));
|
|
7230
7554
|
}
|
|
7555
|
+
// Floor mode will be activated when server sends debate_user_floor
|
|
7231
7556
|
}
|
|
7232
7557
|
|
|
7233
7558
|
function sendDebateStickyComment() {
|