clay-server 5.1.0-beta.1 → 5.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/LICENSES/README.md +4 -0
  2. package/LICENSES/dicebear-avatars.md +16 -0
  3. package/lib/daemon-project-access.js +7 -1
  4. package/lib/daemon.js +2 -0
  5. package/lib/dicebear-avatar.js +62 -0
  6. package/lib/knowledge-db-service.js +175 -0
  7. package/lib/knowledge-db-validation.js +0 -0
  8. package/lib/knowledge-document-index.js +49 -0
  9. package/lib/knowledge-draft-store.js +56 -0
  10. package/lib/knowledge-file-store.js +199 -0
  11. package/lib/knowledge-markdown.js +128 -0
  12. package/lib/mate-knowledge-mcp-server.js +29 -6
  13. package/lib/mate-knowledge-service.js +23 -2
  14. package/lib/mate-knowledge-sync.js +36 -21
  15. package/lib/mate-workspace-color.js +4 -0
  16. package/lib/mates.js +18 -0
  17. package/lib/project-connection.js +36 -2
  18. package/lib/project-debate-proposal.js +6 -0
  19. package/lib/project-debate-workspace.js +43 -0
  20. package/lib/project-debate.js +1 -0
  21. package/lib/project-knowledge.js +315 -136
  22. package/lib/project-mate-creation-proposal.js +1 -0
  23. package/lib/project-sessions.js +39 -2
  24. package/lib/project-user-knowledge.js +60 -0
  25. package/lib/project.js +59 -18
  26. package/lib/public/app.js +73 -34
  27. package/lib/public/clay-studio-wordmark-bold.svg +20 -0
  28. package/lib/public/css/clay-workspace.css +105 -0
  29. package/lib/public/css/debates-workbench.css +47 -0
  30. package/lib/public/css/home-debate-live.css +26 -0
  31. package/lib/public/css/home-hub.css +3 -1
  32. package/lib/public/css/home-mate-model-picker.css +15 -131
  33. package/lib/public/css/home-mate-settings.css +168 -16
  34. package/lib/public/css/icon-strip.css +249 -32
  35. package/lib/public/css/mate-conversation.css +176 -0
  36. package/lib/public/css/mate-knowledge-workbench.css +118 -0
  37. package/lib/public/css/mate-workspace-color.css +16 -0
  38. package/lib/public/css/mates.css +28 -28
  39. package/lib/public/css/messages.css +1 -114
  40. package/lib/public/css/mobile-nav.css +16 -16
  41. package/lib/public/css/overlays.css +8 -0
  42. package/lib/public/css/project-logs.css +7 -0
  43. package/lib/public/css/project-mate-creation.css +105 -0
  44. package/lib/public/css/right-workbench.css +3 -3
  45. package/lib/public/css/session-folders.css +80 -21
  46. package/lib/public/css/sidebar.css +183 -107
  47. package/lib/public/css/title-bar.css +151 -0
  48. package/lib/public/css/worker-delegation.css +47 -0
  49. package/lib/public/css/worker-proposal.css +72 -150
  50. package/lib/public/css/you.css +74 -0
  51. package/lib/public/index.html +33 -101
  52. package/lib/public/modules/account-island.js +230 -0
  53. package/lib/public/modules/app-cursors.js +19 -43
  54. package/lib/public/modules/app-debate-ui.js +4 -3
  55. package/lib/public/modules/app-header.js +106 -0
  56. package/lib/public/modules/app-message-router.js +12 -3
  57. package/lib/public/modules/app-messages.js +34 -9
  58. package/lib/public/modules/app-notifications.js +4 -7
  59. package/lib/public/modules/app-projects.js +5 -38
  60. package/lib/public/modules/app-rendering.js +12 -13
  61. package/lib/public/modules/avatar.js +25 -9
  62. package/lib/public/modules/chat-render-runtime.js +16 -4
  63. package/lib/public/modules/command-palette.js +2 -15
  64. package/lib/public/modules/cursor-sharing-preference.js +3 -3
  65. package/lib/public/modules/debate-controls.js +299 -0
  66. package/lib/public/modules/debate.js +2 -0
  67. package/lib/public/modules/debates-workbench.js +339 -0
  68. package/lib/public/modules/default-ai.js +81 -65
  69. package/lib/public/modules/home-debate-controls.js +18 -289
  70. package/lib/public/modules/home-mate-avatar-editor.js +228 -0
  71. package/lib/public/modules/home-mate-color-picker.js +66 -0
  72. package/lib/public/modules/home-mate-creation.js +1 -1
  73. package/lib/public/modules/home-mate-instructions.js +90 -0
  74. package/lib/public/modules/home-mate-model-picker.js +80 -271
  75. package/lib/public/modules/home-mate-profile-editor.js +72 -0
  76. package/lib/public/modules/home-mate-settings.js +118 -125
  77. package/lib/public/modules/home-shell.js +3 -0
  78. package/lib/public/modules/home-surface-boot.js +1 -9
  79. package/lib/public/modules/icon-strip-tooltip.js +95 -0
  80. package/lib/public/modules/knowledge-db-edit-state.js +35 -0
  81. package/lib/public/modules/knowledge-db-workbench.js +234 -0
  82. package/lib/public/modules/knowledge-history-state.js +55 -0
  83. package/lib/public/modules/knowledge-markdown-editor.js +57 -0
  84. package/lib/public/modules/knowledge-preview-links.js +70 -0
  85. package/lib/public/modules/knowledge-workbench-shell.js +21 -0
  86. package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
  87. package/lib/public/modules/mate-knowledge-workbench.js +500 -0
  88. package/lib/public/modules/mate-knowledge.js +11 -3
  89. package/lib/public/modules/mate-management.js +54 -10
  90. package/lib/public/modules/mate-sidebar.js +11 -1
  91. package/lib/public/modules/mate-workspace-color.js +33 -0
  92. package/lib/public/modules/mention.js +5 -13
  93. package/lib/public/modules/profile.js +51 -18
  94. package/lib/public/modules/project-chat-identity.js +79 -0
  95. package/lib/public/modules/project-debate-planning-workspace.js +250 -0
  96. package/lib/public/modules/project-debate-workspace.js +185 -0
  97. package/lib/public/modules/project-header-identity.js +127 -0
  98. package/lib/public/modules/project-logs-render.js +9 -4
  99. package/lib/public/modules/project-mate-creation-workspace.js +414 -0
  100. package/lib/public/modules/project-mate-navigation.js +238 -0
  101. package/lib/public/modules/project-session-navigation.js +29 -0
  102. package/lib/public/modules/project-switcher.js +6 -8
  103. package/lib/public/modules/projects-hub-view.js +5 -6
  104. package/lib/public/modules/projects-hub.js +2 -6
  105. package/lib/public/modules/qrcode.js +27 -8
  106. package/lib/public/modules/search-clay-chat.js +8 -11
  107. package/lib/public/modules/session-activity-tooltip.js +12 -0
  108. package/lib/public/modules/session-create-form.js +86 -14
  109. package/lib/public/modules/session-create.js +50 -7
  110. package/lib/public/modules/session-list-visibility.js +41 -0
  111. package/lib/public/modules/session-presence-ui.js +4 -1
  112. package/lib/public/modules/session-title-marquee.js +51 -0
  113. package/lib/public/modules/sidebar-mates.js +3 -50
  114. package/lib/public/modules/sidebar-mobile.js +63 -60
  115. package/lib/public/modules/sidebar-projects.js +84 -97
  116. package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
  117. package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
  118. package/lib/public/modules/sidebar-sessions.js +49 -50
  119. package/lib/public/modules/sidebar.js +11 -13
  120. package/lib/public/modules/thinking-lifecycle.js +7 -6
  121. package/lib/public/modules/tool-palette-order.js +4 -3
  122. package/lib/public/modules/tool-palette.js +13 -3
  123. package/lib/public/modules/tools.js +22 -22
  124. package/lib/public/modules/worker-proposal.js +42 -8
  125. package/lib/public/modules/worker-runtime-picker.js +115 -0
  126. package/lib/public/modules/you-activity.js +121 -0
  127. package/lib/public/modules/you.js +251 -0
  128. package/lib/public/style.css +16 -8
  129. package/lib/public/vendor/codemirror/LICENSE +21 -0
  130. package/lib/public/vendor/codemirror/codemirror.css +344 -0
  131. package/lib/public/vendor/codemirror/codemirror.js +9884 -0
  132. package/lib/public/vendor/codemirror/continuelist.js +101 -0
  133. package/lib/public/vendor/codemirror/markdown.js +886 -0
  134. package/lib/public/vendor/codemirror/show-hint.css +37 -0
  135. package/lib/public/vendor/codemirror/show-hint.js +523 -0
  136. package/lib/sdk-bridge.js +15 -3
  137. package/lib/server-admin.js +11 -0
  138. package/lib/server-home-chat-events.js +1 -1
  139. package/lib/server-home-chat.js +25 -3
  140. package/lib/server-home-debate-planning.js +4 -1
  141. package/lib/server-home-debates.js +2 -0
  142. package/lib/server-home-mate-creation.js +4 -1
  143. package/lib/server-mate-instructions.js +44 -0
  144. package/lib/server-mates.js +12 -3
  145. package/lib/server-palette.js +1 -1
  146. package/lib/server-settings.js +65 -1
  147. package/lib/server-user-knowledge.js +119 -0
  148. package/lib/server.js +21 -1
  149. package/lib/session-visibility.js +7 -2
  150. package/lib/sessions.js +32 -6
  151. package/lib/user-knowledge-service.js +167 -0
  152. package/lib/users-permissions.js +7 -0
  153. package/lib/users-project-mate-filter-preferences.js +39 -0
  154. package/lib/users.js +6 -0
  155. package/lib/workspace-query-access.js +4 -1
  156. package/lib/ws-schema.js +50 -0
  157. package/package.json +10 -1
@@ -2,8 +2,6 @@ import { mateAvatarUrl } from './avatar.js';
2
2
  import { escapeHtml } from './utils.js';
3
3
  import { refreshIcons } from './icons.js';
4
4
  import { openSearch as openSessionSearch } from './session-search.js';
5
- import { showHomeHub, minimizeHomeHub } from './app-home-hub.js';
6
- import { openHomeConversation } from './home-mate-chat.js';
7
5
  import { startSearchClayChat, attachSearchClayChat, detachSearchClayChat, getSearchClayChatSummary } from './search-clay-chat.js';
8
6
  import { getWs } from './ws-ref.js';
9
7
  import { openProjectLog } from './project-logs.js';
@@ -110,13 +108,7 @@ export function handleClaySessionTarget(msg) {
110
108
  navigateToLog(msg.target);
111
109
  return true;
112
110
  }
113
- if (msg.target.isMate && msg.target.mateId && msg.target.homeSessionId) {
114
- showHomeHub();
115
- openHomeConversation(msg.target.mateId, msg.target.homeSessionId);
116
- } else {
117
- minimizeHomeHub();
118
- navigateToSession({ projectSlug: msg.target.projectSlug, sessionId: msg.target.sessionId }, null);
119
- }
111
+ navigateToSession({ projectSlug: msg.target.projectSlug, sessionId: msg.target.sessionId }, null);
120
112
  return true;
121
113
  }
122
114
 
@@ -166,7 +158,6 @@ export function handlePaletteSessionSwitch() {
166
158
 
167
159
  function navigateToLog(target) {
168
160
  closeCommandPalette();
169
- minimizeHomeHub();
170
161
  if (ctx.currentSlug && ctx.currentSlug() === target.projectSlug) {
171
162
  openProjectLog(target.ref);
172
163
  } else {
@@ -363,11 +354,7 @@ function resumeClayChat() {
363
354
  function activateItem(entry) {
364
355
  if (entry.type === "resume-clay") { resumeClayChat(); return; }
365
356
  if (entry.type === "ask-clay") { beginClayChat(entry.query); return; }
366
- if (entry.type === "mate-session") {
367
- closeCommandPalette();
368
- showHomeHub();
369
- openHomeConversation(entry.data.mateId, entry.data.sessionId);
370
- } else if (entry.type === "session") navigateToSession(entry.data, entry.query);
357
+ if (entry.type === "mate-session" || entry.type === "session") navigateToSession(entry.data, entry.query);
371
358
  }
372
359
 
373
360
  function navigateToSession(item, query) {
@@ -15,18 +15,18 @@ export function handleCursorSharingMessage(msg) {
15
15
  }
16
16
  if (msg.ready !== true || msg.accountAvailable === false || typeof msg.cursorSharing !== "boolean") {
17
17
  if (store.get("cursorSharingHydrated") && store.get("cursorSharingEnabled")) clearPresence();
18
- store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null });
18
+ store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null, cursorSharingPending: null, cursorSharingError: msg.error || "unavailable" });
19
19
  showToast(msg.error || "Cursor sharing is unavailable.", "warn");
20
20
  return true;
21
21
  }
22
22
  var knownUserId = store.get("myUserId");
23
23
  if (knownUserId && msg.accountId && knownUserId !== msg.accountId) {
24
24
  if (store.get("cursorSharingHydrated") && store.get("cursorSharingEnabled")) clearPresence();
25
- store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null });
25
+ store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null, cursorSharingPending: null, cursorSharingError: "account-changed" });
26
26
  return true;
27
27
  }
28
28
  var wasEnabled = store.get("cursorSharingHydrated") && store.get("cursorSharingEnabled");
29
- store.set({ cursorSharingEnabled: msg.cursorSharing, cursorSharingHydrated: true, cursorSharingAccountId: msg.accountId || null });
29
+ store.set({ cursorSharingEnabled: msg.cursorSharing, cursorSharingHydrated: true, cursorSharingAccountId: msg.accountId || null, cursorSharingPending: null, cursorSharingError: null });
30
30
  if (wasEnabled && !msg.cursorSharing) {
31
31
  var ws = getWs();
32
32
  if (ws && ws.readyState === 1) {
@@ -0,0 +1,299 @@
1
+ // Shared debate participation controls for Home and project workspaces.
2
+
3
+ function findHeader(messages) {
4
+ for (var i = (messages || []).length - 1; i >= 0; i--) if (messages[i] && messages[i].role === "debate_header") return messages[i];
5
+ return null;
6
+ }
7
+
8
+ function findActiveTurn(messages) {
9
+ for (var i = (messages || []).length - 1; i >= 0; i--) {
10
+ if (messages[i] && messages[i].role === "debate_turn" && messages[i].status === "active") return messages[i];
11
+ }
12
+ return null;
13
+ }
14
+
15
+ export function homeDebateControlState(messages) {
16
+ var header = findHeader(messages);
17
+ if (!header || ["live", "ended", "interrupted"].indexOf(header.phase) === -1) return null;
18
+ var mode = header.phase === "live" ? (header.interaction || "default") : "terminal";
19
+ return { mode: mode, header: header, turn: findActiveTurn(messages), phase: header.phase };
20
+ }
21
+
22
+ export function createDebateControls(options) {
23
+ var slotEl = null;
24
+ var normalComposerEl = null;
25
+ var modelEl = null;
26
+ var controlEl = null;
27
+ var controlMode = null;
28
+ var controlStateKey = null;
29
+ var currentState = null;
30
+ var currentRequestId = null;
31
+ var startNewDebate = null;
32
+ var inputEl = null;
33
+ var primaryEl = null;
34
+ var secondaryEl = null;
35
+ var activityEl = null;
36
+ var handEl = null;
37
+ var stopEl = null;
38
+ var composing = false;
39
+ var sizeAnimation = null;
40
+
41
+ function textElement(tag, className, text) {
42
+ var element = document.createElement(tag);
43
+ element.className = className;
44
+ element.textContent = text || "";
45
+ return element;
46
+ }
47
+
48
+ function ensureElements() {
49
+ var nextSlot = document.getElementById(options.slotId);
50
+ if (slotEl === nextSlot) return !!slotEl;
51
+ slotEl = nextSlot;
52
+ normalComposerEl = document.getElementById(options.composerId);
53
+ modelEl = options.modelId ? document.getElementById(options.modelId) : null;
54
+ controlEl = null;
55
+ controlMode = null;
56
+ controlStateKey = null;
57
+ return !!slotEl;
58
+ }
59
+
60
+ function clearControls() {
61
+ if (sizeAnimation) { sizeAnimation.cancel(); sizeAnimation = null; }
62
+ if (slotEl) slotEl.innerHTML = "";
63
+ controlEl = null;
64
+ controlMode = null;
65
+ controlStateKey = null;
66
+ currentState = null;
67
+ inputEl = null;
68
+ primaryEl = null;
69
+ secondaryEl = null;
70
+ activityEl = null;
71
+ handEl = null;
72
+ stopEl = null;
73
+ composing = false;
74
+ }
75
+
76
+ function setSpecialMode(active) {
77
+ if (normalComposerEl) normalComposerEl.hidden = active;
78
+ if (modelEl) modelEl.hidden = active;
79
+ if (slotEl) slotEl.hidden = !active;
80
+ }
81
+
82
+ function sendControl(action, data) {
83
+ if (!currentState) return false;
84
+ return options.send(action, data || {}, currentRequestId);
85
+ }
86
+
87
+ function button(label, className) {
88
+ var element = textElement("button", className, label);
89
+ element.type = "button";
90
+ return element;
91
+ }
92
+
93
+ function dots() {
94
+ var group = document.createElement("span");
95
+ group.className = "home-debate-control-dots";
96
+ group.setAttribute("aria-hidden", "true");
97
+ for (var i = 0; i < 3; i++) group.appendChild(document.createElement("i"));
98
+ return group;
99
+ }
100
+
101
+ function activityLabel(state) {
102
+ if (state.header.stopping) return state.turn ? "Stopping after " + (state.turn.mateName || "the current speaker") + " finishes" : "Stopping debate";
103
+ if (!state.turn) return state.header.handRaised ? "Your hand is raised" : "Debate is live";
104
+ var name = state.turn.mateName || "Mate";
105
+ var activity = state.turn.activity || (state.turn.text ? "speaking" : "preparing");
106
+ return name + " is " + activity.toLowerCase();
107
+ }
108
+
109
+ function lockSubmission(label) {
110
+ if (inputEl) inputEl.disabled = true;
111
+ if (primaryEl) { primaryEl.disabled = true; primaryEl.textContent = label; }
112
+ if (secondaryEl) secondaryEl.disabled = true;
113
+ }
114
+
115
+ function submitInput(action, response) {
116
+ var text = inputEl ? inputEl.value.trim() : "";
117
+ if (action === "user_floor" && !text) return false;
118
+ if (!sendControl(action, { text: text, response: response })) return false;
119
+ lockSubmission(action === "user_floor" ? "Sending…" : "Continuing…");
120
+ return true;
121
+ }
122
+
123
+ function bindInput(submit) {
124
+ inputEl.addEventListener("compositionstart", function () { composing = true; });
125
+ inputEl.addEventListener("compositionend", function () { composing = false; });
126
+ inputEl.addEventListener("input", function () {
127
+ if (controlMode === "user_floor" && primaryEl) primaryEl.disabled = !inputEl.value.trim();
128
+ });
129
+ inputEl.addEventListener("keydown", function (event) {
130
+ if (event.key !== "Enter" || event.shiftKey || event.isComposing || composing || event.keyCode === 229) return;
131
+ event.preventDefault();
132
+ submit();
133
+ });
134
+ }
135
+
136
+ function focusInputOnce() {
137
+ var target = inputEl;
138
+ if (!target) return;
139
+ var focus = function () {
140
+ if (target === inputEl && !target.disabled && target.isConnected !== false) target.focus({ preventScroll: true });
141
+ };
142
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(focus);
143
+ else focus();
144
+ }
145
+
146
+ function buildDefault(state) {
147
+ var context = document.createElement("div");
148
+ context.className = "home-debate-control-context";
149
+ context.appendChild(dots());
150
+ activityEl = textElement("span", "home-debate-control-activity", activityLabel(state));
151
+ activityEl.setAttribute("role", "status");
152
+ activityEl.setAttribute("aria-live", "polite");
153
+ context.appendChild(activityEl);
154
+ controlEl.appendChild(context);
155
+ var actions = document.createElement("div");
156
+ actions.className = "home-debate-control-actions";
157
+ handEl = button(state.header.handRaised ? "Hand raised" : "Raise hand", "home-debate-control-secondary");
158
+ handEl.setAttribute("aria-pressed", state.header.handRaised ? "true" : "false");
159
+ handEl.disabled = state.header.handRaised === true;
160
+ handEl.addEventListener("click", function () {
161
+ if (!sendControl("hand_raise")) return;
162
+ handEl.disabled = true;
163
+ handEl.textContent = "Raising hand…";
164
+ });
165
+ stopEl = button(state.header.stopping ? "Cancel stop" : "Stop debate", state.header.stopping ? "home-debate-control-secondary" : "home-debate-control-stop");
166
+ stopEl.addEventListener("click", function () {
167
+ var cancelling = currentState && currentState.header && currentState.header.stopping === true;
168
+ if (!sendControl(cancelling ? "cancel_stop" : "stop")) return;
169
+ stopEl.disabled = true;
170
+ stopEl.textContent = cancelling ? "Cancelling…" : "Stopping…";
171
+ });
172
+ actions.appendChild(handEl);
173
+ actions.appendChild(stopEl);
174
+ controlEl.appendChild(actions);
175
+ }
176
+
177
+ function buildInputMode(state) {
178
+ var isFloor = state.mode === "user_floor";
179
+ var heading = textElement("div", "home-debate-control-heading", isFloor ? "You have the floor" : "The moderator is ready to conclude");
180
+ heading.id = options.slotId + "-heading";
181
+ controlEl.appendChild(heading);
182
+ inputEl = document.createElement("textarea");
183
+ inputEl.rows = 2;
184
+ inputEl.placeholder = isFloor ? "Share your thoughts with the panel" : "Add an optional direction to continue";
185
+ inputEl.setAttribute("aria-labelledby", heading.id);
186
+ controlEl.appendChild(inputEl);
187
+ var actions = document.createElement("div");
188
+ actions.className = "home-debate-control-actions";
189
+ if (isFloor) {
190
+ primaryEl = button("Send", "home-debate-control-primary");
191
+ primaryEl.disabled = true;
192
+ primaryEl.addEventListener("click", function () { submitInput("user_floor"); });
193
+ secondaryEl = button("Pass", "home-debate-control-secondary");
194
+ secondaryEl.addEventListener("click", function () {
195
+ if (!sendControl("user_floor", { text: "(The user passed without speaking)" })) return;
196
+ lockSubmission("Sending…");
197
+ });
198
+ } else {
199
+ primaryEl = button("Continue", "home-debate-control-primary");
200
+ primaryEl.addEventListener("click", function () { submitInput("conclude", "continue"); });
201
+ secondaryEl = button("End debate", "home-debate-control-stop");
202
+ secondaryEl.addEventListener("click", function () {
203
+ if (!sendControl("conclude", { response: "end" })) return;
204
+ lockSubmission("Ending…");
205
+ });
206
+ }
207
+ actions.appendChild(primaryEl);
208
+ actions.appendChild(secondaryEl);
209
+ controlEl.appendChild(actions);
210
+ bindInput(function () { submitInput(isFloor ? "user_floor" : "conclude", isFloor ? null : "continue"); });
211
+ focusInputOnce();
212
+ }
213
+
214
+ function terminalLabel(state) {
215
+ if (state.phase === "interrupted") return "Debate interrupted when Clay restarted";
216
+ if (state.header.reason === "error") return "The debate stopped after an error";
217
+ if (state.header.reason === "stopped" || state.header.reason === "user_stopped") return "Debate stopped";
218
+ return "Debate ended";
219
+ }
220
+
221
+ function buildTerminal(state) {
222
+ var status = textElement("div", "home-debate-control-terminal-status", terminalLabel(state));
223
+ status.setAttribute("role", "status");
224
+ controlEl.appendChild(status);
225
+ var actions = document.createElement("div");
226
+ actions.className = "home-debate-control-actions";
227
+ primaryEl = button("Resume debate", "home-debate-control-primary");
228
+ primaryEl.addEventListener("click", function () {
229
+ if (!sendControl("resume")) return;
230
+ lockSubmission("Resuming…");
231
+ });
232
+ actions.appendChild(primaryEl);
233
+ if (typeof startNewDebate === "function") {
234
+ secondaryEl = button("New debate", "home-debate-control-secondary");
235
+ secondaryEl.addEventListener("click", function () { startNewDebate(); });
236
+ actions.appendChild(secondaryEl);
237
+ }
238
+ controlEl.appendChild(actions);
239
+ }
240
+
241
+ function buildControls(state) {
242
+ var previousHeight = slotEl.getBoundingClientRect ? slotEl.getBoundingClientRect().height : 0;
243
+ if (sizeAnimation) { sizeAnimation.cancel(); sizeAnimation = null; }
244
+ slotEl.innerHTML = "";
245
+ controlEl = document.createElement("section");
246
+ controlEl.className = "home-debate-control-surface home-debate-control-" + state.mode;
247
+ controlEl.setAttribute("role", state.mode === "default" ? "toolbar" : "region");
248
+ controlEl.setAttribute("aria-label", state.mode === "terminal" ? "Debate status" : "Live debate controls");
249
+ slotEl.appendChild(controlEl);
250
+ if (state.mode === "default") buildDefault(state);
251
+ else if (state.mode === "user_floor" || state.mode === "conclude") buildInputMode(state);
252
+ else buildTerminal(state);
253
+ if (previousHeight && slotEl.animate && !(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches)) {
254
+ var nextHeight = slotEl.getBoundingClientRect().height;
255
+ if (Math.abs(previousHeight - nextHeight) > 1) sizeAnimation = slotEl.animate([
256
+ { height: previousHeight + 'px' }, { height: nextHeight + 'px' }
257
+ ], { duration: 170, easing: 'ease-out' });
258
+ }
259
+ controlMode = state.mode;
260
+ controlStateKey = state.mode + ":" + state.phase + ":" + (state.header.reason || "");
261
+ }
262
+
263
+ function updateControls(state) {
264
+ if (state.mode !== "default") return;
265
+ var label = activityLabel(state);
266
+ if (activityEl && activityEl.textContent !== label) activityEl.textContent = label;
267
+ if (state.header.handRaised && handEl) {
268
+ handEl.textContent = "Hand raised";
269
+ handEl.disabled = true;
270
+ handEl.setAttribute("aria-pressed", "true");
271
+ }
272
+ if (stopEl) {
273
+ stopEl.disabled = false;
274
+ stopEl.textContent = state.header.stopping ? "Cancel stop" : "Stop debate";
275
+ stopEl.className = state.header.stopping ? "home-debate-control-secondary" : "home-debate-control-stop";
276
+ }
277
+ }
278
+
279
+ function renderControls(messages, requestId, onStartNewDebate) {
280
+ if (!ensureElements()) return false;
281
+ var state = homeDebateControlState(messages);
282
+ if (currentRequestId !== (requestId || null)) clearControls();
283
+ currentRequestId = requestId || null;
284
+ startNewDebate = onStartNewDebate || null;
285
+ if (!state) {
286
+ setSpecialMode(false);
287
+ clearControls();
288
+ return false;
289
+ }
290
+ currentState = state;
291
+ setSpecialMode(true);
292
+ var nextStateKey = state.mode + ":" + state.phase + ":" + (state.header.reason || "");
293
+ if (!controlEl || controlMode !== state.mode || controlStateKey !== nextStateKey) buildControls(state);
294
+ else updateControls(state);
295
+ return true;
296
+ }
297
+
298
+ return { render: renderControls };
299
+ }
@@ -1,3 +1,4 @@
1
+ import { resetProjectDebateWorkspace } from './project-debate-workspace.js';
1
2
  import { mateAvatarUrl } from './avatar.js';
2
3
  import { renderMarkdown, highlightCodeBlocks, buildPrintHtml, getPrintCss } from './markdown.js';
3
4
  import { escapeHtml } from './utils.js';
@@ -37,6 +38,7 @@ export function initDebate(_ctx) {
37
38
  }
38
39
 
39
40
  export function resetDebateState() {
41
+ resetProjectDebateWorkspace();
40
42
  debateActive = false;
41
43
  debateTopic = "";
42
44
  debateRound = 0;