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,41 @@
1
+ // Transient launch presentation for a new Home debate-planning conversation.
2
+
3
+ import { createHomeDebateActivityRow, resetHomeDebateActivityAnnouncement } from './home-debate-activity.js';
4
+
5
+ var pendingRequestId = null;
6
+
7
+ export function beginHomeDebateLaunch(requestId) {
8
+ resetHomeDebateActivityAnnouncement("home-debate-activity-launch");
9
+ pendingRequestId = requestId || null;
10
+ }
11
+
12
+ export function resetHomeDebateLaunch() {
13
+ pendingRequestId = null;
14
+ resetHomeDebateActivityAnnouncement("home-debate-activity-launch");
15
+ }
16
+
17
+ export function settleHomeDebateLaunch(msg) {
18
+ if (!pendingRequestId || !msg || msg.requestId !== pendingRequestId) return false;
19
+ pendingRequestId = null;
20
+ resetHomeDebateActivityAnnouncement("home-debate-activity-launch");
21
+ return true;
22
+ }
23
+
24
+ export function syncHomeDebateLaunchHistory(msg) {
25
+ if (!msg) return false;
26
+ var hasMessages = Array.isArray(msg.messages) && msg.messages.length > 0;
27
+ if (msg.debatePlanning === true && !hasMessages) {
28
+ if (!pendingRequestId) resetHomeDebateActivityAnnouncement("home-debate-activity-launch");
29
+ pendingRequestId = msg.requestId || "restored-debate-planning";
30
+ return true;
31
+ }
32
+ return settleHomeDebateLaunch(msg);
33
+ }
34
+
35
+ export function isHomeDebateLaunching() {
36
+ return !!pendingRequestId;
37
+ }
38
+
39
+ export function createHomeDebateLaunchRow() {
40
+ return createHomeDebateActivityRow("Preparing your debate", "Clay is preparing your debate", "home-debate-activity-launch");
41
+ }
@@ -0,0 +1,284 @@
1
+ import { store } from './store.js';
2
+ import { mateAvatarUrl, userAvatarUrl } from './avatar.js';
3
+ import { createAssistantBubble, createUserBubble, renderAssistantBubbleText, finalizeAssistantBubble } from './chat-bubble-renderer.js';
4
+
5
+ function textElement(tag, className, text) {
6
+ var element = document.createElement(tag);
7
+ element.className = className;
8
+ element.textContent = text || "";
9
+ return element;
10
+ }
11
+
12
+ function mateById(mateId) {
13
+ var mates = store.get('cachedMatesList') || [];
14
+ for (var i = 0; i < mates.length; i++) if (mates[i] && mates[i].id === mateId) return mates[i];
15
+ return null;
16
+ }
17
+
18
+ function debateIdentity(message, prior) {
19
+ var cached = mateById(message.speakerMateId || message.mateId);
20
+ var previous = prior || {};
21
+ var cachedProfile = cached && cached.profile ? cached.profile : (cached || {});
22
+ var name = message.mateName || previous.mateName || cachedProfile.displayName || (cached && cached.name) || "Mate";
23
+ return {
24
+ mateId: message.speakerMateId || message.mateId || previous.mateId || null,
25
+ mateName: name,
26
+ avatarStyle: message.avatarStyle || previous.avatarStyle || cachedProfile.avatarStyle || "imprint",
27
+ avatarSeed: message.avatarSeed || previous.avatarSeed || cachedProfile.avatarSeed || message.speakerMateId || message.mateId || name,
28
+ avatarColor: message.avatarColor || previous.avatarColor || cachedProfile.avatarColor || "",
29
+ avatarCustom: message.avatarCustom || previous.avatarCustom || cachedProfile.avatarCustom || "",
30
+ };
31
+ }
32
+
33
+ function mateForTurn(message) {
34
+ var identity = debateIdentity(message, message);
35
+ return {
36
+ id: identity.mateId,
37
+ name: identity.mateName,
38
+ profile: {
39
+ displayName: identity.mateName,
40
+ avatarStyle: identity.avatarStyle,
41
+ avatarSeed: identity.avatarSeed,
42
+ avatarColor: identity.avatarColor,
43
+ avatarCustom: identity.avatarCustom,
44
+ },
45
+ };
46
+ }
47
+
48
+ function findHeader(messages) {
49
+ for (var i = messages.length - 1; i >= 0; i--) if (messages[i].role === "debate_header") return messages[i];
50
+ return null;
51
+ }
52
+
53
+ export function isHomeDebateLive(messages) {
54
+ var header = findHeader(messages || []);
55
+ return !!(header && header.phase === "live");
56
+ }
57
+
58
+ export function homeDebatePhase(messages) {
59
+ var header = findHeader(messages || []);
60
+ return header ? header.phase || "live" : null;
61
+ }
62
+
63
+ function findTurn(messages, msg) {
64
+ for (var i = messages.length - 1; i >= 0; i--) {
65
+ var turn = messages[i];
66
+ if (turn.role !== "debate_turn") continue;
67
+ if (msg.turnId && turn.turnId === msg.turnId) return turn;
68
+ if (!msg.turnId && turn.status === "active" && (!msg.speakerMateId || turn.mateId === msg.speakerMateId)) return turn;
69
+ }
70
+ return null;
71
+ }
72
+
73
+ function decisionEntry(source) {
74
+ return { decisionId: source.decisionId || null, mateId: source.speakerMateId || source.mateId || null, mateName: source.mateName || "Mate", toolName: source.toolName || "Tool", action: source.action || "Use " + (source.toolName || "tool"), command: typeof source.command === "string" ? source.command : "", commandTruncated: source.commandTruncated === true, decision: source.decision === "allowed" ? "allowed" : "blocked", reason: source.reason || (source.decision === "allowed" ? "Read-only investigation" : "Not verified as read-only") };
75
+ }
76
+
77
+ function appendToolDecision(messages, source) {
78
+ var entry = decisionEntry(source);
79
+ for (var i = messages.length - 1; i >= 0; i--) {
80
+ var priorEntries = messages[i].role === "debate_tool_decision" ? (Array.isArray(messages[i].entries) ? messages[i].entries : [messages[i]]) : [];
81
+ for (var j = 0; j < priorEntries.length; j++) if (entry.decisionId && priorEntries[j].decisionId === entry.decisionId) return;
82
+ }
83
+ var last = messages.length ? messages[messages.length - 1] : null;
84
+ if (last && last.role === "debate_tool_decision") {
85
+ last.entries = (Array.isArray(last.entries) ? last.entries : []).concat([entry]);
86
+ return;
87
+ }
88
+ messages.push(Object.assign({ role: "debate_tool_decision", entries: [entry] }, entry));
89
+ }
90
+
91
+ export function normalizeHomeDebateMessages(raw) {
92
+ var messages = [];
93
+ for (var i = 0; i < (raw || []).length; i++) {
94
+ var item = raw[i];
95
+ if (!item || ["debate_header", "debate_turn", "debate_user", "debate_tool_decision"].indexOf(item.role) === -1) continue;
96
+ messages.push(Object.assign({}, item, { entries: Array.isArray(item.entries) ? item.entries.map(function (entry) { return Object.assign({}, entry); }) : item.entries }));
97
+ }
98
+ return messages;
99
+ }
100
+
101
+ export function applyHomeDebateEvent(messages, msg) {
102
+ var next = messages.slice();
103
+ var type = msg.eventType;
104
+ var header = findHeader(next);
105
+ if (type === "debate_tool_decision") {
106
+ appendToolDecision(next, msg);
107
+ return next;
108
+ }
109
+ if (type === "debate_started") {
110
+ next.push({ role: "debate_header", phase: "live", topic: msg.topic || "Debate", format: msg.format || "free_discussion", moderatorId: msg.moderatorId || null, moderatorName: msg.moderatorName || "Clay", panelists: Array.isArray(msg.panelists) ? msg.panelists : [], round: 1, interaction: null, handRaised: false });
111
+ return next;
112
+ }
113
+ if (type === "debate_turn") {
114
+ next.push(Object.assign({ role: "debate_turn", turnId: msg.turnId || "turn:" + next.length, speakerRole: msg.role || "panelist", round: msg.round || 1, text: "", activity: "", status: "active" }, debateIdentity(msg)));
115
+ if (header) next[next.indexOf(header)] = Object.assign({}, header, { phase: "live", round: msg.round || header.round || 1, interaction: null });
116
+ return next;
117
+ }
118
+ var turn = findTurn(next, msg);
119
+ if (turn) {
120
+ var turnIndex = next.indexOf(turn);
121
+ if (type === "debate_activity") next[turnIndex] = Object.assign({}, turn, { activity: msg.activity || "Thinking" });
122
+ if (type === "debate_stream") next[turnIndex] = Object.assign({}, turn, { text: (turn.text || "") + (msg.delta || ""), activity: "" });
123
+ if (type === "debate_turn_done") next[turnIndex] = Object.assign({}, turn, debateIdentity(msg, turn), { text: msg.text || turn.text || "", activity: "", status: "done" });
124
+ } else if (type === "debate_turn_done") {
125
+ next.push(Object.assign({ role: "debate_turn", turnId: msg.turnId || "turn:" + next.length, speakerRole: msg.role || "panelist", round: msg.round || 1, text: msg.text || "", activity: "", status: "done" }, debateIdentity(msg)));
126
+ }
127
+ header = findHeader(next);
128
+ if (!header) return next;
129
+ var headerIndex = next.indexOf(header);
130
+ if (type === "debate_hand_raised") next[headerIndex] = Object.assign({}, header, { handRaised: true });
131
+ if (type === "debate_stop_requested") next[headerIndex] = Object.assign({}, header, { stopping: true });
132
+ if (type === "debate_stop_cancelled") next[headerIndex] = Object.assign({}, header, { stopping: false });
133
+ if (type === "debate_conclude_confirm") next[headerIndex] = Object.assign({}, header, { interaction: "conclude" });
134
+ if (type === "debate_user_floor") next[headerIndex] = Object.assign({}, header, { interaction: "user_floor" });
135
+ if (type === "debate_user_floor_done") {
136
+ next.push({ role: "debate_user", text: msg.text || "" });
137
+ next[headerIndex] = Object.assign({}, header, { interaction: null, handRaised: false });
138
+ }
139
+ if (type === "debate_comment_injected") next.push({ role: "debate_user", text: msg.text || "" });
140
+ if (type === "debate_user_resume") next.push({ role: "debate_user", text: msg.text || "" });
141
+ if (type === "debate_resumed") next[headerIndex] = Object.assign({}, header, { phase: "live", interaction: null, round: msg.round || header.round });
142
+ if (type === "debate_ended") next[headerIndex] = Object.assign({}, header, { phase: msg.reason === "interrupted" ? "interrupted" : "ended", reason: msg.reason || "ended", interaction: null, stopping: false });
143
+ return next;
144
+ }
145
+
146
+ function createHeader(message) {
147
+ var card = document.createElement("section");
148
+ card.className = "home-debate-live-header";
149
+ card.setAttribute("aria-label", "Debate: " + (message.topic || "Untitled debate"));
150
+ var top = document.createElement("div");
151
+ top.className = "home-debate-live-header-top";
152
+ var title = document.createElement("div");
153
+ title.appendChild(textElement("span", "home-debate-live-kicker", message.phase === "live" ? "Live debate" : "Debate"));
154
+ title.appendChild(textElement("h3", "home-debate-live-topic", message.topic || "Untitled debate"));
155
+ top.appendChild(title);
156
+ top.appendChild(textElement("span", "home-debate-live-round", "Round " + (message.round || 1)));
157
+ card.appendChild(top);
158
+ var panel = [message.moderatorName || "Clay"];
159
+ for (var i = 0; i < (message.panelists || []).length; i++) panel.push(message.panelists[i].name || "Mate");
160
+ card.appendChild(textElement("p", "home-debate-live-panel", panel.join(" · ")));
161
+ if (message.phase !== "live") {
162
+ var statusText = "Debate ended";
163
+ if (message.phase === "interrupted") statusText = "Debate interrupted when Clay restarted";
164
+ else if (message.reason === "error") statusText = "The debate stopped after an error. Start a new debate to continue.";
165
+ else if (message.reason === "stopped" || message.reason === "user_stopped") statusText = "Debate stopped";
166
+ var status = textElement("p", "home-debate-live-status", statusText);
167
+ status.setAttribute("role", "status");
168
+ card.appendChild(status);
169
+ }
170
+ return card;
171
+ }
172
+
173
+ function createTurn(message, finalize) {
174
+ var mate = mateForTurn(message);
175
+ var name = message.mateName || mate.name || "Mate";
176
+ var role = message.speakerRole || "panelist";
177
+ var roleLabel = role.charAt(0).toUpperCase() + role.slice(1);
178
+ var row = createAssistantBubble({ avatarUrl: mateAvatarUrl(mate, 36), name: name, time: "" });
179
+ row.classList.add("home-chat-message", "home-debate-live-turn");
180
+ row.setAttribute("role", "article");
181
+ row.setAttribute("aria-label", name + ", " + roleLabel + ", round " + (message.round || 1));
182
+ var header = row.querySelector(".dm-bubble-header");
183
+ if (header) header.appendChild(textElement("span", "home-debate-live-turn-meta", roleLabel + " · Round " + (message.round || 1)));
184
+ var contentWrap = row.querySelector(".dm-bubble-content");
185
+ var markdown = row.querySelector(".md-content");
186
+ if (message.status === "active" && contentWrap) {
187
+ var activity = textElement("div", "home-debate-live-activity", message.activity || (message.text ? "Speaking" : "Preparing"));
188
+ activity.setAttribute("role", "status");
189
+ activity.setAttribute("aria-label", name + " is " + (message.activity || (message.text ? "speaking" : "preparing")).toLowerCase());
190
+ var dots = document.createElement("span");
191
+ dots.setAttribute("aria-hidden", "true");
192
+ for (var i = 0; i < 3; i++) dots.appendChild(document.createElement("i"));
193
+ activity.appendChild(dots);
194
+ if (markdown && typeof contentWrap.insertBefore === "function") contentWrap.insertBefore(activity, markdown);
195
+ else contentWrap.appendChild(activity);
196
+ }
197
+ if (finalize || message.status === "done") finalizeAssistantBubble(row, message.text || "", true);
198
+ else renderAssistantBubbleText(row, message.text || "", false);
199
+ return row;
200
+ }
201
+
202
+ function createUserTurn(message) {
203
+ var users = store.get('cachedAllUsers') || [];
204
+ var myUserId = store.get('myUserId');
205
+ var current = null;
206
+ for (var i = 0; i < users.length; i++) if (users[i] && users[i].id === myUserId) current = users[i];
207
+ var user = createUserBubble({ text: message.text || "", name: "You", avatarUrl: userAvatarUrl(current || { id: myUserId || "you", avatarSeed: myUserId || "you" }, 36), time: "" });
208
+ user.classList.add("home-chat-message", "home-debate-live-user");
209
+ user.setAttribute("role", "article");
210
+ user.setAttribute("aria-label", "You, participant");
211
+ var header = user.querySelector(".dm-bubble-header");
212
+ if (header) header.appendChild(textElement("span", "home-debate-live-turn-meta", "Participant"));
213
+ return user;
214
+ }
215
+
216
+ function createToolDecision(message) {
217
+ var entries = Array.isArray(message.entries) && message.entries.length ? message.entries : [decisionEntry(message)];
218
+ var groups = [];
219
+ for (var i = 0; i < entries.length; i++) {
220
+ var entry = decisionEntry(entries[i]);
221
+ var key = [entry.mateName, entry.action, entry.toolName, entry.decision, entry.reason].join("\u0000");
222
+ var group = null;
223
+ for (var j = 0; j < groups.length; j++) if (groups[j].key === key) group = groups[j];
224
+ if (group) group.count += 1;
225
+ else groups.push({ key: key, entry: entry, count: 1 });
226
+ }
227
+ var block = document.createElement("section");
228
+ block.className = "home-debate-tool-decisions";
229
+ block.setAttribute("role", "status");
230
+ block.setAttribute("aria-label", "Moderator access decisions");
231
+ var heading = textElement("div", "home-debate-tool-decisions-heading", "Moderator access");
232
+ heading.appendChild(textElement("span", "home-debate-tool-decisions-count", entries.length + (entries.length === 1 ? " check" : " checks")));
233
+ block.appendChild(heading);
234
+ var list = document.createElement("div");
235
+ list.className = "home-debate-tool-decisions-list";
236
+ for (var gi = 0; gi < groups.length; gi++) {
237
+ var allowed = groups[gi].entry.decision === "allowed";
238
+ var row = document.createElement("div");
239
+ row.className = "home-debate-tool-decision home-debate-tool-decision-" + (allowed ? "allowed" : "blocked");
240
+ var mark = textElement("span", "home-debate-tool-decision-mark", allowed ? "\u2713" : "\u00d7");
241
+ mark.setAttribute("aria-hidden", "true");
242
+ row.appendChild(mark);
243
+ row.appendChild(textElement("span", "home-debate-tool-decision-action", groups[gi].entry.action));
244
+ row.appendChild(textElement("span", "home-debate-tool-decision-tool", groups[gi].entry.toolName));
245
+ row.appendChild(textElement("span", "home-debate-tool-decision-outcome", allowed ? "Allowed" : "Blocked"));
246
+ row.appendChild(textElement("span", "home-debate-tool-decision-reason", groups[gi].entry.reason));
247
+ if (groups[gi].count > 1) row.appendChild(textElement("span", "home-debate-tool-decision-repeat", "\u00d7" + groups[gi].count));
248
+ list.appendChild(row);
249
+ }
250
+ block.appendChild(list);
251
+ var commands = entries.filter(function (entry) { return typeof entry.command === "string" && entry.command; });
252
+ if (commands.length) {
253
+ var audit = document.createElement("details");
254
+ audit.className = "home-debate-command-audit";
255
+ audit.appendChild(textElement("summary", "home-debate-command-audit-summary", "Audit " + commands.length + (commands.length === 1 ? " command" : " commands")));
256
+ var commandList = document.createElement("div");
257
+ commandList.className = "home-debate-command-audit-list";
258
+ for (var ci = 0; ci < commands.length; ci++) {
259
+ var commandRow = document.createElement("div");
260
+ commandRow.className = "home-debate-command-audit-row";
261
+ commandRow.appendChild(textElement("span", "home-debate-command-audit-meta", (commands[ci].mateName || "Mate") + " · " + (commands[ci].decision === "allowed" ? "Allowed" : "Blocked")));
262
+ commandRow.appendChild(textElement("code", "home-debate-command-audit-code", commands[ci].command + (commands[ci].commandTruncated ? "\n… command truncated at 4000 characters" : "")));
263
+ commandList.appendChild(commandRow);
264
+ }
265
+ audit.appendChild(commandList);
266
+ block.appendChild(audit);
267
+ }
268
+ return block;
269
+ }
270
+
271
+ export function createHomeDebateLiveCard(message, finalize) {
272
+ if (message.role === "debate_header") return createHeader(message);
273
+ if (message.role === "debate_user") return createUserTurn(message);
274
+ if (message.role === "debate_tool_decision") return createToolDecision(message);
275
+ return createTurn(message, finalize);
276
+ }
277
+
278
+ export function createHomeTypingIndicator() {
279
+ var typing = document.createElement("div");
280
+ typing.className = "home-chat-typing";
281
+ typing.setAttribute("aria-label", "Mate is responding");
282
+ typing.innerHTML = "<span></span><span></span><span></span>";
283
+ return typing;
284
+ }
@@ -0,0 +1,73 @@
1
+ import { store } from './store.js';
2
+
3
+ function mateName(mateId) {
4
+ var mates = store.get('cachedMatesList') || [];
5
+ for (var i = 0; i < mates.length; i++) {
6
+ if (!mates[i] || mates[i].id !== mateId) continue;
7
+ var profile = mates[i].profile || {};
8
+ return profile.displayName || mates[i].displayName || mates[i].name || "Mate";
9
+ }
10
+ return "Mate";
11
+ }
12
+
13
+ function textElement(tag, className, text) {
14
+ var element = document.createElement(tag);
15
+ element.className = className;
16
+ element.textContent = text || "";
17
+ return element;
18
+ }
19
+
20
+ export function appendDebateModelSelectors(body, proposal, disabled) {
21
+ var selections = Array.isArray(proposal.modelSelections) ? proposal.modelSelections : [];
22
+ if (!selections.length) return null;
23
+ var fieldset = document.createElement("fieldset");
24
+ fieldset.className = "home-debate-models";
25
+ fieldset.disabled = disabled === true;
26
+ fieldset.appendChild(textElement("legend", "home-debate-models-title", "Models"));
27
+ fieldset.appendChild(textElement("p", "home-debate-models-hint", "Used for this debate only. Mate defaults stay unchanged."));
28
+ for (var i = 0; i < selections.length; i++) {
29
+ var selection = selections[i];
30
+ if (!selection || !selection.mateId) continue;
31
+ var row = document.createElement("label");
32
+ row.className = "home-debate-model-row";
33
+ var identity = document.createElement("span");
34
+ identity.className = "home-debate-model-identity";
35
+ identity.appendChild(textElement("strong", "home-debate-model-name", mateName(selection.mateId)));
36
+ identity.appendChild(textElement("small", "home-debate-model-role", selection.role === "moderator" ? "Moderator" : "Panelist"));
37
+ row.appendChild(identity);
38
+ var models = Array.isArray(selection.models) ? selection.models : [];
39
+ if (models.length) {
40
+ var select = document.createElement("select");
41
+ select.className = "home-debate-model-select";
42
+ select.dataset.mateId = selection.mateId;
43
+ select.setAttribute("aria-label", "Model for " + mateName(selection.mateId));
44
+ for (var j = 0; j < models.length; j++) {
45
+ var option = document.createElement("option");
46
+ option.value = models[j].value || "";
47
+ option.textContent = models[j].label || models[j].value || "Model";
48
+ if (option.value === selection.selectedModel) option.selected = true;
49
+ select.appendChild(option);
50
+ }
51
+ select.value = selection.selectedModel || (models[0] && models[0].value) || "";
52
+ row.appendChild(select);
53
+ } else {
54
+ var unavailable = textElement("span", "home-debate-model-unavailable", "Default model");
55
+ unavailable.title = selection.error || "The model catalog is unavailable.";
56
+ row.appendChild(unavailable);
57
+ }
58
+ fieldset.appendChild(row);
59
+ }
60
+ body.appendChild(fieldset);
61
+ return fieldset;
62
+ }
63
+
64
+ export function collectDebateModelOverrides(card) {
65
+ var result = [];
66
+ if (!card || typeof card.querySelectorAll !== "function") return result;
67
+ var selects = card.querySelectorAll(".home-debate-model-select");
68
+ for (var i = 0; i < selects.length; i++) {
69
+ if (!selects[i].dataset || !selects[i].dataset.mateId || !selects[i].value) continue;
70
+ result.push({ mateId: selects[i].dataset.mateId, model: selects[i].value });
71
+ }
72
+ return result;
73
+ }