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,373 @@
1
+ // Home conversation row actions and server-authoritative details dialog.
2
+
3
+ import { store } from './store.js';
4
+ import { copyToClipboard } from './utils.js';
5
+
6
+ var menu = null;
7
+ var menuTrigger = null;
8
+ var detailsOverlay = null;
9
+ var detailsOpener = null;
10
+ var detailsKey = null;
11
+ var detailsConversation = null;
12
+ var copyTimers = [];
13
+
14
+ function mateNames() {
15
+ var result = {};
16
+ var mates = store.get('cachedMatesList') || [];
17
+ for (var i = 0; i < mates.length; i++) {
18
+ if (!mates[i] || mates[i].archived) continue;
19
+ var profile = mates[i].profile || {};
20
+ result[mates[i].id] = profile.displayName || mates[i].displayName || mates[i].name || "Mate";
21
+ }
22
+ return result;
23
+ }
24
+
25
+ function safeText(value, fallback) {
26
+ return typeof value === "string" && value ? value : fallback;
27
+ }
28
+
29
+ function conversationKey(conversation) {
30
+ var identity = conversation.localId != null ? "local:" + conversation.localId : conversation.sessionId;
31
+ return conversation.mateId + ":" + identity;
32
+ }
33
+
34
+ export function getHomeSessionConversations() {
35
+ var byMate = store.get('homeMateSessions') || {};
36
+ var names = mateNames();
37
+ var mateIds = Object.keys(byMate);
38
+ var result = [];
39
+ for (var i = 0; i < mateIds.length; i++) {
40
+ if (!names[mateIds[i]]) continue;
41
+ var sessions = Array.isArray(byMate[mateIds[i]]) ? byMate[mateIds[i]] : [];
42
+ for (var j = 0; j < sessions.length; j++) {
43
+ if (!sessions[j] || typeof sessions[j].id !== "string" || !sessions[j].id) continue;
44
+ result.push({
45
+ mateId: mateIds[i],
46
+ mateName: names[mateIds[i]],
47
+ sessionId: sessions[j].id,
48
+ cliSessionId: safeText(sessions[j].cliSessionId, null),
49
+ localId: sessions[j].localId != null ? sessions[j].localId : null,
50
+ title: safeText(sessions[j].title, "New conversation"),
51
+ vendor: safeText(sessions[j].vendor, null),
52
+ model: safeText(sessions[j].model, null),
53
+ createdAt: typeof sessions[j].createdAt === "number" ? sessions[j].createdAt : 0,
54
+ lastActivity: typeof sessions[j].lastActivity === "number" ? sessions[j].lastActivity : 0,
55
+ isProcessing: sessions[j].isProcessing === true,
56
+ });
57
+ }
58
+ }
59
+ result.sort(function (a, b) { return b.lastActivity - a.lastActivity; });
60
+ return result;
61
+ }
62
+
63
+ function findConversation(key) {
64
+ var conversations = getHomeSessionConversations();
65
+ for (var i = 0; i < conversations.length; i++) {
66
+ if (conversationKey(conversations[i]) === key) return conversations[i];
67
+ }
68
+ return null;
69
+ }
70
+
71
+ function menuItems() {
72
+ return menu ? menu.querySelectorAll('[role="menuitem"]') : [];
73
+ }
74
+
75
+ function positionMenu() {
76
+ if (!menu || !menuTrigger || !menuTrigger.isConnected) return;
77
+ var rect = menuTrigger.getBoundingClientRect();
78
+ var menuRect = menu.getBoundingClientRect();
79
+ var left = Math.min(window.innerWidth - menuRect.width - 8, Math.max(8, rect.right - menuRect.width));
80
+ var top = rect.bottom + 5;
81
+ if (top + menuRect.height > window.innerHeight - 8) top = Math.max(8, rect.top - menuRect.height - 5);
82
+ menu.style.left = left + "px";
83
+ menu.style.top = top + "px";
84
+ }
85
+
86
+ function closeMenu(returnFocus) {
87
+ var trigger = menuTrigger;
88
+ if (menu) menu.remove();
89
+ if (trigger) trigger.setAttribute("aria-expanded", "false");
90
+ menu = null;
91
+ menuTrigger = null;
92
+ document.removeEventListener("pointerdown", handleMenuOutside, true);
93
+ document.removeEventListener("keydown", handleMenuKeydown, true);
94
+ window.removeEventListener("resize", handleViewportChange);
95
+ window.removeEventListener("scroll", handleViewportChange, true);
96
+ if (returnFocus && trigger && trigger.isConnected) trigger.focus({ preventScroll: true });
97
+ }
98
+
99
+ function handleViewportChange() {
100
+ closeMenu(false);
101
+ }
102
+
103
+ function handleMenuOutside(event) {
104
+ if (menu && !menu.contains(event.target) && event.target !== menuTrigger) closeMenu(false);
105
+ }
106
+
107
+ function handleMenuKeydown(event) {
108
+ if (!menu) return;
109
+ var items = menuItems();
110
+ if (event.key === "Escape") {
111
+ event.preventDefault();
112
+ event.stopPropagation();
113
+ closeMenu(true);
114
+ return;
115
+ }
116
+ if (event.key !== "ArrowDown" && event.key !== "ArrowUp" && event.key !== "Home" && event.key !== "End") return;
117
+ event.preventDefault();
118
+ var current = Array.prototype.indexOf.call(items, document.activeElement);
119
+ var next = 0;
120
+ if (event.key === "End") next = items.length - 1;
121
+ else if (event.key === "ArrowUp") next = current <= 0 ? items.length - 1 : current - 1;
122
+ else if (event.key === "ArrowDown") next = current < 0 || current === items.length - 1 ? 0 : current + 1;
123
+ if (items[next]) items[next].focus({ preventScroll: true });
124
+ }
125
+
126
+ function openMenu(trigger, conversation, options) {
127
+ closeMenu(false);
128
+ menuTrigger = trigger;
129
+ trigger.setAttribute("aria-expanded", "true");
130
+ menu = document.createElement("div");
131
+ menu.className = "home-session-actions-menu";
132
+ menu.setAttribute("role", "menu");
133
+ menu.setAttribute("aria-label", "Actions for " + conversation.title);
134
+ var details = document.createElement("button");
135
+ details.type = "button";
136
+ details.className = "home-session-actions-menu-item";
137
+ details.setAttribute("role", "menuitem");
138
+ details.textContent = "View details";
139
+ details.addEventListener("click", function (event) {
140
+ event.preventDefault();
141
+ event.stopPropagation();
142
+ var opener = options && options.detailsOpener ? options.detailsOpener : trigger;
143
+ closeMenu(false);
144
+ if (options && options.beforeOpenDetails) options.beforeOpenDetails();
145
+ openHomeSessionDetails(conversation, opener);
146
+ });
147
+ menu.appendChild(details);
148
+ document.body.appendChild(menu);
149
+ requestAnimationFrame(function () {
150
+ positionMenu();
151
+ details.focus({ preventScroll: true });
152
+ });
153
+ document.addEventListener("pointerdown", handleMenuOutside, true);
154
+ document.addEventListener("keydown", handleMenuKeydown, true);
155
+ window.addEventListener("resize", handleViewportChange);
156
+ window.addEventListener("scroll", handleViewportChange, true);
157
+ }
158
+
159
+ export function createHomeSessionActionsTrigger(conversation, options) {
160
+ var trigger = document.createElement("button");
161
+ trigger.type = "button";
162
+ trigger.className = "home-session-actions-trigger";
163
+ trigger.setAttribute("aria-label", "Conversation actions for " + conversation.title);
164
+ trigger.setAttribute("title", "Conversation actions");
165
+ trigger.setAttribute("aria-haspopup", "menu");
166
+ trigger.setAttribute("aria-expanded", "false");
167
+ trigger.innerHTML = '<span class="home-session-actions-mark" aria-hidden="true">•••</span>';
168
+ trigger.addEventListener("click", function (event) {
169
+ event.preventDefault();
170
+ event.stopPropagation();
171
+ if (menu && menuTrigger === trigger) closeMenu(false);
172
+ else openMenu(trigger, conversation, options || {});
173
+ });
174
+ trigger.addEventListener("keydown", function (event) {
175
+ if (event.key !== "ArrowDown" && event.key !== "ArrowUp" && event.key !== "Home" && event.key !== "End") return;
176
+ event.preventDefault();
177
+ event.stopPropagation();
178
+ openMenu(trigger, conversation, options || {});
179
+ requestAnimationFrame(function () {
180
+ var items = menuItems();
181
+ if (!items.length) return;
182
+ items[event.key === "ArrowUp" || event.key === "End" ? items.length - 1 : 0].focus({ preventScroll: true });
183
+ });
184
+ });
185
+ return trigger;
186
+ }
187
+
188
+ export function disposeHomeSessionActionsMenu() {
189
+ closeMenu(false);
190
+ }
191
+
192
+ function formatTime(value) {
193
+ if (!value) return "Not available";
194
+ var date = new Date(value);
195
+ if (isNaN(date.getTime())) return "Not available";
196
+ return date.toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
197
+ }
198
+
199
+ function clearCopyTimers() {
200
+ for (var i = 0; i < copyTimers.length; i++) clearTimeout(copyTimers[i]);
201
+ copyTimers = [];
202
+ }
203
+
204
+ function addDetailField(list, label, value, copyValue, copyKey) {
205
+ var row = document.createElement("div");
206
+ row.className = "home-session-details-field";
207
+ var term = document.createElement("dt");
208
+ term.textContent = label;
209
+ var description = document.createElement("dd");
210
+ var text = document.createElement("span");
211
+ text.textContent = value;
212
+ if (copyKey) text.className = "home-session-details-id";
213
+ description.appendChild(text);
214
+ if (copyValue) {
215
+ var copy = document.createElement("button");
216
+ copy.type = "button";
217
+ copy.className = "home-session-details-copy";
218
+ copy.dataset.homeSessionCopy = copyKey;
219
+ copy.setAttribute("aria-label", "Copy " + label);
220
+ copy.textContent = "Copy";
221
+ copy.addEventListener("click", function () {
222
+ copyToClipboard(copyValue).then(function () {
223
+ copy.textContent = "Copied";
224
+ var timer = setTimeout(function () { if (copy.isConnected) copy.textContent = "Copy"; }, 1200);
225
+ copyTimers.push(timer);
226
+ }).catch(function () {
227
+ copy.textContent = "Copy failed";
228
+ });
229
+ });
230
+ description.appendChild(copy);
231
+ }
232
+ row.appendChild(term);
233
+ row.appendChild(description);
234
+ list.appendChild(row);
235
+ }
236
+
237
+ function renderDetails() {
238
+ if (!detailsOverlay || !detailsConversation) return;
239
+ var body = detailsOverlay.querySelector(".home-session-details-body");
240
+ if (!body) return;
241
+ body.innerHTML = "";
242
+ var summary = document.createElement("div");
243
+ summary.className = "home-session-details-summary";
244
+ var title = document.createElement("h3");
245
+ title.textContent = detailsConversation.title;
246
+ var mate = document.createElement("p");
247
+ mate.textContent = "Conversation with " + detailsConversation.mateName;
248
+ summary.appendChild(title);
249
+ summary.appendChild(mate);
250
+ body.appendChild(summary);
251
+ var list = document.createElement("dl");
252
+ list.className = "home-session-details-list";
253
+ addDetailField(list, "Status", detailsConversation.isProcessing ? "Working" : "Ready");
254
+ addDetailField(list, "Provider", detailsConversation.vendor || "Not available");
255
+ addDetailField(list, "Model", detailsConversation.model || "Not available");
256
+ addDetailField(list, "Created", formatTime(detailsConversation.createdAt));
257
+ addDetailField(list, "Last activity", formatTime(detailsConversation.lastActivity));
258
+ addDetailField(list, "Session reference", detailsConversation.sessionId, detailsConversation.sessionId, "reference");
259
+ if (detailsConversation.cliSessionId) {
260
+ addDetailField(list, "Session ID", detailsConversation.cliSessionId, detailsConversation.cliSessionId, "session-id");
261
+ } else {
262
+ addDetailField(list, "Session ID", "Not assigned yet — this conversation is still local.");
263
+ }
264
+ var localId = detailsConversation.localId == null ? "Not available" : String(detailsConversation.localId);
265
+ addDetailField(list, "Local ID", localId, detailsConversation.localId == null ? null : localId, "local-id");
266
+ body.appendChild(list);
267
+ }
268
+
269
+ function focusableDetails() {
270
+ return detailsOverlay ? detailsOverlay.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), [tabindex]:not([tabindex="-1"])') : [];
271
+ }
272
+
273
+ function handleDetailsKeydown(event) {
274
+ if (!detailsOverlay) return;
275
+ if (event.key === "Escape") {
276
+ event.preventDefault();
277
+ event.stopPropagation();
278
+ closeHomeSessionDetails();
279
+ return;
280
+ }
281
+ if (event.key !== "Tab") return;
282
+ var focusable = focusableDetails();
283
+ if (!focusable.length) return;
284
+ var first = focusable[0];
285
+ var last = focusable[focusable.length - 1];
286
+ if (event.shiftKey && (document.activeElement === first || !detailsOverlay.contains(document.activeElement))) {
287
+ event.preventDefault();
288
+ last.focus();
289
+ } else if (!event.shiftKey && (document.activeElement === last || !detailsOverlay.contains(document.activeElement))) {
290
+ event.preventDefault();
291
+ first.focus();
292
+ }
293
+ }
294
+
295
+ export function closeHomeSessionDetails() {
296
+ var opener = detailsOpener;
297
+ clearCopyTimers();
298
+ if (detailsOverlay) detailsOverlay.remove();
299
+ detailsOverlay = null;
300
+ detailsOpener = null;
301
+ detailsKey = null;
302
+ detailsConversation = null;
303
+ document.removeEventListener("keydown", handleDetailsKeydown, true);
304
+ document.body.classList.remove("home-session-details-open");
305
+ if (opener && opener.isConnected) opener.focus({ preventScroll: true });
306
+ }
307
+
308
+ export function openHomeSessionDetails(conversation, opener) {
309
+ if (!conversation || !conversation.mateId || !conversation.sessionId) return false;
310
+ closeHomeSessionDetails();
311
+ detailsConversation = conversation;
312
+ detailsKey = conversationKey(conversation);
313
+ detailsOpener = opener || document.activeElement;
314
+ var overlay = document.createElement("div");
315
+ overlay.className = "home-session-details-overlay";
316
+ var dialog = document.createElement("section");
317
+ dialog.className = "home-session-details-dialog";
318
+ dialog.setAttribute("role", "dialog");
319
+ dialog.setAttribute("aria-modal", "true");
320
+ dialog.setAttribute("aria-labelledby", "home-session-details-title");
321
+ var header = document.createElement("header");
322
+ header.className = "home-session-details-header";
323
+ var title = document.createElement("h2");
324
+ title.id = "home-session-details-title";
325
+ title.textContent = "Conversation details";
326
+ var close = document.createElement("button");
327
+ close.type = "button";
328
+ close.className = "home-session-details-close";
329
+ close.setAttribute("aria-label", "Close conversation details");
330
+ close.textContent = "×";
331
+ close.addEventListener("click", closeHomeSessionDetails);
332
+ header.appendChild(title);
333
+ header.appendChild(close);
334
+ var body = document.createElement("div");
335
+ body.className = "home-session-details-body";
336
+ dialog.appendChild(header);
337
+ dialog.appendChild(body);
338
+ overlay.appendChild(dialog);
339
+ overlay.addEventListener("click", function (event) { if (event.target === overlay) closeHomeSessionDetails(); });
340
+ document.body.appendChild(overlay);
341
+ detailsOverlay = overlay;
342
+ document.body.classList.add("home-session-details-open");
343
+ document.addEventListener("keydown", handleDetailsKeydown, true);
344
+ renderDetails();
345
+ requestAnimationFrame(function () { close.focus({ preventScroll: true }); });
346
+ return true;
347
+ }
348
+
349
+ export function syncHomeSessionDetails() {
350
+ if (!detailsOverlay || !detailsKey) return;
351
+ var next = findConversation(detailsKey);
352
+ if (!next) {
353
+ closeHomeSessionDetails();
354
+ return;
355
+ }
356
+ var previous = JSON.stringify(detailsConversation);
357
+ if (JSON.stringify(next) === previous) return;
358
+ var activeCopy = document.activeElement && document.activeElement.dataset ? document.activeElement.dataset.homeSessionCopy : null;
359
+ detailsConversation = next;
360
+ renderDetails();
361
+ if (!activeCopy || !detailsOverlay) return;
362
+ var copies = detailsOverlay.querySelectorAll("[data-home-session-copy]");
363
+ for (var i = 0; i < copies.length; i++) {
364
+ if (copies[i].dataset.homeSessionCopy !== activeCopy) continue;
365
+ copies[i].focus({ preventScroll: true });
366
+ break;
367
+ }
368
+ }
369
+
370
+ export function disposeHomeSessionActions() {
371
+ closeMenu(false);
372
+ closeHomeSessionDetails();
373
+ }
@@ -0,0 +1,13 @@
1
+ // Correlate a confirmed draft-model update with the exact active Home session.
2
+
3
+ export function confirmedHomeSessionModel(active, message) {
4
+ if (!active || !message || message.sessionApplied !== true) return null;
5
+ if (!active.mateId || message.mateId !== active.mateId) return null;
6
+ if (!active.sessionId || (message.sessionId !== active.sessionId && message.requestedSessionId !== active.sessionId)) return null;
7
+ if (!message.sessionId || !message.sessionModel || !message.sessionVendor) return null;
8
+ return {
9
+ sessionId: message.sessionId,
10
+ vendor: message.sessionVendor,
11
+ model: message.sessionModel,
12
+ };
13
+ }
@@ -0,0 +1,9 @@
1
+ // Reversible project-chrome suppression for the home route.
2
+
3
+ export function showHomeShell() {
4
+ document.body.classList.add("home-active");
5
+ }
6
+
7
+ export function hideHomeShell() {
8
+ document.body.classList.remove("home-active");
9
+ }
@@ -0,0 +1,63 @@
1
+ // Complete, globally sorted Home chat archive rendered in the sidebar.
2
+
3
+ import { store } from './store.js';
4
+ import { getHomeSessionConversations, createHomeSessionActionsTrigger, disposeHomeSessionActionsMenu } from './home-session-actions.js';
5
+
6
+ export function renderHomeSidebarChats(openConversation) {
7
+ var list = document.getElementById("home-sidebar-recent-list");
8
+ if (!list) return 0;
9
+ disposeHomeSessionActionsMenu();
10
+ list.innerHTML = "";
11
+ var chats = getHomeSessionConversations();
12
+ var scope = store.get('homeChatScope') === "current" ? "current" : "all";
13
+ var activeMateId = store.get('homeChatMateId');
14
+ if (scope === "current") {
15
+ chats = chats.filter(function (chat) { return chat.mateId === activeMateId; });
16
+ }
17
+ if (!chats.length) {
18
+ var empty = document.createElement("div");
19
+ empty.className = "home-sidebar-recent-empty";
20
+ empty.textContent = scope === "current" ? "No chats with this Mate yet." : "Chats will appear here.";
21
+ list.appendChild(empty);
22
+ return 0;
23
+ }
24
+ var activeSessionId = store.get('homeChatSessionId');
25
+ for (var i = 0; i < chats.length; i++) {
26
+ (function (chat) {
27
+ var item = document.createElement("div");
28
+ item.className = "home-sidebar-recent-item";
29
+ var row = document.createElement("button");
30
+ row.type = "button";
31
+ row.className = "home-sidebar-recent-row";
32
+ row.setAttribute("aria-label", chat.title + ", with " + chat.mateName);
33
+ if (chat.mateId === activeMateId && chat.sessionId === activeSessionId) {
34
+ item.classList.add("is-active");
35
+ row.setAttribute("aria-current", "page");
36
+ }
37
+ var copy = document.createElement("span");
38
+ copy.className = "home-sidebar-recent-copy";
39
+ var title = document.createElement("span");
40
+ title.className = "home-sidebar-recent-title";
41
+ title.textContent = chat.title;
42
+ var mate = document.createElement("span");
43
+ mate.className = "home-sidebar-recent-mate";
44
+ mate.textContent = chat.mateName;
45
+ copy.appendChild(title);
46
+ copy.appendChild(mate);
47
+ row.appendChild(copy);
48
+ if (chat.isProcessing) {
49
+ var activity = document.createElement("span");
50
+ activity.className = "home-sidebar-processing";
51
+ activity.setAttribute("aria-label", "Processing");
52
+ row.appendChild(activity);
53
+ }
54
+ row.addEventListener("click", function () {
55
+ if (typeof openConversation === "function") openConversation(chat.mateId, chat.sessionId);
56
+ });
57
+ item.appendChild(row);
58
+ item.appendChild(createHomeSessionActionsTrigger(chat));
59
+ list.appendChild(item);
60
+ })(chats[i]);
61
+ }
62
+ return chats.length;
63
+ }
@@ -0,0 +1,158 @@
1
+ // Minimal Home navigation through Mates and their conversation history.
2
+
3
+ import { store } from './store.js';
4
+ import { getWs } from './ws-ref.js';
5
+ import { refreshIcons } from './icons.js';
6
+ import { updateHomeSurfacePreference } from './home-surface.js';
7
+ import { openHomeConversation, startNewHomeConversation } from './home-mate-chat.js';
8
+ import { openHomeDebatesArchive } from './home-debates-archive.js';
9
+ import { openHomeConversationsSheet, refreshHomeConversationsSheet } from './home-conversations-sheet.js';
10
+ import { renderHomeSidebarChats } from './home-sidebar-chat-list.js';
11
+ import { syncHomeSessionDetails } from './home-session-actions.js';
12
+ import { toggleHomeCapsules } from './home-dock.js';
13
+
14
+ var initialized = false;
15
+ var requestedMateIds = {};
16
+
17
+ function visibleMates() {
18
+ return (store.get('cachedMatesList') || []).filter(function (mate) {
19
+ return !!mate && !mate.archived;
20
+ });
21
+ }
22
+
23
+ function requestConversationLists(force) {
24
+ var ws = getWs();
25
+ if (!ws || ws.readyState !== 1) return;
26
+ if (force) requestedMateIds = {};
27
+ var mates = visibleMates();
28
+ for (var i = 0; i < mates.length; i++) {
29
+ if (requestedMateIds[mates[i].id]) continue;
30
+ requestedMateIds[mates[i].id] = true;
31
+ ws.send(JSON.stringify({ type: "home_mate_sessions_list", mateId: mates[i].id }));
32
+ }
33
+ }
34
+
35
+ function renderRecentConversations() {
36
+ renderHomeSidebarChats(openConversationFromSidebar);
37
+ }
38
+
39
+ function renderChatScope() {
40
+ var scope = store.get('homeChatScope') === "current" ? "current" : "all";
41
+ var buttons = document.querySelectorAll("[data-home-chat-scope]");
42
+ for (var i = 0; i < buttons.length; i++) {
43
+ buttons[i].setAttribute("aria-pressed", String(buttons[i].dataset.homeChatScope === scope));
44
+ }
45
+ }
46
+
47
+ function renderSidebarState() {
48
+ var hub = document.getElementById("home-hub");
49
+ if (!hub) return;
50
+ var collapsed = store.get('homeSidebarCollapsed') === true;
51
+ hub.classList.toggle("home-sidebar-collapsed", collapsed);
52
+ var collapse = document.getElementById("home-sidebar-collapse");
53
+ var expand = document.getElementById("home-sidebar-expand");
54
+ if (collapse) collapse.setAttribute("aria-expanded", String(!collapsed));
55
+ if (expand) expand.setAttribute("aria-expanded", String(!collapsed));
56
+ renderChatScope();
57
+ renderRecentConversations();
58
+ refreshHomeConversationsSheet();
59
+ syncHomeSessionDetails();
60
+ }
61
+
62
+ function setCollapsed(collapsed) {
63
+ updateHomeSurfacePreference({ sidebarCollapsed: collapsed });
64
+ }
65
+
66
+ function setChatScope(event) {
67
+ var scope = event.currentTarget.dataset.homeChatScope;
68
+ if (scope !== "current" && scope !== "all") return;
69
+ if ((store.get('homeChatScope') || "all") === scope) return;
70
+ updateHomeSurfacePreference({ chatScope: scope });
71
+ }
72
+
73
+ function isNarrowDrawer() {
74
+ return !!window.matchMedia && window.matchMedia("(max-width: 768px)").matches;
75
+ }
76
+
77
+ function focusNarrowNavigationTarget() {
78
+ var composer = document.getElementById("home-mate-chat-input");
79
+ if (composer && !composer.disabled && composer.getClientRects().length) {
80
+ composer.focus();
81
+ return;
82
+ }
83
+ var expand = document.getElementById("home-sidebar-expand");
84
+ if (expand && expand.getClientRects().length) expand.focus();
85
+ }
86
+
87
+ function closeNarrowDrawer(focusConversation) {
88
+ if (!isNarrowDrawer()) return;
89
+ setCollapsed(true);
90
+ if (focusConversation) focusNarrowNavigationTarget();
91
+ }
92
+
93
+ export function closeHomeSidebarAfterSelection() {
94
+ closeNarrowDrawer(true);
95
+ }
96
+
97
+ function openConversationFromSidebar(mateId, sessionId) {
98
+ openHomeConversation(mateId, sessionId);
99
+ closeNarrowDrawer(true);
100
+ }
101
+
102
+ function startConversationFromSidebar() {
103
+ startNewHomeConversation();
104
+ closeNarrowDrawer(true);
105
+ }
106
+
107
+ function openAllConversations(event) {
108
+ openHomeConversationsSheet(openConversationFromSidebar, event.currentTarget);
109
+ }
110
+
111
+ function openDebatesFromSidebar() {
112
+ openHomeDebatesArchive();
113
+ closeNarrowDrawer(false);
114
+ }
115
+
116
+ function toggleCapsulesFromSidebar() {
117
+ var opening = store.get('dockOpen') !== true;
118
+ toggleHomeCapsules();
119
+ closeNarrowDrawer(!opening);
120
+ }
121
+
122
+ function handleSidebarKeydown(event) {
123
+ if (event.key !== "Escape" || event.defaultPrevented) return;
124
+ if (!document.body.classList.contains("home-active")) return;
125
+ if (document.querySelector(".home-conversations-sheet, .home-session-details-overlay")) return;
126
+ if (!isNarrowDrawer() || store.get('homeSidebarCollapsed') === true) return;
127
+ event.preventDefault();
128
+ closeNarrowDrawer(true);
129
+ }
130
+
131
+ export function initHomeSidebar() {
132
+ if (initialized) return;
133
+ initialized = true;
134
+ document.getElementById("home-sidebar-collapse").addEventListener("click", function () { setCollapsed(true); });
135
+ document.getElementById("home-sidebar-expand").addEventListener("click", function () { setCollapsed(false); });
136
+ document.getElementById("home-sidebar-backdrop").addEventListener("click", function () { setCollapsed(true); });
137
+ document.getElementById("home-sidebar-new").addEventListener("click", startConversationFromSidebar);
138
+ document.getElementById("home-sidebar-all").addEventListener("click", openAllConversations);
139
+ document.getElementById("home-sidebar-debate").addEventListener("click", openDebatesFromSidebar);
140
+ document.getElementById("home-tools-btn").addEventListener("click", toggleCapsulesFromSidebar);
141
+ var scopeButtons = document.querySelectorAll("[data-home-chat-scope]");
142
+ for (var i = 0; i < scopeButtons.length; i++) scopeButtons[i].addEventListener("click", setChatScope);
143
+ store.subscribe(function (state, prev) {
144
+ if (state.connected !== prev.connected && state.connected) requestConversationLists(true);
145
+ if (state.cachedMatesList !== prev.cachedMatesList) requestConversationLists(false);
146
+ if (state.homeMateSessions !== prev.homeMateSessions || state.homeChatMateId !== prev.homeChatMateId || state.homeChatSessionId !== prev.homeChatSessionId || state.homeSidebarCollapsed !== prev.homeSidebarCollapsed || state.homeChatScope !== prev.homeChatScope) {
147
+ renderSidebarState();
148
+ }
149
+ });
150
+ document.addEventListener("keydown", handleSidebarKeydown);
151
+ requestConversationLists(false);
152
+ renderSidebarState();
153
+ refreshIcons();
154
+ }
155
+
156
+ export function refreshHomeSidebarSessions() {
157
+ requestConversationLists(true);
158
+ }
@@ -0,0 +1,19 @@
1
+ // Durable Home main-stage selection shared by chat and debate archive controllers.
2
+
3
+ import { store } from './store.js';
4
+ import { updateHomeSurfacePreference } from './home-surface.js';
5
+
6
+ export function setHomeSubSurface(surface, persist) {
7
+ var next = surface === "debates" ? "debates" : "chat";
8
+ if (store.get('homeSubSurface') === next) {
9
+ if (next === "chat" && store.get('homeDebateTopicFormOpen')) store.set({ homeDebateTopicFormOpen: false });
10
+ return false;
11
+ }
12
+ store.set({ homeSubSurface: next, homeDebateTopicFormOpen: next === "chat" ? false : store.get('homeDebateTopicFormOpen') });
13
+ if (persist !== false) updateHomeSurfacePreference({ subSurface: next });
14
+ return true;
15
+ }
16
+
17
+ export function isHomeDebatesSurface() {
18
+ return store.get('homeSubSurface') === "debates";
19
+ }