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.
- package/lib/ask-user-mcp-server.js +5 -119
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +1 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +4 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +1 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-memory.js +14 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +397 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +349 -102
- package/lib/public/app.js +85 -42
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +93 -74
- package/lib/public/modules/app-connection.js +10 -1
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +102 -37
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +158 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +7 -64
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +7 -6
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +13 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +10 -6
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +111 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +18 -3
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +93 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +73 -43
- package/lib/yoke/adapters/codex.js +40 -10
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +3 -2
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- 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
|
+
}
|