clay-server 3.8.1 → 4.0.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 (189) hide show
  1. package/lib/ask-user-mcp-server.js +5 -119
  2. package/lib/builtin-mates.js +6 -6
  3. package/lib/claude-hook-installer.js +15 -0
  4. package/lib/clay-history-mcp-server.js +62 -297
  5. package/lib/daemon.js +1 -1
  6. package/lib/debate-model-selection.js +119 -0
  7. package/lib/home-debate-tool-policy.js +164 -0
  8. package/lib/home-response-notifications.js +26 -0
  9. package/lib/mate-creation-mcp-server.js +55 -0
  10. package/lib/mate-ready-creation.js +95 -0
  11. package/lib/mates.js +2 -0
  12. package/lib/notes.js +2 -1
  13. package/lib/project-ask-user.js +64 -0
  14. package/lib/project-capsule-catalog.js +101 -0
  15. package/lib/project-connection.js +4 -0
  16. package/lib/project-debate-proposal.js +133 -17
  17. package/lib/project-debate.js +214 -110
  18. package/lib/project-delegated-follow-up.js +84 -0
  19. package/lib/project-delegated-session.js +53 -0
  20. package/lib/project-filesystem.js +7 -9
  21. package/lib/project-knowledge.js +1 -0
  22. package/lib/project-mate-creation-proposal.js +120 -0
  23. package/lib/project-memory.js +14 -7
  24. package/lib/project-models.js +157 -32
  25. package/lib/project-session-notes.js +2 -2
  26. package/lib/project-session-pair.js +8 -8
  27. package/lib/project-sessions.js +66 -51
  28. package/lib/project-vendor-login.js +397 -0
  29. package/lib/project-worker-proposal.js +25 -25
  30. package/lib/project-workspace-query.js +144 -0
  31. package/lib/project.js +349 -102
  32. package/lib/public/app.js +85 -42
  33. package/lib/public/css/avatar-imprints.css +0 -1
  34. package/lib/public/css/base.css +4 -0
  35. package/lib/public/css/capsule-ui.css +389 -0
  36. package/lib/public/css/command-palette.css +306 -6
  37. package/lib/public/css/home-capsule-library.css +243 -0
  38. package/lib/public/css/home-capsule-source.css +192 -0
  39. package/lib/public/css/home-debate-live.css +146 -0
  40. package/lib/public/css/home-debate-planning.css +125 -0
  41. package/lib/public/css/home-debates-archive.css +281 -0
  42. package/lib/public/css/home-hub.css +896 -405
  43. package/lib/public/css/home-mate-creation.css +34 -0
  44. package/lib/public/css/home-mate-model-picker.css +131 -0
  45. package/lib/public/css/home-mate-settings.css +344 -0
  46. package/lib/public/css/home-session-actions.css +265 -0
  47. package/lib/public/css/home-sidebar.css +667 -0
  48. package/lib/public/css/icon-strip.css +1 -2
  49. package/lib/public/css/mates.css +7 -34
  50. package/lib/public/css/pane.css +1 -1
  51. package/lib/public/css/playbook.css +0 -80
  52. package/lib/public/css/sticky-notes.css +53 -117
  53. package/lib/public/css/tui-attention.css +0 -44
  54. package/lib/public/css/workspace-assignment.css +45 -0
  55. package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
  56. package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
  57. package/lib/public/index.html +93 -74
  58. package/lib/public/modules/app-connection.js +10 -1
  59. package/lib/public/modules/app-dm.js +43 -160
  60. package/lib/public/modules/app-home-hub.js +328 -585
  61. package/lib/public/modules/app-message-cards.js +242 -0
  62. package/lib/public/modules/app-message-router.js +84 -0
  63. package/lib/public/modules/app-messages.js +102 -37
  64. package/lib/public/modules/app-notifications.js +8 -119
  65. package/lib/public/modules/app-projects.js +9 -1
  66. package/lib/public/modules/app-rendering.js +21 -602
  67. package/lib/public/modules/avatar-imprint.js +11 -8
  68. package/lib/public/modules/chat-bubble-renderer.js +152 -0
  69. package/lib/public/modules/chat-render-runtime.js +198 -0
  70. package/lib/public/modules/command-palette.js +225 -436
  71. package/lib/public/modules/dm-render.js +82 -0
  72. package/lib/public/modules/home-capsule-creation-intent.js +31 -0
  73. package/lib/public/modules/home-capsule-library.js +146 -0
  74. package/lib/public/modules/home-capsule-source.js +383 -0
  75. package/lib/public/modules/home-chat-identity.js +35 -0
  76. package/lib/public/modules/home-chat-scroll.js +77 -0
  77. package/lib/public/modules/home-chat-stream-state.js +34 -0
  78. package/lib/public/modules/home-composer-focus.js +25 -0
  79. package/lib/public/modules/home-conversations-sheet.js +179 -0
  80. package/lib/public/modules/home-debate-activity.js +48 -0
  81. package/lib/public/modules/home-debate-controls.js +295 -0
  82. package/lib/public/modules/home-debate-launch.js +41 -0
  83. package/lib/public/modules/home-debate-live.js +284 -0
  84. package/lib/public/modules/home-debate-models.js +73 -0
  85. package/lib/public/modules/home-debate-planning.js +335 -0
  86. package/lib/public/modules/home-debates-archive.js +279 -0
  87. package/lib/public/modules/home-dock-resize.js +74 -0
  88. package/lib/public/modules/home-dock.js +446 -0
  89. package/lib/public/modules/home-mate-chat.js +496 -0
  90. package/lib/public/modules/home-mate-creation.js +109 -0
  91. package/lib/public/modules/home-mate-model-picker.js +281 -0
  92. package/lib/public/modules/home-mate-selection.js +38 -0
  93. package/lib/public/modules/home-mate-settings-menu.js +131 -0
  94. package/lib/public/modules/home-mate-settings.js +383 -0
  95. package/lib/public/modules/home-session-actions.js +373 -0
  96. package/lib/public/modules/home-session-model-confirmation.js +13 -0
  97. package/lib/public/modules/home-shell.js +9 -0
  98. package/lib/public/modules/home-sidebar-chat-list.js +63 -0
  99. package/lib/public/modules/home-sidebar.js +158 -0
  100. package/lib/public/modules/home-sub-surface.js +19 -0
  101. package/lib/public/modules/home-surface-boot.js +68 -0
  102. package/lib/public/modules/home-surface.js +141 -0
  103. package/lib/public/modules/home-tools.js +271 -0
  104. package/lib/public/modules/markdown.js +50 -2
  105. package/lib/public/modules/mate-management.js +86 -0
  106. package/lib/public/modules/mate-wizard.js +0 -7
  107. package/lib/public/modules/mention.js +17 -19
  108. package/lib/public/modules/pane-bridge.js +9 -0
  109. package/lib/public/modules/profile.js +4 -5
  110. package/lib/public/modules/project-settings.js +34 -28
  111. package/lib/public/modules/project-switcher.js +11 -5
  112. package/lib/public/modules/project-workspace-assignment.js +23 -0
  113. package/lib/public/modules/search-clay-chat.js +402 -0
  114. package/lib/public/modules/server-settings.js +14 -12
  115. package/lib/public/modules/session-actions.js +1 -1
  116. package/lib/public/modules/sidebar-mates.js +56 -552
  117. package/lib/public/modules/sidebar-mobile.js +7 -64
  118. package/lib/public/modules/sidebar-presence.js +37 -0
  119. package/lib/public/modules/split-pair-ui.js +13 -13
  120. package/lib/public/modules/split-view.js +7 -0
  121. package/lib/public/modules/sticky-notes.js +7 -6
  122. package/lib/public/modules/tool-input-composition.js +48 -0
  123. package/lib/public/modules/tool-llm-status.js +167 -0
  124. package/lib/public/modules/tool-renderer-advanced.js +285 -0
  125. package/lib/public/modules/tool-renderer-chart.js +158 -0
  126. package/lib/public/modules/tool-renderer-semantics.js +35 -0
  127. package/lib/public/modules/tool-renderer.js +464 -0
  128. package/lib/public/modules/tool-runtime.js +309 -0
  129. package/lib/public/modules/tool-ui-evaluator.js +97 -0
  130. package/lib/public/modules/tool-ui-tree.js +21 -0
  131. package/lib/public/modules/tui-attention.js +10 -0
  132. package/lib/public/modules/user-settings.js +16 -23
  133. package/lib/public/modules/vendor-login.js +287 -0
  134. package/lib/public/modules/worker-proposal.js +2 -2
  135. package/lib/public/modules/workspace-assignment-card.js +149 -0
  136. package/lib/public/modules/workspace-assignment-routing.js +4 -0
  137. package/lib/public/style.css +13 -2
  138. package/lib/runtime-env.js +65 -0
  139. package/lib/sdk-bridge.js +120 -32
  140. package/lib/sdk-message-processor.js +10 -6
  141. package/lib/server-home-capsule-creation.js +36 -0
  142. package/lib/server-home-chat-events.js +287 -0
  143. package/lib/server-home-chat.js +518 -0
  144. package/lib/server-home-clay-entry.js +65 -0
  145. package/lib/server-home-clay-session-links.js +26 -0
  146. package/lib/server-home-debate-planning.js +214 -0
  147. package/lib/server-home-debates.js +137 -0
  148. package/lib/server-home-mate-creation.js +261 -0
  149. package/lib/server-home-models.js +241 -0
  150. package/lib/server-home-preferences.js +61 -0
  151. package/lib/server-mates.js +37 -0
  152. package/lib/server-tools.js +377 -0
  153. package/lib/server.js +111 -59
  154. package/lib/session-pair-mcp-server.js +6 -6
  155. package/lib/sessions.js +18 -3
  156. package/lib/tool-capsule-source.js +142 -0
  157. package/lib/tool-control-mcp-server.js +126 -0
  158. package/lib/tool-llm.js +48 -0
  159. package/lib/tool-storage.js +77 -0
  160. package/lib/tool-ui-spec-advanced.js +82 -0
  161. package/lib/tool-ui-spec.js +261 -0
  162. package/lib/tools-registry.js +286 -0
  163. package/lib/users-home-dock-preferences.js +77 -0
  164. package/lib/users-home-surface-preferences.js +99 -0
  165. package/lib/users-preferences.js +4 -7
  166. package/lib/users.js +12 -0
  167. package/lib/whats-new-content.js +3 -3
  168. package/lib/workspace-assignment-service.js +420 -0
  169. package/lib/workspace-query-mcp-server.js +154 -0
  170. package/lib/workspace-query-service.js +492 -0
  171. package/lib/ws-schema.js +93 -12
  172. package/lib/yoke/adapters/acp.js +2 -1
  173. package/lib/yoke/adapters/antigravity.js +2 -1
  174. package/lib/yoke/adapters/claude-worker.js +11 -4
  175. package/lib/yoke/adapters/claude.js +73 -43
  176. package/lib/yoke/adapters/codex.js +40 -10
  177. package/lib/yoke/adapters/kiro.js +2 -1
  178. package/lib/yoke/claude-user-input.js +38 -0
  179. package/lib/yoke/codex-app-server.js +20 -2
  180. package/lib/yoke/codex-user-input.js +64 -0
  181. package/lib/yoke/complete-once.js +164 -0
  182. package/lib/yoke/index.js +5 -1
  183. package/lib/yoke/interface.js +19 -0
  184. package/lib/yoke/mcp-bridge-server.js +2 -6
  185. package/lib/yoke/user-input.js +254 -0
  186. package/package.json +3 -2
  187. package/lib/public/css/home-chat.css +0 -380
  188. package/lib/public/modules/home-chat.js +0 -438
  189. package/lib/server-clay-home.js +0 -245
@@ -0,0 +1,335 @@
1
+ // Safe native Home transcript presentation for a session-bound debate brief.
2
+
3
+ import { store } from './store.js';
4
+ import { refreshIcons } from './icons.js';
5
+ import { appendDebateModelSelectors, collectDebateModelOverrides } from './home-debate-models.js';
6
+ import { createHomeDebateActivityRow, resetHomeDebateActivityAnnouncement } from './home-debate-activity.js';
7
+ var pendingComposerOpener = null;
8
+ var planningPending = false;
9
+
10
+ export function clearHomeDebatePlanningPending() { planningPending = false; resetHomeDebateActivityAnnouncement("home-debate-activity-next"); }
11
+ export function isHomeDebatePlanningPending() { return planningPending; }
12
+ export function syncHomeDebatePlanningPending(msg) {
13
+ var wasPending = planningPending;
14
+ planningPending = false;
15
+ if (!msg || (msg.debatePhase !== "planning" && msg.mateCreation !== true)) return;
16
+ var history = Array.isArray(msg.messages) ? msg.messages : [];
17
+ for (var i = history.length - 1; i >= 0; i--) {
18
+ if (history[i] && history[i].role === "question") {
19
+ planningPending = history[i].status === "answered" && (wasPending || msg.isProcessing === true);
20
+ if (planningPending && !wasPending) resetHomeDebateActivityAnnouncement("home-debate-activity-next");
21
+ return;
22
+ }
23
+ }
24
+ }
25
+
26
+ export function createHomeDebatePlanningPendingRow() {
27
+ return createHomeDebateActivityRow("Preparing the next question", "Clay is preparing the next question", "home-debate-activity-next");
28
+ }
29
+
30
+ export function requestHomeDebateComposerFocus() {
31
+ pendingComposerOpener = document.activeElement || document.body;
32
+ }
33
+
34
+ export function restoreHomeDebateComposerFocus(input) {
35
+ if (!pendingComposerOpener) return;
36
+ var opener = pendingComposerOpener;
37
+ if (!document.body || !document.body.classList.contains("home-active")) { pendingComposerOpener = null; return; }
38
+ if (!input || input.disabled) return;
39
+ pendingComposerOpener = null;
40
+ var active = document.activeElement;
41
+ if (active && active !== document.body && active !== opener && active.id !== "home-sidebar-expand") return;
42
+ input.focus({ preventScroll: true });
43
+ }
44
+
45
+ function mateName(mateId) {
46
+ var mates = store.get('cachedMatesList') || [];
47
+ for (var i = 0; i < mates.length; i++) {
48
+ if (!mates[i] || mates[i].id !== mateId) continue;
49
+ var profile = mates[i].profile || {};
50
+ return profile.displayName || mates[i].displayName || mates[i].name || "Mate";
51
+ }
52
+ return "Mate";
53
+ }
54
+
55
+ function textElement(tag, className, text) {
56
+ var element = document.createElement(tag);
57
+ element.className = className;
58
+ element.textContent = text || "";
59
+ return element;
60
+ }
61
+
62
+ export function createHomeDebateProposalCard(message, respond) {
63
+ var proposal = message.proposal || {};
64
+ var card = document.createElement("section");
65
+ card.className = "debate-brief-card home-debate-proposal";
66
+ card.dataset.proposalId = proposal.proposalId || "";
67
+ card.setAttribute("aria-label", "Debate proposal: " + (proposal.topic || "Untitled debate"));
68
+ var header = textElement("div", "debate-brief-card-header", "Debate proposal");
69
+ card.appendChild(header);
70
+ var body = document.createElement("div");
71
+ body.className = "debate-brief-card-body";
72
+ body.appendChild(textElement("h3", "debate-brief-topic", proposal.topic || "Untitled debate"));
73
+ if (proposal.context) body.appendChild(textElement("p", "debate-brief-context", proposal.context));
74
+ var panelists = Array.isArray(proposal.panelists) ? proposal.panelists : [];
75
+ if (panelists.length) {
76
+ body.appendChild(textElement("div", "debate-brief-panelists-label", "Panel"));
77
+ var list = document.createElement("div");
78
+ list.className = "debate-brief-panelists";
79
+ for (var i = 0; i < panelists.length; i++) {
80
+ var name = mateName(panelists[i].mateId);
81
+ var detail = panelists[i].role ? name + " — " + panelists[i].role : name;
82
+ list.appendChild(textElement("div", "debate-brief-panelist", detail));
83
+ }
84
+ body.appendChild(list);
85
+ }
86
+ appendDebateModelSelectors(body, proposal, message.status === "submitting" || message.status === "started" || message.status === "cancelled");
87
+ card.appendChild(body);
88
+ if (message.error) {
89
+ var error = textElement("p", "home-debate-proposal-error", message.error);
90
+ error.setAttribute("role", "alert");
91
+ card.appendChild(error);
92
+ }
93
+ var actions = document.createElement("div");
94
+ actions.className = "debate-brief-actions";
95
+ if (message.status === "started" || message.status === "cancelled") {
96
+ var label = message.status === "started" ? "Debate started" : "Proposal cancelled";
97
+ var resolved = textElement("span", "debate-brief-resolved-label", label);
98
+ resolved.setAttribute("role", "status");
99
+ actions.appendChild(resolved);
100
+ } else {
101
+ var start = textElement("button", "debate-brief-start-btn", message.status === "submitting" ? "Starting…" : "Start debate");
102
+ start.type = "button";
103
+ start.disabled = message.status === "submitting";
104
+ start.setAttribute("aria-label", "Approve and start this debate");
105
+ start.addEventListener("click", function () {
106
+ var overrides = collectDebateModelOverrides(card);
107
+ if (overrides.length) respond(message, "start", start, null, overrides);
108
+ else respond(message, "start", start);
109
+ });
110
+ var cancel = textElement("button", "debate-brief-cancel-btn", "Cancel");
111
+ cancel.type = "button";
112
+ cancel.disabled = message.status === "submitting";
113
+ cancel.setAttribute("aria-label", "Cancel this debate proposal");
114
+ cancel.addEventListener("click", function () { respond(message, "cancel", cancel); });
115
+ actions.appendChild(start);
116
+ actions.appendChild(cancel);
117
+ }
118
+ card.appendChild(actions);
119
+ refreshIcons();
120
+ return card;
121
+ }
122
+
123
+ export function createHomeDebateQuestionCard(message, respond) {
124
+ var question = Array.isArray(message.questions) && message.questions.length ? message.questions[0] : {};
125
+ var card = document.createElement("section");
126
+ card.className = "home-debate-question";
127
+ card.dataset.toolId = message.toolId || "";
128
+ card.setAttribute("aria-busy", message.status === "submitting" ? "true" : "false");
129
+ var isMateCreation = message.flow === "mate_creation";
130
+ card.setAttribute("aria-label", (isMateCreation ? "Mate creation interview question: " : "Debate planning question: ") + (question.question || "Question"));
131
+ if (question.header) card.appendChild(textElement("div", "home-debate-question-header", question.header));
132
+ card.appendChild(textElement("h3", "home-debate-question-text", question.question || "Clay has a question."));
133
+ var form = document.createElement("div");
134
+ form.className = "home-debate-question-form";
135
+ var options = Array.isArray(question.options) ? question.options.slice(0, 6) : [];
136
+ var freeform = options.length === 0;
137
+ var selected = "";
138
+ var buttons = [];
139
+ for (var i = 0; i < options.length; i++) {
140
+ (function (option) {
141
+ var button = document.createElement("button");
142
+ button.type = "button";
143
+ button.className = "home-debate-question-option";
144
+ button.setAttribute("aria-pressed", "false");
145
+ button.appendChild(textElement("span", "home-debate-question-option-label", option.label || "Option"));
146
+ if (option.description) button.appendChild(textElement("span", "home-debate-question-option-description", option.description));
147
+ button.addEventListener("click", function () {
148
+ if (message.status !== "pending") return;
149
+ selected = option.label || "";
150
+ answerControl.value = "";
151
+ for (var j = 0; j < buttons.length; j++) buttons[j].setAttribute("aria-pressed", buttons[j] === button ? "true" : "false");
152
+ submit.disabled = !selected;
153
+ });
154
+ buttons.push(button);
155
+ form.appendChild(button);
156
+ })(options[i]);
157
+ }
158
+ var answerLabel = textElement("label", freeform ? "home-debate-question-freeform-label" : "home-debate-question-other-label", freeform ? "Your answer" : "Other");
159
+ var answerControl = document.createElement(freeform ? "textarea" : "input");
160
+ if (!freeform) answerControl.type = "text";
161
+ if (freeform) answerControl.rows = 3;
162
+ answerControl.className = freeform ? "home-debate-question-freeform" : "home-debate-question-other";
163
+ answerControl.placeholder = freeform ? (isMateCreation ? "Describe what you want in your own words" : "Describe the topic in your own words") : "Type another answer";
164
+ answerLabel.appendChild(answerControl);
165
+ form.appendChild(answerLabel);
166
+ var submit = textElement("button", "home-debate-question-submit", message.status === "submitting" ? "Submitting…" : "Submit answer");
167
+ submit.type = "button";
168
+ submit.disabled = message.status !== "pending" || !selected;
169
+ function submitAnswer() {
170
+ var answer = answerControl.value.trim() || selected;
171
+ if (!answer || message.status !== "pending") return;
172
+ respond(message, "answer", submit, { 0: answer });
173
+ }
174
+ answerControl.addEventListener("input", function () {
175
+ selected = answerControl.value.trim();
176
+ for (var j = 0; j < buttons.length; j++) buttons[j].setAttribute("aria-pressed", "false");
177
+ submit.disabled = !selected;
178
+ });
179
+ answerControl.addEventListener("keydown", function (event) {
180
+ var submitKey = freeform ? (event.key === "Enter" && (event.ctrlKey || event.metaKey)) : (event.key === "Enter" && !event.shiftKey);
181
+ if (submitKey) { event.preventDefault(); submitAnswer(); }
182
+ });
183
+ submit.addEventListener("click", submitAnswer);
184
+ form.appendChild(submit);
185
+ if (message.error && message.status !== "expired") {
186
+ var retryError = textElement("p", "home-debate-question-error", message.error);
187
+ retryError.setAttribute("role", "alert");
188
+ retryError.tabIndex = -1;
189
+ form.appendChild(retryError);
190
+ }
191
+ if (message.status === "answered") {
192
+ form.textContent = "";
193
+ var answer = message.answers && message.answers[0] ? String(message.answers[0]) : "Answered";
194
+ var status = textElement("p", "home-debate-question-status", "Answered: " + answer);
195
+ status.setAttribute("role", "status");
196
+ status.tabIndex = -1;
197
+ form.appendChild(status);
198
+ } else if (message.status === "expired") {
199
+ form.textContent = "";
200
+ var expired = textElement("p", "home-debate-question-error", message.error || "This question expired. Ask Clay to repeat it.");
201
+ expired.setAttribute("role", "alert");
202
+ expired.tabIndex = -1;
203
+ form.appendChild(expired);
204
+ }
205
+ card.appendChild(form);
206
+ return card;
207
+ }
208
+
209
+ export function createHomeDebateTranscriptCard(message, respond) {
210
+ return message.role === "question" ? createHomeDebateQuestionCard(message, respond) : createHomeDebateProposalCard(message, respond);
211
+ }
212
+
213
+ export function markHomeDebateProposalSubmitting(message, opener) {
214
+ message.status = "submitting";
215
+ var card = opener;
216
+ while (card && (" " + card.className + " ").indexOf(" home-debate-proposal ") === -1) card = card.parentNode;
217
+ function disableControls(node) {
218
+ if (!node) return;
219
+ if (node.tagName === "BUTTON" || node.tagName === "SELECT") node.disabled = true;
220
+ var children = node.children || [];
221
+ for (var i = 0; i < children.length; i++) disableControls(children[i]);
222
+ }
223
+ disableControls(card);
224
+ if (opener && opener.textContent === "Start debate") opener.textContent = "Starting…";
225
+ }
226
+
227
+ export function restoreHomeDebateProposalFocus(proposalId) {
228
+ if (!proposalId || !document.querySelectorAll) return;
229
+ var cards = document.querySelectorAll(".home-debate-proposal");
230
+ for (var i = 0; i < cards.length; i++) {
231
+ if (!cards[i].dataset || cards[i].dataset.proposalId !== proposalId) continue;
232
+ var target = cards[i].querySelector('[role="status"]') || cards[i].querySelector(".debate-brief-start-btn");
233
+ if (!target) return;
234
+ target.tabIndex = -1;
235
+ target.focus({ preventScroll: true });
236
+ return;
237
+ }
238
+ }
239
+
240
+ export function normalizeHomeTranscript(raw) {
241
+ return (raw || []).filter(function (message) {
242
+ return message && ((message.role === "assignment" && message.assignment) || ((message.role === "proposal" || message.role === "mate_proposal") && message.proposal) || (message.role === "question" && message.toolId) || ["debate_header", "debate_turn", "debate_user", "debate_tool_decision"].indexOf(message.role) !== -1 || ((message.role === "user" || message.role === "assistant") && typeof message.text === "string"));
243
+ }).map(function (message) {
244
+ if (message.role === "assignment") return { role: "assignment", assignment: message.assignment, requestId: message.requestId || null };
245
+ if (message.role === "proposal") return { role: "proposal", proposal: message.proposal, status: message.status || "pending", error: message.error || "" };
246
+ if (message.role === "mate_proposal") return { role: "mate_proposal", proposal: message.proposal, status: message.status || "pending", mateId: message.mateId || null, error: message.error || "" };
247
+ if (message.role === "question") return { role: "question", flow: message.flow || "debate", toolId: message.toolId, questions: message.questions || [], status: message.status || "pending", answers: message.answers || null, error: message.error || "" };
248
+ if (["debate_header", "debate_turn", "debate_user", "debate_tool_decision"].indexOf(message.role) !== -1) return Object.assign({}, message);
249
+ return { role: message.role, text: message.text, ts: message.ts || 0 };
250
+ });
251
+ }
252
+
253
+ export function applyHomeDebateQuestion(messages, msg) {
254
+ if (!msg || !msg.toolId) return messages;
255
+ for (var i = 0; i < messages.length; i++) if (messages[i].role === "question" && messages[i].toolId === msg.toolId) return messages;
256
+ return messages.concat([{ role: "question", flow: msg.type === "home_mate_creation_question" ? "mate_creation" : "debate", toolId: msg.toolId, questions: msg.questions || [], status: "pending", error: "" }]);
257
+ }
258
+
259
+ export function resolveHomeDebateQuestion(messages, msg) {
260
+ for (var i = 0; i < messages.length; i++) {
261
+ if (messages[i].role !== "question" || messages[i].toolId !== msg.toolId) continue;
262
+ messages[i] = Object.assign({}, messages[i], { status: msg.status === "answered" ? "answered" : "expired", answers: msg.answers || null, error: msg.error || "" });
263
+ }
264
+ return messages;
265
+ }
266
+
267
+ export function failHomeDebateQuestion(messages, msg) {
268
+ for (var i = messages.length - 1; i >= 0; i--) {
269
+ if (messages[i].role !== "question" || (messages[i].status !== "pending" && messages[i].status !== "submitting")) continue;
270
+ messages[i] = Object.assign({}, messages[i], { status: "pending", error: msg.text || "The answer could not be submitted. Try again." });
271
+ break;
272
+ }
273
+ return messages;
274
+ }
275
+
276
+ export function hasPendingHomeDebateQuestion(messages) {
277
+ for (var i = 0; i < messages.length; i++) if (messages[i].role === "question" && (messages[i].status === "pending" || messages[i].status === "submitting")) return true;
278
+ return false;
279
+ }
280
+
281
+ export function markHomeDebateQuestionSubmitting(message, opener) {
282
+ message.status = "submitting";
283
+ if (!planningPending) resetHomeDebateActivityAnnouncement("home-debate-activity-next");
284
+ planningPending = true;
285
+ var form = opener && opener.parentNode;
286
+ function disableControls(node) {
287
+ if (!node) return;
288
+ if (node.tagName === "BUTTON" || node.tagName === "INPUT" || node.tagName === "TEXTAREA") node.disabled = true;
289
+ var children = node.children || [];
290
+ for (var i = 0; i < children.length; i++) disableControls(children[i]);
291
+ }
292
+ disableControls(form);
293
+ if (opener) opener.textContent = "Submitting…";
294
+ }
295
+
296
+ export function createHomeDebateResponder(sendMessage, getContext, onChange) {
297
+ return function respond(message, action, opener, answers, modelOverrides) {
298
+ if (!message || message.status === "submitting") return;
299
+ var payload = message.role === "question" ? { type: message.flow === "mate_creation" ? "home_mate_creation_question_response" : "home_debate_question_response", toolId: message.toolId, answers: answers || {} } : { type: "home_debate_proposal_response", proposalId: message.proposal.proposalId, action: action, modelOverrides: Array.isArray(modelOverrides) ? modelOverrides : [] };
300
+ Object.assign(payload, getContext());
301
+ if (!sendMessage(payload)) return;
302
+ if (message.role === "question") markHomeDebateQuestionSubmitting(message, opener);
303
+ else markHomeDebateProposalSubmitting(message, opener);
304
+ if (typeof onChange === "function") onChange(message);
305
+ };
306
+ }
307
+
308
+ export function restoreHomeDebateQuestionFocus(toolId) {
309
+ if (!toolId || !document.querySelectorAll) return;
310
+ var cards = document.querySelectorAll(".home-debate-question");
311
+ for (var i = 0; i < cards.length; i++) {
312
+ if (!cards[i].dataset || cards[i].dataset.toolId !== toolId) continue;
313
+ var target = cards[i].querySelector('[role="status"]') || cards[i].querySelector('[role="alert"]') || cards[i];
314
+ target.tabIndex = -1;
315
+ target.focus({ preventScroll: true });
316
+ return;
317
+ }
318
+ }
319
+
320
+ export function applyHomeDebateProposal(messages, msg) {
321
+ var id = msg && msg.proposal && msg.proposal.proposalId;
322
+ if (!id) return messages;
323
+ for (var i = 0; i < messages.length; i++) {
324
+ if (messages[i].role === "proposal" && messages[i].proposal.proposalId === id) return messages;
325
+ }
326
+ return messages.concat([{ role: "proposal", proposal: msg.proposal, status: "pending" }]);
327
+ }
328
+
329
+ export function resolveHomeDebateProposal(messages, msg) {
330
+ for (var i = 0; i < messages.length; i++) {
331
+ if (messages[i].role !== "proposal" || messages[i].proposal.proposalId !== msg.proposalId) continue;
332
+ messages[i] = Object.assign({}, messages[i], { status: msg.action === "start" ? "started" : (msg.action === "cancel" ? "cancelled" : "pending"), error: msg.action === "error" ? (msg.error || "The debate could not be started.") : "" });
333
+ }
334
+ return messages;
335
+ }
@@ -0,0 +1,279 @@
1
+ // Full-stage Home archive for durable debate planning and live sessions.
2
+
3
+ import { store } from './store.js';
4
+ import { getWs } from './ws-ref.js';
5
+ import { refreshIcons } from './icons.js';
6
+ import { openHomeConversation, openHomeMateAction } from './home-mate-chat.js';
7
+ import { setHomeSubSurface, isHomeDebatesSurface } from './home-sub-surface.js';
8
+
9
+ var initialized = false;
10
+ var requestSequence = 0;
11
+ var topicSubmitting = false;
12
+
13
+ function element(id) {
14
+ return document.getElementById(id);
15
+ }
16
+
17
+ function focusHeading() {
18
+ var heading = element("home-debates-title");
19
+ if (!heading || heading.getClientRects && !heading.getClientRects().length) return;
20
+ heading.focus({ preventScroll: true });
21
+ }
22
+
23
+ function queueHeadingFocus() {
24
+ if (typeof requestAnimationFrame !== "function") {
25
+ focusHeading();
26
+ return;
27
+ }
28
+ requestAnimationFrame(function () { requestAnimationFrame(focusHeading); });
29
+ }
30
+
31
+ function phaseLabel(phase) {
32
+ if (phase === "live") return "Live";
33
+ if (phase === "ended") return "Ended";
34
+ if (phase === "interrupted") return "Interrupted";
35
+ return "Planning";
36
+ }
37
+
38
+ function formatLabel(format) {
39
+ if (!format) return "";
40
+ return format.replace(/[_-]+/g, " ").replace(/\b\w/g, function (letter) { return letter.toUpperCase(); });
41
+ }
42
+
43
+ function dateLabel(value) {
44
+ if (typeof value !== "number" || !isFinite(value) || value <= 0) return "Date unavailable";
45
+ try { return new Intl.DateTimeFormat(undefined, { dateStyle: "medium" }).format(new Date(value)); }
46
+ catch (error) { return new Date(value).toLocaleDateString(); }
47
+ }
48
+
49
+ function participantsLabel(participants) {
50
+ var source = Array.isArray(participants) ? participants : [];
51
+ var names = [];
52
+ for (var i = 0; i < source.length; i++) if (source[i] && source[i].name) names.push(source[i].name);
53
+ return names.length ? names.join(", ") : "Panel not selected";
54
+ }
55
+
56
+ function setArchiveOwnership(open) {
57
+ var archive = element("home-debates-archive");
58
+ var chat = element("home-mate-chat");
59
+ var messages = element("home-mate-chat-messages");
60
+ var composer = document.querySelector(".home-mate-chat-composer-frame");
61
+ var suggestions = element("home-mate-chat-suggestions");
62
+ var debateButton = element("home-sidebar-debate");
63
+ if (archive) archive.hidden = !open;
64
+ if (chat) chat.classList.toggle("home-debates-open", open);
65
+ if (messages) messages.hidden = open;
66
+ if (composer) composer.hidden = open;
67
+ if (suggestions) suggestions.hidden = open;
68
+ if (debateButton) {
69
+ debateButton.setAttribute("aria-pressed", String(open));
70
+ if (open) debateButton.setAttribute("aria-current", "page");
71
+ else debateButton.removeAttribute("aria-current");
72
+ }
73
+ }
74
+
75
+ function emptyState(title, detail, retry) {
76
+ var wrap = document.createElement("div");
77
+ wrap.className = "home-debates-empty";
78
+ var icon = document.createElement("i");
79
+ icon.dataset.lucide = retry ? "circle-alert" : "messages-square";
80
+ icon.setAttribute("aria-hidden", "true");
81
+ var heading = document.createElement("h2");
82
+ heading.textContent = title;
83
+ var copy = document.createElement("p");
84
+ copy.textContent = detail;
85
+ wrap.appendChild(icon);
86
+ wrap.appendChild(heading);
87
+ wrap.appendChild(copy);
88
+ if (retry) {
89
+ var button = document.createElement("button");
90
+ button.type = "button";
91
+ button.className = "home-debates-retry";
92
+ button.textContent = "Retry";
93
+ button.addEventListener("click", requestHomeDebates);
94
+ wrap.appendChild(button);
95
+ }
96
+ return wrap;
97
+ }
98
+
99
+ function createDebateRow(debate) {
100
+ var row = document.createElement("button");
101
+ row.type = "button";
102
+ row.className = "home-debates-row";
103
+ var phase = phaseLabel(debate.phase);
104
+ var date = dateLabel(debate.lastActivity);
105
+ var participants = participantsLabel(debate.participants);
106
+ row.setAttribute("aria-label", (debate.topic || debate.title || "Debate") + ", " + phase + ", " + participants + ", " + date);
107
+
108
+ var body = document.createElement("span");
109
+ body.className = "home-debates-row-body";
110
+ var title = document.createElement("span");
111
+ title.className = "home-debates-row-title";
112
+ title.textContent = debate.topic || debate.title || "Debate planning";
113
+ var panel = document.createElement("span");
114
+ panel.className = "home-debates-row-panel";
115
+ panel.textContent = participants;
116
+ body.appendChild(title);
117
+ body.appendChild(panel);
118
+
119
+ var meta = document.createElement("span");
120
+ meta.className = "home-debates-row-meta";
121
+ var state = document.createElement("span");
122
+ state.className = "home-debates-phase is-" + debate.phase;
123
+ state.textContent = phase;
124
+ var details = document.createElement("span");
125
+ var detailParts = [];
126
+ if (debate.format) detailParts.push(formatLabel(debate.format));
127
+ if (debate.round) detailParts.push("Round " + debate.round);
128
+ detailParts.push(date);
129
+ details.textContent = detailParts.join(" · ");
130
+ meta.appendChild(state);
131
+ meta.appendChild(details);
132
+
133
+ var arrow = document.createElement("i");
134
+ arrow.dataset.lucide = "chevron-right";
135
+ arrow.setAttribute("aria-hidden", "true");
136
+ row.appendChild(body);
137
+ row.appendChild(meta);
138
+ row.appendChild(arrow);
139
+ row.addEventListener("click", function () {
140
+ setHomeSubSurface("chat");
141
+ openHomeConversation(debate.mateId, debate.sessionId);
142
+ });
143
+ return row;
144
+ }
145
+
146
+ export function renderHomeDebatesArchive() {
147
+ var open = isHomeDebatesSurface();
148
+ setArchiveOwnership(open);
149
+ if (!open) return;
150
+ var list = element("home-debates-list");
151
+ var summary = element("home-debates-summary");
152
+ var topicForm = element("home-debates-topic-form");
153
+ if (topicForm) topicForm.hidden = !store.get('homeDebateTopicFormOpen');
154
+ if (!list || !summary) return;
155
+ list.innerHTML = "";
156
+ var status = store.get('homeDebatesStatus') || "idle";
157
+ var debates = store.get('homeDebates') || [];
158
+ if (status === "loading" || status === "idle") {
159
+ summary.textContent = "Loading debates…";
160
+ list.appendChild(emptyState("Gathering your debates", "Planning sessions and completed debates will appear here.", false));
161
+ } else if (status === "error") {
162
+ summary.textContent = "Debates could not be loaded.";
163
+ list.appendChild(emptyState("Could not load debates", store.get('homeDebatesError') || "Try again when the connection is available.", true));
164
+ } else if (!debates.length) {
165
+ summary.textContent = "No debates yet";
166
+ list.appendChild(emptyState("Your debate archive is empty", "Start a debate when you want Clay to assemble a panel.", false));
167
+ } else {
168
+ summary.textContent = debates.length + (debates.length === 1 ? " debate" : " debates");
169
+ for (var i = 0; i < debates.length; i++) list.appendChild(createDebateRow(debates[i]));
170
+ }
171
+ refreshIcons();
172
+ }
173
+
174
+ export function requestHomeDebates() {
175
+ var ws = getWs();
176
+ requestSequence += 1;
177
+ var requestId = "home-debates:" + requestSequence;
178
+ if (!ws || ws.readyState !== 1) {
179
+ store.set({ homeDebatesStatus: "error", homeDebatesRequestId: requestId, homeDebatesError: "Reconnect to load your debates." });
180
+ renderHomeDebatesArchive();
181
+ return false;
182
+ }
183
+ store.set({ homeDebatesStatus: "loading", homeDebatesRequestId: requestId, homeDebatesError: "" });
184
+ renderHomeDebatesArchive();
185
+ ws.send(JSON.stringify({ type: "home_debates_list", requestId: requestId }));
186
+ return true;
187
+ }
188
+
189
+ export function openHomeDebatesArchive() {
190
+ setHomeSubSurface("debates");
191
+ renderHomeDebatesArchive();
192
+ requestHomeDebates();
193
+ queueHeadingFocus();
194
+ }
195
+
196
+ export function restoreHomeDebatesArchive() {
197
+ if (!isHomeDebatesSurface()) return false;
198
+ renderHomeDebatesArchive();
199
+ requestHomeDebates();
200
+ return true;
201
+ }
202
+
203
+ export function handleHomeDebatesState(msg) {
204
+ if (!msg) return;
205
+ var activeRequestId = store.get('homeDebatesRequestId');
206
+ if (msg.requestId && activeRequestId && msg.requestId !== activeRequestId) return;
207
+ var debates = Array.isArray(msg.debates) ? msg.debates : [];
208
+ store.set({
209
+ homeDebatesStatus: msg.status === "error" || msg.error ? "error" : "ready",
210
+ homeDebates: debates,
211
+ homeDebatesError: msg.error || "",
212
+ });
213
+ renderHomeDebatesArchive();
214
+ }
215
+
216
+ function focusTopic() {
217
+ var input = element("home-debates-topic");
218
+ if (input) input.focus({ preventScroll: true });
219
+ }
220
+
221
+ function startNewDebate() {
222
+ var status = element("home-debates-topic-status");
223
+ if (status) status.textContent = "Press Ctrl or Command + Enter to start.";
224
+ store.set({ homeDebateTopicFormOpen: true });
225
+ renderHomeDebatesArchive();
226
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(focusTopic);
227
+ else focusTopic();
228
+ }
229
+
230
+ function cancelNewDebate() {
231
+ if (topicSubmitting) return;
232
+ store.set({ homeDebateTopicFormOpen: false });
233
+ renderHomeDebatesArchive();
234
+ var button = element("home-debates-new");
235
+ if (button) button.focus({ preventScroll: true });
236
+ }
237
+
238
+ function submitNewDebate(event) {
239
+ if (event && typeof event.preventDefault === "function") event.preventDefault();
240
+ if (topicSubmitting) return;
241
+ var input = element("home-debates-topic");
242
+ var status = element("home-debates-topic-status");
243
+ var topic = input && typeof input.value === "string" ? input.value.trim() : "";
244
+ if (!topic) {
245
+ if (status) status.textContent = "Enter a topic to start the debate.";
246
+ if (input) input.focus({ preventScroll: true });
247
+ return;
248
+ }
249
+ topicSubmitting = true;
250
+ if (status) status.textContent = "Starting debate…";
251
+ var started = openHomeMateAction("debate", topic.slice(0, 1000));
252
+ topicSubmitting = false;
253
+ if (!started) {
254
+ if (status) status.textContent = "Clay is not available right now. Try again.";
255
+ return;
256
+ }
257
+ if (input) input.value = "";
258
+ store.set({ homeDebateTopicFormOpen: false });
259
+ }
260
+
261
+ function handleTopicKeydown(event) {
262
+ if (!event || event.isComposing || event.keyCode === 229) return;
263
+ if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) submitNewDebate(event);
264
+ }
265
+
266
+ export function initHomeDebatesArchive() {
267
+ if (initialized) return;
268
+ initialized = true;
269
+ element("home-debates-new").addEventListener("click", startNewDebate);
270
+ element("home-debates-topic-form").addEventListener("submit", submitNewDebate);
271
+ element("home-debates-topic-cancel").addEventListener("click", cancelNewDebate);
272
+ element("home-debates-topic").addEventListener("keydown", handleTopicKeydown);
273
+ store.subscribe(function (state, previous) {
274
+ if (state.homeSubSurface !== previous.homeSubSurface) renderHomeDebatesArchive();
275
+ if (state.homeDebateTopicFormOpen !== previous.homeDebateTopicFormOpen) renderHomeDebatesArchive();
276
+ if (state.connected !== previous.connected && state.connected && state.homeSubSurface === "debates") requestHomeDebates();
277
+ });
278
+ renderHomeDebatesArchive();
279
+ }