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,496 @@
1
+ // home-mate-chat.js - Embedded conversation surface for the selected mate.
2
+ import { store } from './store.js';
3
+ import { getWs } from './ws-ref.js';
4
+ import { renderAssistantBubbleText, finalizeAssistantBubble, disposeChatBubbleTree } from './chat-bubble-renderer.js';
5
+ import { createHomeOrdinaryBubble, createHomeOrdinaryTyping } from './home-chat-identity.js';
6
+ import { openHomeMateSettings, closeHomeMateSettings } from './home-mate-settings.js';
7
+ import { forgetHomeSession, rememberHomeMate, rememberHomeSession } from './home-surface.js';
8
+ import { isOwnedHomeSessionMessage, resolveHomeSessionIdentity, appendHomeStreamText, finalizeHomeAssistant } from './home-chat-stream-state.js';
9
+ import { bindHomeComposerSubmission } from './home-composer-focus.js';
10
+ import { confirmedHomeSessionModel } from './home-session-model-confirmation.js';
11
+ import { createHomeDebateTranscriptCard, createHomeDebateResponder, normalizeHomeTranscript, applyHomeDebateProposal, resolveHomeDebateProposal, applyHomeDebateQuestion, resolveHomeDebateQuestion, failHomeDebateQuestion, hasPendingHomeDebateQuestion, restoreHomeDebateProposalFocus, restoreHomeDebateQuestionFocus, requestHomeDebateComposerFocus, restoreHomeDebateComposerFocus, clearHomeDebatePlanningPending, isHomeDebatePlanningPending, syncHomeDebatePlanningPending, createHomeDebatePlanningPendingRow } from './home-debate-planning.js';
12
+ import { applyHomeDebateEvent, createHomeDebateLiveCard, homeDebatePhase } from './home-debate-live.js';
13
+ import { renderHomeDebateControls } from './home-debate-controls.js';
14
+ import { beginHomeDebateLaunch, resetHomeDebateLaunch, settleHomeDebateLaunch, syncHomeDebateLaunchHistory, isHomeDebateLaunching, createHomeDebateLaunchRow } from './home-debate-launch.js';
15
+ import { setHomeSubSurface } from './home-sub-surface.js';
16
+ import { createWorkspaceAssignmentCard, applyHomeWorkspaceAssignment } from './workspace-assignment-card.js';
17
+ import { markHomeChatActivity, followHomeChatNextRender, captureHomeChatScroll, restoreHomeChatScroll } from './home-chat-scroll.js';
18
+ import { createHomeMateProposalCard, createHomeMateProposalResponder, applyHomeMateProposal, resolveHomeMateProposal, restoreHomeMateProposalFocus } from './home-mate-creation.js';
19
+ import { findHomeMate, getHomeMateName, getHomeMateShortBio } from './home-mate-selection.js';
20
+ var messages = [], streamingText = "", streaming = false, bound = false, animateSwitch = false;
21
+ var chatEl = null, stageEl = null, messagesEl = null, suggestionsEl = null, inputEl = null, sendBtn = null;
22
+ var sessionModelEl = null, sessionModelValueEl = null, sessionModelChooseEl = null, sessionRequestSequence = 0, activeSessionRequestId = null, mateCreationActive = false;
23
+ function sendMessage(message) {
24
+ var ws = getWs();
25
+ if (!ws || ws.readyState !== 1) return false;
26
+ ws.send(JSON.stringify(message));
27
+ return true;
28
+ }
29
+ var respondToDebateTranscript = createHomeDebateResponder(sendMessage, function () { return { mateId: store.get('homeChatMateId'), sessionId: store.get('homeChatSessionId'), requestId: activeSessionRequestId }; }, function (message) { renderHomeChat(); if (message && message.role === "question") restoreHomeDebateQuestionFocus(message.toolId); });
30
+ var respondToMateProposal = createHomeMateProposalResponder(sendMessage, function () { return { mateId: store.get('homeChatMateId'), sessionId: store.get('homeChatSessionId'), requestId: activeSessionRequestId }; }, function () { renderHomeChat(); });
31
+ function getMate(mateId) { return findHomeMate(store.get('cachedMatesList') || [], mateId); }
32
+ function resizeInput() {
33
+ if (!inputEl) return;
34
+ inputEl.style.height = "auto";
35
+ inputEl.style.height = Math.min(108, inputEl.scrollHeight) + "px";
36
+ }
37
+ function nextSessionRequestId() {
38
+ sessionRequestSequence++;
39
+ return "home-session-" + Date.now() + "-" + sessionRequestSequence;
40
+ }
41
+ function resetHomeSessionModel(sessionId) {
42
+ activeSessionRequestId = nextSessionRequestId();
43
+ store.set({
44
+ homeChatSessionId: sessionId || null,
45
+ homeChatSessionModel: null,
46
+ homeChatSessionVendor: null,
47
+ homeChatSessionModelLoading: true,
48
+ });
49
+ renderSessionModel();
50
+ }
51
+ function requestHomeSession(message, sessionId) {
52
+ var requestId = nextSessionRequestId();
53
+ message.requestId = requestId;
54
+ if (!sendMessage(message)) return false;
55
+ activeSessionRequestId = requestId;
56
+ store.set({
57
+ homeChatSessionId: sessionId || null,
58
+ homeChatSessionModel: null,
59
+ homeChatSessionVendor: null,
60
+ homeChatSessionModelLoading: true,
61
+ });
62
+ renderSessionModel();
63
+ return requestId;
64
+ }
65
+ function currentSessionModelLabel() {
66
+ if (!store.get('homeChatMateId') || store.get('homeChatSessionModelLoading')) return "Loading model…";
67
+ var model = store.get('homeChatSessionModel');
68
+ if (model) return (store.get('homeChatSessionVendor') || "Vendor") + " · " + model;
69
+ return "Choose model";
70
+ }
71
+ function hasCommittedSessionModel() {
72
+ return !store.get('homeChatSessionModelLoading') && !!store.get('homeChatSessionModel');
73
+ }
74
+ function renderSessionModel() {
75
+ if (!sessionModelEl || !sessionModelValueEl || !sessionModelChooseEl) return;
76
+ var label = currentSessionModelLabel();
77
+ var needsChoice = label === "Choose model";
78
+ var canChangeDraft = !!store.get('homeChatSessionId') && !store.get('homeChatSessionModelLoading') && messages.length === 0 && !streaming;
79
+ sessionModelValueEl.textContent = needsChoice ? "" : label;
80
+ sessionModelValueEl.classList.toggle("hidden", needsChoice);
81
+ sessionModelChooseEl.classList.toggle("hidden", !needsChoice && !canChangeDraft);
82
+ sessionModelChooseEl.setAttribute("aria-label", canChangeDraft ? "Choose a model for this draft conversation and future new conversations." : "Choose a model for the current Mate. Used for new conversations.");
83
+ sessionModelEl.title = "Model for this conversation: " + label;
84
+ sessionModelEl.setAttribute("aria-label", "Model for this conversation: " + label);
85
+ }
86
+ function submitMessage() {
87
+ var mateId = store.get('homeChatMateId');
88
+ var text = inputEl ? inputEl.value.trim() : "";
89
+ if (!mateId || !text || streaming || hasPendingHomeDebateQuestion(messages) || !hasCommittedSessionModel()) return false;
90
+ if (!sendMessage({ type: "home_mate_send", mateId: mateId, sessionId: store.get('homeChatSessionId'), requestId: activeSessionRequestId, text: text })) return false;
91
+ messages.push({ role: "user", text: text, ts: Date.now() });
92
+ streamingText = "";
93
+ streaming = true;
94
+ followHomeChatNextRender();
95
+ inputEl.value = "";
96
+ resizeInput();
97
+ renderHomeChat();
98
+ return true;
99
+ }
100
+ function submitSuggestion(text) {
101
+ if (!inputEl || !text) return;
102
+ inputEl.value = text;
103
+ resizeInput();
104
+ submitMessage();
105
+ }
106
+ export function startNewHomeConversation() {
107
+ setHomeSubSurface("chat");
108
+ var mateId = store.get('homeChatMateId');
109
+ if (!mateId || streaming) return;
110
+ resetHomeDebateLaunch();
111
+ mateCreationActive = false;
112
+ if (!requestHomeSession({ type: "home_mate_new_session", mateId: mateId }, null)) return;
113
+ messages = [];
114
+ streamingText = "";
115
+ streaming = false;
116
+ animateSwitch = true;
117
+ renderHomeChat();
118
+ }
119
+ export function startHomeCapsuleCreation(mateId, description) {
120
+ if (!mateId || mateId !== store.get('homeChatMateId') || !description || streaming) return false;
121
+ setHomeSubSurface("chat"); resetHomeDebateLaunch();
122
+ mateCreationActive = false;
123
+ closeHomeMateSettings();
124
+ rememberHomeMate(mateId);
125
+ messages = []; streamingText = ""; streaming = true; animateSwitch = true;
126
+ if (inputEl) inputEl.value = "";
127
+ var requestId = requestHomeSession({
128
+ type: "home_mate_new_session",
129
+ mateId: mateId,
130
+ intent: { type: "capsule_creation", description: description },
131
+ }, null);
132
+ if (!requestId) {
133
+ streaming = false; renderHomeChat();
134
+ return false;
135
+ }
136
+ renderHomeChat();
137
+ return true;
138
+ }
139
+ function bindComposer() {
140
+ if (bound || !inputEl || !sendBtn) return;
141
+ bound = true;
142
+ inputEl.addEventListener("input", function () {
143
+ resizeInput();
144
+ sendBtn.disabled = streaming || hasPendingHomeDebateQuestion(messages) || !store.get('homeChatMateId') || !hasCommittedSessionModel() || !inputEl.value.trim();
145
+ });
146
+ bindHomeComposerSubmission(inputEl, sendBtn, submitMessage);
147
+ sessionModelChooseEl.addEventListener("click", function () {
148
+ var mate = getMate(store.get('homeChatMateId'));
149
+ if (mate) openHomeMateSettings(mate.id, sessionModelChooseEl, { section: "model", sessionId: store.get('homeChatSessionId') });
150
+ });
151
+ window.addEventListener("clay:home-mate-model-confirmed", function (event) {
152
+ handleHomeMateModelConfirmed(event.detail || {});
153
+ });
154
+ }
155
+ function ensureDom() {
156
+ if (!chatEl) chatEl = document.getElementById("home-mate-chat");
157
+ if (!stageEl) stageEl = chatEl ? chatEl.querySelector(".home-mate-chat-stage") : null;
158
+ if (!messagesEl) messagesEl = document.getElementById("home-mate-chat-messages");
159
+ if (!suggestionsEl) suggestionsEl = document.getElementById("home-mate-chat-suggestions");
160
+ if (!inputEl) inputEl = document.getElementById("home-mate-chat-input");
161
+ if (!sendBtn) sendBtn = document.getElementById("home-mate-chat-send");
162
+ if (!sessionModelEl) sessionModelEl = document.getElementById("home-mate-chat-session-model");
163
+ if (!sessionModelValueEl) sessionModelValueEl = document.getElementById("home-mate-chat-session-model-value");
164
+ if (!sessionModelChooseEl) sessionModelChooseEl = document.getElementById("home-mate-chat-session-model-choose");
165
+ bindComposer();
166
+ return !!(chatEl && stageEl && messagesEl && suggestionsEl && inputEl && sendBtn);
167
+ }
168
+ function formatTime(timestamp) { var date = timestamp ? new Date(timestamp) : null; return date ? date.getHours().toString().padStart(2, "0") + ":" + date.getMinutes().toString().padStart(2, "0") : ""; }
169
+ function appendMessage(message, mate, mateName, finalize) {
170
+ if (message.role === "assignment") return createWorkspaceAssignmentCard(message.assignment, { home: true, context: { mateId: store.get('homeChatMateId'), sessionId: store.get('homeChatSessionId'), requestId: activeSessionRequestId } });
171
+ if (message.role === "mate_proposal") return createHomeMateProposalCard(message, respondToMateProposal, function (created) { openHomeChat(created.mateId); });
172
+ if (message.role === "proposal" || message.role === "question") return createHomeDebateTranscriptCard(message, respondToDebateTranscript);
173
+ if (["debate_header", "debate_turn", "debate_user", "debate_tool_decision"].indexOf(message.role) !== -1) return createHomeDebateLiveCard(message, finalize);
174
+ var isUser = message.role === "user";
175
+ var timeText = formatTime(typeof message.ts === "number" ? message.ts : 0);
176
+ var row = createHomeOrdinaryBubble(message, mate, mateName, timeText);
177
+ if (!isUser) {
178
+ if (finalize) finalizeAssistantBubble(row, message.text || "", true);
179
+ else renderAssistantBubbleText(row, message.text || "", false);
180
+ }
181
+ if (timeText) row.title = timeText;
182
+ return row;
183
+ }
184
+ function renderEmptyState(mate, mateName) {
185
+ var empty = document.createElement("div");
186
+ empty.className = "home-mate-chat-empty";
187
+ var brand = document.createElement("div");
188
+ brand.className = "home-mate-chat-brand";
189
+ var symbol = document.createElement("img");
190
+ symbol.src = "/clay-studio-symbol.png";
191
+ symbol.alt = "";
192
+ brand.appendChild(symbol);
193
+ var wordmark = document.createElement("span");
194
+ wordmark.className = "home-sidebar-brand-wordmark home-mate-chat-brand-wordmark";
195
+ wordmark.textContent = "Clay Studio";
196
+ brand.appendChild(wordmark);
197
+ empty.appendChild(brand);
198
+ var greeting = document.createElement("h2");
199
+ greeting.textContent = mate ? "What should we work on, " + mateName + "?" : "Getting Home ready...";
200
+ empty.appendChild(greeting);
201
+ var detail = document.createElement("p");
202
+ detail.textContent = mate ? getHomeMateShortBio(mate) : "Loading your Mate and recent conversation.";
203
+ empty.appendChild(detail);
204
+ messagesEl.appendChild(empty);
205
+ suggestionsEl.innerHTML = "";
206
+ if (!mate) return;
207
+ var suggestions = ["Make me a small tool"];
208
+ for (var i = 0; i < suggestions.length; i++) {
209
+ (function (suggestion) {
210
+ var chip = document.createElement("button");
211
+ chip.type = "button";
212
+ chip.className = "home-mate-chat-suggestion";
213
+ chip.textContent = suggestion;
214
+ chip.addEventListener("click", function () { submitSuggestion(suggestion); });
215
+ suggestionsEl.appendChild(chip);
216
+ })(suggestions[i]);
217
+ }
218
+ }
219
+ export function renderHomeChat() {
220
+ if (!ensureDom()) return;
221
+ var scrollSnapshot = captureHomeChatScroll(animateSwitch);
222
+ var mateId = store.get('homeChatMateId');
223
+ var mate = getMate(mateId);
224
+ var mateName = getHomeMateName(mate);
225
+ var debateLaunching = isHomeDebateLaunching();
226
+ var hasConversation = debateLaunching || messages.length > 0 || streaming || !!streamingText;
227
+ chatEl.classList.toggle("is-empty", !hasConversation);
228
+ chatEl.classList.toggle("has-conversation", hasConversation);
229
+ disposeChatBubbleTree(messagesEl);
230
+ messagesEl.innerHTML = "";
231
+ suggestionsEl.innerHTML = "";
232
+ if (hasConversation) {
233
+ var transcript = document.createElement("div");
234
+ transcript.className = "home-mate-chat-transcript home-chat-bubble-layout";
235
+ for (var i = 0; i < messages.length; i++) transcript.appendChild(appendMessage(messages[i], mate, mateName, !streaming));
236
+ if (isHomeDebatePlanningPending()) transcript.appendChild(createHomeDebatePlanningPendingRow());
237
+ if (debateLaunching) {
238
+ transcript.appendChild(createHomeDebateLaunchRow());
239
+ } else if (streamingText) {
240
+ transcript.appendChild(appendMessage({ role: "assistant", text: streamingText, ts: Date.now() }, mate, mateName, false));
241
+ } else if (streaming && mate) {
242
+ transcript.appendChild(createHomeOrdinaryTyping(mate, mateName));
243
+ }
244
+ messagesEl.appendChild(transcript);
245
+ } else {
246
+ renderEmptyState(mate, mateName);
247
+ }
248
+ var awaitingQuestion = hasPendingHomeDebateQuestion(messages);
249
+ var debatePhase = homeDebatePhase(messages);
250
+ inputEl.disabled = !mateId || awaitingQuestion || !hasCommittedSessionModel(); if (debateLaunching || mateCreationActive || !!debatePhase) inputEl.disabled = true;
251
+ inputEl.placeholder = debateLaunching ? "Preparing your debate…" : (mateCreationActive ? "Use the interview cards above" : (debatePhase ? "Debate session" : (awaitingQuestion ? "Answer the question above to continue" : (mateId ? "Message " + mateName : "Message"))));
252
+ sendBtn.disabled = !mateId || streaming || awaitingQuestion || !hasCommittedSessionModel();
253
+ if (debateLaunching || mateCreationActive || !!debatePhase || !inputEl.value.trim()) sendBtn.disabled = true;
254
+ renderSessionModel();
255
+ renderHomeDebateControls(messages, activeSessionRequestId, function () { store.set({ homeDebateTopicFormOpen: true }); setHomeSubSurface("debates"); });
256
+ if (animateSwitch) {
257
+ messagesEl.classList.remove("is-switching");
258
+ void messagesEl.offsetWidth;
259
+ messagesEl.classList.add("is-switching");
260
+ animateSwitch = false;
261
+ }
262
+ restoreHomeChatScroll(scrollSnapshot);
263
+ }
264
+ export function openHomeChat(mateId) {
265
+ if (!mateId) return;
266
+ setHomeSubSurface("chat");
267
+ resetHomeDebateLaunch();
268
+ mateCreationActive = false;
269
+ if (store.get('homeChatMateId') && store.get('homeChatMateId') !== mateId) closeHomeMateSettings();
270
+ var preferredSession = (store.get('homeActiveSessionByMate') || {})[mateId] || null;
271
+ resetHomeSessionModel(preferredSession);
272
+ store.set({ homeChatMateId: mateId });
273
+ rememberHomeMate(mateId);
274
+ messages = [];
275
+ streamingText = "";
276
+ streaming = false;
277
+ animateSwitch = true;
278
+ if (inputEl) inputEl.value = "";
279
+ renderHomeChat();
280
+ if (store.get('homeSurfaceLoaded')) resumeHomeChat();
281
+ }
282
+ export function openHomeConversation(mateId, sessionId) {
283
+ if (!mateId || !sessionId) return;
284
+ setHomeSubSurface("chat");
285
+ resetHomeDebateLaunch();
286
+ mateCreationActive = false;
287
+ closeHomeMateSettings();
288
+ resetHomeSessionModel(sessionId);
289
+ store.set({ homeChatMateId: mateId });
290
+ rememberHomeMate(mateId);
291
+ rememberHomeSession(mateId, sessionId);
292
+ messages = [];
293
+ streamingText = "";
294
+ streaming = false;
295
+ animateSwitch = true;
296
+ if (inputEl) inputEl.value = "";
297
+ renderHomeChat();
298
+ if (store.get('homeSurfaceLoaded')) resumeHomeChat();
299
+ }
300
+ export function openHomeMateAction(kind, initialTopic) {
301
+ if (kind !== "debate" && kind !== "mate") return false;
302
+ var mates = store.get('cachedMatesList') || [];
303
+ var clay = null;
304
+ for (var i = 0; i < mates.length; i++) if (mates[i] && mates[i].builtinKey === "clay") clay = mates[i];
305
+ if (!clay || streaming) return false;
306
+ requestHomeDebateComposerFocus();
307
+ closeHomeMateSettings();
308
+ store.set({ homeChatMateId: clay.id });
309
+ rememberHomeMate(clay.id);
310
+ messages = []; streamingText = ""; streaming = false; animateSwitch = true;
311
+ resetHomeDebateLaunch();
312
+ var payload = kind === "mate" ? { type: "home_mate_creation_plan", mateId: clay.id } : { type: "home_mate_debate_plan", mateId: clay.id, topic: typeof initialTopic === "string" ? initialTopic.trim().slice(0, 1000) : "" };
313
+ var requestId = requestHomeSession(payload, null);
314
+ if (!requestId) return false;
315
+ setHomeSubSurface("chat");
316
+ if (kind === "debate") beginHomeDebateLaunch(requestId);
317
+ else { streaming = true; mateCreationActive = true; }
318
+ renderHomeChat();
319
+ return true;
320
+ }
321
+ export function resumeHomeChat() {
322
+ var mateId = store.get('homeChatMateId');
323
+ if (!mateId) return;
324
+ sendMessage({ type: "home_mate_sessions_list", mateId: mateId });
325
+ var sessionId = store.get('homeChatSessionId') || (store.get('homeActiveSessionByMate') || {})[mateId];
326
+ if (sessionId) requestHomeSession({ type: "home_mate_session_open", mateId: mateId, sessionId: sessionId }, sessionId);
327
+ else requestHomeSession({ type: "home_mate_open", mateId: mateId }, null);
328
+ }
329
+ export function closeHomeChat() {
330
+ resetHomeDebateLaunch();
331
+ sendMessage({ type: "home_mate_close" });
332
+ streaming = false;
333
+ streamingText = "";
334
+ renderHomeChat();
335
+ }
336
+ export function handleHomeMateHistory(msg) {
337
+ if (!isCurrentSessionMessage(msg)) return;
338
+ syncHomeDebateLaunchHistory(msg);
339
+ store.set({
340
+ homeChatSessionId: msg.sessionId || null,
341
+ homeChatSessionModel: typeof msg.model === "string" && msg.model ? msg.model : null,
342
+ homeChatSessionVendor: typeof msg.vendor === "string" && msg.vendor ? msg.vendor : null,
343
+ homeChatSessionModelLoading: false,
344
+ });
345
+ if (msg.sessionId) rememberHomeSession(msg.mateId, msg.sessionId);
346
+ syncHomeDebatePlanningPending(msg);
347
+ mateCreationActive = msg.mateCreation === true;
348
+ messages = normalizeHomeTranscript(msg.messages);
349
+ streamingText = "";
350
+ streaming = msg.isProcessing === true;
351
+ renderHomeChat();
352
+ if (msg.debatePlanning) restoreHomeDebateComposerFocus(inputEl);
353
+ if (msg.mateCreation) for (var i = messages.length - 1; i >= 0; i--) if (messages[i].role === "question" && messages[i].status === "pending") { restoreHomeDebateQuestionFocus(messages[i].toolId); break; }
354
+ }
355
+ export function handleHomeDebateTranscript(msg) {
356
+ if (!isCurrentSessionMessage(msg)) return;
357
+ markHomeChatActivity();
358
+ settleHomeDebateLaunch(msg);
359
+ if (msg.type === "home_debate_proposal" || msg.type === "home_debate_question" || msg.type === "home_debate_event" || msg.type === "home_mate_creation_proposal" || msg.type === "home_mate_creation_question") messages = finalizeHomeAssistant(messages, streamingText, "", Date.now());
360
+ if (msg.type === "home_debate_event") messages = applyHomeDebateEvent(messages, msg);
361
+ if (msg.type === "home_debate_proposal") messages = applyHomeDebateProposal(messages, msg);
362
+ if (msg.type === "home_debate_proposal_resolved") messages = resolveHomeDebateProposal(messages, msg);
363
+ if (msg.type === "home_debate_question") messages = applyHomeDebateQuestion(messages, msg);
364
+ if (msg.type === "home_debate_question_resolved") messages = resolveHomeDebateQuestion(messages, msg);
365
+ if (msg.type === "home_mate_creation_question") messages = applyHomeDebateQuestion(messages, msg);
366
+ if (msg.type === "home_mate_creation_question_resolved") messages = resolveHomeDebateQuestion(messages, msg);
367
+ if (msg.type === "home_mate_creation_proposal") messages = applyHomeMateProposal(messages, msg);
368
+ if (msg.type === "home_mate_creation_proposal_resolved") messages = resolveHomeMateProposal(messages, msg);
369
+ if (msg.type === "home_mate_error" && /^question_/.test(msg.code || "")) messages = failHomeDebateQuestion(messages, msg);
370
+ if (msg.type === "home_debate_proposal" || msg.type === "home_debate_question" || msg.type === "home_debate_event" || msg.type === "home_mate_creation_proposal" || msg.type === "home_mate_creation_question") { clearHomeDebatePlanningPending(); streaming = false; streamingText = ""; }
371
+ if ((msg.type === "home_debate_question_resolved" || msg.type === "home_mate_creation_question_resolved") && msg.status === "expired") clearHomeDebatePlanningPending();
372
+ renderHomeChat();
373
+ if (msg.proposalId) restoreHomeDebateProposalFocus(msg.proposalId);
374
+ if (msg.proposalId && msg.type === "home_mate_creation_proposal_resolved") restoreHomeMateProposalFocus(msg.proposalId);
375
+ if (msg.toolId && msg.type === "home_mate_creation_question") restoreHomeDebateQuestionFocus(msg.toolId);
376
+ if (msg.toolId && msg.type === "home_debate_question_resolved") restoreHomeDebateQuestionFocus(msg.toolId);
377
+ if (msg.toolId && msg.type === "home_mate_error") restoreHomeDebateQuestionFocus(msg.toolId);
378
+ }
379
+ export function handleHomeMateDelta(msg) {
380
+ if (!isCurrentSessionMessage(msg)) return;
381
+ markHomeChatActivity();
382
+ settleHomeDebateLaunch(msg);
383
+ if (msg.sessionId && msg.sessionId !== store.get('homeChatSessionId')) {
384
+ store.set({ homeChatSessionId: msg.sessionId });
385
+ rememberHomeSession(msg.mateId, msg.sessionId);
386
+ }
387
+ updateHomeSessionMetadata(msg);
388
+ streaming = true;
389
+ updateSessionProcessing(msg.mateId, msg.sessionId, true);
390
+ streamingText = appendHomeStreamText(streamingText, msg.text);
391
+ renderHomeChat();
392
+ }
393
+ export function handleHomeWorkspaceAssignment(msg) {
394
+ if (!isCurrentSessionMessage(msg) || !msg.assignment) return;
395
+ markHomeChatActivity();
396
+ messages = applyHomeWorkspaceAssignment(messages, msg);
397
+ renderHomeChat();
398
+ }
399
+ export function handleHomeMateDone(msg) {
400
+ if (!isCurrentSessionMessage(msg)) return;
401
+ markHomeChatActivity();
402
+ settleHomeDebateLaunch(msg);
403
+ if (msg.sessionId && msg.sessionId !== store.get('homeChatSessionId')) {
404
+ store.set({ homeChatSessionId: msg.sessionId });
405
+ rememberHomeSession(msg.mateId, msg.sessionId);
406
+ }
407
+ updateHomeSessionMetadata(msg);
408
+ messages = finalizeHomeAssistant(messages, streamingText, msg.text, Date.now());
409
+ streamingText = "";
410
+ streaming = false;
411
+ updateSessionProcessing(msg.mateId, msg.sessionId, false);
412
+ renderHomeChat();
413
+ }
414
+ export function handleHomeMateSessionIdentity(msg) {
415
+ var nextSessionId = resolveHomeSessionIdentity({
416
+ mateId: store.get('homeChatMateId'),
417
+ requestId: activeSessionRequestId,
418
+ sessionId: store.get('homeChatSessionId'),
419
+ }, msg);
420
+ if (!nextSessionId) return;
421
+ store.set({ homeChatSessionId: nextSessionId });
422
+ rememberHomeSession(msg.mateId, nextSessionId);
423
+ }
424
+ export function handleHomeMateError(msg) {
425
+ if (!isCurrentSessionMessage(msg)) return;
426
+ markHomeChatActivity();
427
+ settleHomeDebateLaunch(msg);
428
+ clearHomeDebatePlanningPending();
429
+ if (msg.code === "session_not_found") {
430
+ forgetHomeSession(msg.mateId);
431
+ requestHomeSession({ type: "home_mate_open", mateId: msg.mateId }, null);
432
+ return;
433
+ }
434
+ if (msg.code === "model_unavailable") {
435
+ store.set({ homeChatSessionModel: null, homeChatSessionModelLoading: false });
436
+ }
437
+ if (streamingText) messages.push({ role: "assistant", text: streamingText, ts: Date.now() });
438
+ streamingText = "";
439
+ streaming = false;
440
+ messages.push({ role: "assistant", text: msg.text || "Chat unavailable.", ts: Date.now() });
441
+ renderHomeChat();
442
+ }
443
+ export function handleHomeMateModelConfirmed(msg) {
444
+ var confirmed = confirmedHomeSessionModel({
445
+ mateId: store.get('homeChatMateId'),
446
+ sessionId: store.get('homeChatSessionId'),
447
+ }, msg);
448
+ if (!confirmed) {
449
+ if (!msg.requestedSessionId && !store.get('homeChatSessionModel')) resumeHomeChat();
450
+ return;
451
+ }
452
+ store.set({
453
+ homeChatSessionId: confirmed.sessionId,
454
+ homeChatSessionVendor: confirmed.vendor,
455
+ homeChatSessionModel: confirmed.model,
456
+ homeChatSessionModelLoading: false,
457
+ });
458
+ rememberHomeSession(msg.mateId, confirmed.sessionId);
459
+ renderHomeChat();
460
+ }
461
+ function isCurrentSessionMessage(msg) {
462
+ return isOwnedHomeSessionMessage({
463
+ mateId: store.get('homeChatMateId'),
464
+ requestId: activeSessionRequestId,
465
+ sessionId: store.get('homeChatSessionId'),
466
+ }, msg);
467
+ }
468
+ function updateHomeSessionMetadata(msg) {
469
+ var update = {};
470
+ if (Object.prototype.hasOwnProperty.call(msg, "model")) {
471
+ update.homeChatSessionModel = typeof msg.model === "string" && msg.model ? msg.model : null;
472
+ update.homeChatSessionModelLoading = false;
473
+ }
474
+ if (Object.prototype.hasOwnProperty.call(msg, "vendor")) {
475
+ update.homeChatSessionVendor = typeof msg.vendor === "string" && msg.vendor ? msg.vendor : null;
476
+ }
477
+ if (Object.keys(update).length) store.set(update);
478
+ }
479
+ export function handleHomeMateSessionsState(msg) {
480
+ if (!msg.mateId) return;
481
+ var sessions = Object.assign({}, store.get('homeMateSessions') || {});
482
+ sessions[msg.mateId] = Array.isArray(msg.sessions) ? msg.sessions : [];
483
+ store.set({ homeMateSessions: sessions });
484
+ }
485
+ function updateSessionProcessing(mateId, sessionId, processing) {
486
+ if (!mateId || !sessionId) return;
487
+ var byMate = Object.assign({}, store.get('homeMateSessions') || {});
488
+ var sessions = Array.isArray(byMate[mateId]) ? byMate[mateId].slice() : [], changed = false;
489
+ for (var i = 0; i < sessions.length; i++) {
490
+ if (!sessions[i] || sessions[i].id !== sessionId || sessions[i].isProcessing === processing) continue;
491
+ sessions[i] = Object.assign({}, sessions[i], { isProcessing: processing });
492
+ changed = true;
493
+ }
494
+ if (!changed) return;
495
+ byMate[mateId] = sessions; store.set({ homeMateSessions: byMate });
496
+ }
@@ -0,0 +1,109 @@
1
+ // Native proposal card for a Clay-led Mate creation interview.
2
+
3
+ function textElement(tag, className, text) {
4
+ var element = document.createElement(tag);
5
+ element.className = className;
6
+ element.textContent = text || "";
7
+ return element;
8
+ }
9
+
10
+ export function createHomeMateProposalCard(message, respond, openMate) {
11
+ var proposal = message.proposal || {};
12
+ var card = document.createElement("section");
13
+ card.className = "home-mate-proposal";
14
+ card.dataset.proposalId = proposal.proposalId || "";
15
+ card.setAttribute("aria-label", "New Mate proposal: " + (proposal.name || "Unnamed Mate"));
16
+ card.appendChild(textElement("div", "home-mate-proposal-eyebrow", "New Mate"));
17
+ card.appendChild(textElement("h3", "home-mate-proposal-name", proposal.name || "Unnamed Mate"));
18
+ if (proposal.bio) card.appendChild(textElement("p", "home-mate-proposal-bio", proposal.bio));
19
+ var facts = document.createElement("dl");
20
+ facts.className = "home-mate-proposal-facts";
21
+ function fact(label, value) {
22
+ if (!value) return;
23
+ facts.appendChild(textElement("dt", "", label));
24
+ facts.appendChild(textElement("dd", "", value));
25
+ }
26
+ fact("Relationship", proposal.relationship);
27
+ fact("Activities", Array.isArray(proposal.activities) ? proposal.activities.join(", ") : "");
28
+ fact("Communication", Array.isArray(proposal.communicationStyle) ? proposal.communicationStyle.join(", ") : "");
29
+ fact("Autonomy", proposal.autonomy);
30
+ card.appendChild(facts);
31
+ if (proposal.identityMarkdown) {
32
+ var details = document.createElement("details");
33
+ details.className = "home-mate-proposal-identity";
34
+ details.appendChild(textElement("summary", "", "Review full identity"));
35
+ details.appendChild(textElement("pre", "", proposal.identityMarkdown));
36
+ card.appendChild(details);
37
+ }
38
+ if (message.error) {
39
+ var error = textElement("p", "home-mate-proposal-error", message.error);
40
+ error.setAttribute("role", "alert");
41
+ card.appendChild(error);
42
+ }
43
+ var actions = document.createElement("div");
44
+ actions.className = "home-mate-proposal-actions";
45
+ if (message.status === "created" || message.status === "cancelled") {
46
+ var resolved = textElement("span", "home-mate-proposal-status", message.status === "created" ? "Mate created" : "Proposal cancelled");
47
+ resolved.setAttribute("role", "status");
48
+ resolved.tabIndex = -1;
49
+ actions.appendChild(resolved);
50
+ if (message.status === "created" && message.mateId && typeof openMate === "function") {
51
+ var mateName = message.mateName || proposal.name || "Mate";
52
+ var open = textElement("button", "home-mate-proposal-open", "Open " + mateName);
53
+ open.type = "button";
54
+ open.setAttribute("aria-label", "Open conversation with " + mateName);
55
+ open.addEventListener("click", function () { openMate(message, open); });
56
+ actions.appendChild(open);
57
+ }
58
+ } else {
59
+ var create = textElement("button", "home-mate-proposal-create", message.status === "submitting" ? "Creating…" : "Create Mate");
60
+ create.type = "button";
61
+ create.disabled = message.status === "submitting";
62
+ create.addEventListener("click", function () { respond(message, "create", create); });
63
+ var cancel = textElement("button", "home-mate-proposal-cancel", "Cancel");
64
+ cancel.type = "button";
65
+ cancel.disabled = message.status === "submitting";
66
+ cancel.addEventListener("click", function () { respond(message, "cancel", cancel); });
67
+ actions.appendChild(create);
68
+ actions.appendChild(cancel);
69
+ }
70
+ card.appendChild(actions);
71
+ return card;
72
+ }
73
+
74
+ export function applyHomeMateProposal(messages, msg) {
75
+ var id = msg && msg.proposal && msg.proposal.proposalId;
76
+ if (!id) return messages;
77
+ for (var i = 0; i < messages.length; i++) if (messages[i].role === "mate_proposal" && messages[i].proposal && messages[i].proposal.proposalId === id) return messages;
78
+ return messages.concat([{ role: "mate_proposal", proposal: msg.proposal, status: "pending", error: "" }]);
79
+ }
80
+
81
+ export function resolveHomeMateProposal(messages, msg) {
82
+ for (var i = 0; i < messages.length; i++) {
83
+ if (messages[i].role !== "mate_proposal" || !messages[i].proposal || messages[i].proposal.proposalId !== msg.proposalId) continue;
84
+ messages[i] = Object.assign({}, messages[i], { status: msg.action === "create" ? "created" : (msg.action === "cancel" ? "cancelled" : "pending"), mateId: msg.mateId || null, mateName: msg.mateName || "", error: msg.error || "" });
85
+ }
86
+ return messages;
87
+ }
88
+
89
+ export function createHomeMateProposalResponder(sendMessage, getContext, onChange) {
90
+ return function (message, action, opener) {
91
+ if (!message || message.status === "submitting") return;
92
+ var payload = { type: "home_mate_creation_proposal_response", proposalId: message.proposal.proposalId, action: action === "create" ? "create" : "cancel" };
93
+ Object.assign(payload, getContext());
94
+ if (!sendMessage(payload)) return;
95
+ message.status = "submitting";
96
+ if (opener) opener.textContent = action === "create" ? "Creating…" : "Cancelling…";
97
+ if (typeof onChange === "function") onChange(message);
98
+ };
99
+ }
100
+
101
+ export function restoreHomeMateProposalFocus(proposalId) {
102
+ var cards = document.querySelectorAll(".home-mate-proposal");
103
+ for (var i = 0; i < cards.length; i++) {
104
+ if (!cards[i].dataset || cards[i].dataset.proposalId !== proposalId) continue;
105
+ var target = cards[i].querySelector('[role="status"]') || cards[i].querySelector('[role="alert"]') || cards[i].querySelector("button");
106
+ if (target) target.focus({ preventScroll: true });
107
+ return;
108
+ }
109
+ }