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,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,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
|
+
}
|