clay-server 5.2.0-beta.6 → 5.2.0-beta.8
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/clay-control-presentation-binding.js +96 -0
- package/lib/clay-control-presentation.js +128 -0
- package/lib/clay-control-target-projection.js +26 -0
- package/lib/clay-mate-chat.js +1 -0
- package/lib/clay-mate-knowledge.js +1 -1
- package/lib/clay-product-control-tools.js +1 -1
- package/lib/clay-product-control.js +22 -12
- package/lib/clay-project-records.js +2 -1
- package/lib/clay-scheduling.js +1 -1
- package/lib/clay-screen-controls.js +13 -5
- package/lib/clay-workspace-controls.js +2 -1
- package/lib/contextual-screen-snapshot.js +38 -0
- package/lib/mate-context-service.js +138 -0
- package/lib/mate-context-tools.js +21 -0
- package/lib/project-connection.js +8 -5
- package/lib/project-control-git-view.js +12 -0
- package/lib/project-filesystem.js +5 -1
- package/lib/project-http.js +3 -0
- package/lib/project-notifications.js +5 -4
- package/lib/project-product-control.js +3 -1
- package/lib/project-scheduled-messages.js +4 -4
- package/lib/project-scheduled-task-control.js +1 -1
- package/lib/project-session-document.js +20 -5
- package/lib/project-shared-browser.js +22 -5
- package/lib/project-studio-presentation.js +58 -0
- package/lib/project-user-message.js +36 -0
- package/lib/project-workspace-query.js +11 -1
- package/lib/project.js +24 -7
- package/lib/public/app.js +24 -0
- package/lib/public/appearance-bootstrap.js +2 -0
- package/lib/public/css/contextual-clay.css +240 -0
- package/lib/public/modules/app-favicon.js +7 -7
- package/lib/public/modules/app-message-router.js +5 -1
- package/lib/public/modules/app-messages.js +14 -1
- package/lib/public/modules/app-notifications.js +10 -3
- package/lib/public/modules/app-projects.js +3 -0
- package/lib/public/modules/clay-control-activity.js +214 -0
- package/lib/public/modules/clay-control-copy.js +36 -0
- package/lib/public/modules/clay-control-detail-targets.js +44 -0
- package/lib/public/modules/clay-control-object-targets.js +52 -0
- package/lib/public/modules/clay-control-target-visibility.js +12 -0
- package/lib/public/modules/clay-control-targets.js +44 -0
- package/lib/public/modules/clay-navigation-render.js +52 -0
- package/lib/public/modules/clay-owner-navigation.js +11 -2
- package/lib/public/modules/clay-session-links.js +31 -0
- package/lib/public/modules/clay-studio-bridge.js +20 -0
- package/lib/public/modules/clay-studio-document.js +67 -0
- package/lib/public/modules/clay-studio-render.js +144 -0
- package/lib/public/modules/clay-tool-presentation.js +4 -0
- package/lib/public/modules/command-palette.js +26 -31
- package/lib/public/modules/contextual-ask-session.js +26 -0
- package/lib/public/modules/contextual-clay-geometry.js +155 -0
- package/lib/public/modules/contextual-clay-session.js +130 -0
- package/lib/public/modules/contextual-clay-workspace.js +157 -0
- package/lib/public/modules/contextual-clay.js +237 -0
- package/lib/public/modules/contextual-composer.js +91 -0
- package/lib/public/modules/contextual-mate-context.js +115 -0
- package/lib/public/modules/contextual-mate-hint.js +40 -0
- package/lib/public/modules/contextual-mate-identity.js +23 -0
- package/lib/public/modules/contextual-mate-sessions.js +134 -0
- package/lib/public/modules/contextual-search.js +137 -0
- package/lib/public/modules/contextual-session-citations.js +58 -0
- package/lib/public/modules/filebrowser.js +20 -1
- package/lib/public/modules/generation-stop.js +8 -5
- package/lib/public/modules/git-panel.js +3 -1
- package/lib/public/modules/icon-strip-tooltip.js +2 -1
- package/lib/public/modules/input.js +35 -1
- package/lib/public/modules/issues-render.js +3 -2
- package/lib/public/modules/knowledge-db-workbench.js +4 -4
- package/lib/public/modules/markdown.js +2 -34
- package/lib/public/modules/mate-knowledge-workbench.js +1 -1
- package/lib/public/modules/message-delivery.js +10 -0
- package/lib/public/modules/pane-bridge.js +2 -2
- package/lib/public/modules/pending-message-queue.js +1 -0
- package/lib/public/modules/product-review.js +26 -0
- package/lib/public/modules/project-chat-identity.js +13 -4
- package/lib/public/modules/project-logs-render.js +3 -0
- package/lib/public/modules/project-mate-navigation.js +58 -21
- package/lib/public/modules/scheduled-tasks.js +2 -0
- package/lib/public/modules/search-clay-chat.js +5 -454
- package/lib/public/modules/shared-browser.js +2 -0
- package/lib/public/modules/sidebar-mobile.js +4 -3
- package/lib/public/modules/sidebar-projects.js +1 -0
- package/lib/public/modules/sidebar-sessions.js +1 -0
- package/lib/public/modules/split-view.js +7 -16
- package/lib/public/modules/stt.js +7 -2
- package/lib/public/modules/terminal.js +9 -0
- package/lib/public/modules/tools.js +4 -1
- package/lib/public/modules/wireframe-workbench.js +5 -2
- package/lib/public/style.css +2 -0
- package/lib/sdk-bridge.js +4 -0
- package/lib/server-contextual-clay-settings.js +40 -0
- package/lib/server-contextual-mate-sessions.js +70 -0
- package/lib/server-home-chat.js +7 -1
- package/lib/server-home-clay-entry.js +23 -4
- package/lib/server-home-clay-session-links.js +12 -0
- package/lib/server-owner-ui.js +49 -8
- package/lib/server-settings.js +2 -0
- package/lib/server.js +17 -0
- package/lib/sessions.js +10 -3
- package/lib/terminal-manager.js +18 -11
- package/lib/users-contextual-clay-preferences.js +31 -0
- package/lib/users.js +3 -0
- package/lib/workspace-assignment-service.js +25 -0
- package/lib/workspace-query-mcp-server.js +1 -1
- package/lib/ws-request.js +1 -0
- package/lib/ws-schema.js +10 -0
- package/lib/yoke/claude-hook-installer.js +4 -0
- package/package.json +1 -1
|
@@ -1,454 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { store } from './store.js';
|
|
7
|
-
import { mateAvatarUrl } from './avatar.js';
|
|
8
|
-
import { createAssistantBubble, createUserBubble, finalizeAssistantBubble, renderAssistantBubbleText } from './chat-bubble-renderer.js';
|
|
9
|
-
import { isExactSearchControlMessage, replaceSearchPermissions, applySearchPermissionMessage, createSearchPermissionCard } from './search-clay-controls.js';
|
|
10
|
-
|
|
11
|
-
var state = store.get('searchClayChatState') || null;
|
|
12
|
-
var hostEl = null;
|
|
13
|
-
var backHandler = null;
|
|
14
|
-
var closeHandler = null;
|
|
15
|
-
var sequence = 0;
|
|
16
|
-
var progressTimer = null;
|
|
17
|
-
|
|
18
|
-
function send(payload) {
|
|
19
|
-
var ws = getWs();
|
|
20
|
-
if (!ws || ws.readyState !== 1) return false;
|
|
21
|
-
ws.send(JSON.stringify(payload));
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function requestId() {
|
|
26
|
-
sequence++;
|
|
27
|
-
return "search-clay-" + Date.now() + "-" + sequence;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function stopProgressTimer() {
|
|
31
|
-
if (!progressTimer) return;
|
|
32
|
-
clearInterval(progressTimer);
|
|
33
|
-
progressTimer = null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function startProgressTimer() {
|
|
37
|
-
if (progressTimer) return;
|
|
38
|
-
progressTimer = setInterval(function () { if (state && state.processing) updateProgressDom(); else stopProgressTimer(); }, 1000);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function progressCopy() {
|
|
42
|
-
var elapsed = state && state.startedAt ? Math.max(0, Math.floor((Date.now() - state.startedAt) / 1000)) : 0;
|
|
43
|
-
var label = state && state.step ? "Considering what was found" : "Understanding what to look for";
|
|
44
|
-
if (state.activity === "searching") label = state.step > 1 ? "Checking another lead" : "Searching your conversations";
|
|
45
|
-
else if (state.activity === "reviewing") label = "Reviewing what Clay found";
|
|
46
|
-
else if (state.activity === "reconsidering") label = "Trying another search route";
|
|
47
|
-
else if (elapsed >= 12) label = "Following related context";
|
|
48
|
-
else if (elapsed >= 4) label = "Searching your conversations";
|
|
49
|
-
var detail = (state.step ? "Search pass " + state.step + " · " : "") + elapsed + "s";
|
|
50
|
-
return { label: label, detail: detail };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function updateProgressDom() {
|
|
54
|
-
if (!hostEl) return;
|
|
55
|
-
var progress = progressCopy();
|
|
56
|
-
var label = hostEl.querySelector(".search-clay-pending-copy strong");
|
|
57
|
-
var detail = hostEl.querySelector(".search-clay-pending-copy small");
|
|
58
|
-
if (label) label.textContent = progress.label;
|
|
59
|
-
if (detail) detail.textContent = progress.detail;
|
|
60
|
-
var activeDetails = hostEl.querySelectorAll(".search-clay-activity-item.is-active small");
|
|
61
|
-
var activeIndex = 0;
|
|
62
|
-
for (var i = 0; state && i < state.activities.length; i++) {
|
|
63
|
-
if (state.activities[i].status !== "active") continue;
|
|
64
|
-
var elapsed = Math.max(0, Math.floor((Date.now() - state.activities[i].startedAt) / 1000));
|
|
65
|
-
state.activities[i].detail = elapsed + "s elapsed";
|
|
66
|
-
if (activeDetails[activeIndex]) activeDetails[activeIndex].textContent = state.activities[i].detail;
|
|
67
|
-
activeIndex++;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function button(icon, label, title, handler) {
|
|
72
|
-
var el = document.createElement("button");
|
|
73
|
-
el.type = "button";
|
|
74
|
-
el.className = "search-clay-icon-button";
|
|
75
|
-
el.title = title;
|
|
76
|
-
el.setAttribute("aria-label", title);
|
|
77
|
-
el.innerHTML = '<i data-lucide="' + icon + '" aria-hidden="true"></i><span>' + label + '</span>';
|
|
78
|
-
el.addEventListener("click", handler);
|
|
79
|
-
return el;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function clayMate() {
|
|
83
|
-
var mates = store.get('cachedMatesList') || [];
|
|
84
|
-
for (var i = 0; i < mates.length; i++) {
|
|
85
|
-
if (mates[i] && (mates[i].id === state.mateId || mates[i].builtinKey === "clay")) return mates[i];
|
|
86
|
-
}
|
|
87
|
-
return { name: "Clay", profile: { displayName: "Clay", avatarCustom: "/clay-studio-symbol.png" } };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function appendActivityList(content, items, expanded, onToggle) {
|
|
91
|
-
var panel = document.createElement("div");
|
|
92
|
-
panel.className = "search-clay-activity-panel " + (expanded ? "is-expanded" : "is-collapsed");
|
|
93
|
-
var toggle = document.createElement("button");
|
|
94
|
-
toggle.type = "button";
|
|
95
|
-
toggle.className = "search-clay-activity-toggle";
|
|
96
|
-
toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
97
|
-
toggle.setAttribute("aria-label", (expanded ? "Collapse" : "Expand") + " Clay activity, " + items.length + (items.length === 1 ? " step" : " steps"));
|
|
98
|
-
toggle.innerHTML = '<i data-lucide="activity" aria-hidden="true"></i><span><strong>Activity</strong><small></small></span><i class="search-clay-activity-chevron" data-lucide="chevron-down" aria-hidden="true"></i>';
|
|
99
|
-
toggle.querySelector("small").textContent = items.length + (items.length === 1 ? " step" : " steps");
|
|
100
|
-
if (items.length <= 2) {
|
|
101
|
-
toggle.disabled = true;
|
|
102
|
-
toggle.setAttribute("aria-label", "Clay activity, " + items.length + (items.length === 1 ? " step" : " steps"));
|
|
103
|
-
} else {
|
|
104
|
-
toggle.addEventListener("click", function () {
|
|
105
|
-
expanded = !expanded;
|
|
106
|
-
panel.classList.toggle("is-expanded", expanded);
|
|
107
|
-
panel.classList.toggle("is-collapsed", !expanded);
|
|
108
|
-
toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
109
|
-
toggle.setAttribute("aria-label", (expanded ? "Collapse" : "Expand") + " Clay activity, " + items.length + " steps");
|
|
110
|
-
onToggle(expanded);
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
panel.appendChild(toggle);
|
|
114
|
-
var list = document.createElement("div");
|
|
115
|
-
list.className = "search-clay-activity-list";
|
|
116
|
-
for (var i = 0; i < items.length; i++) {
|
|
117
|
-
var item = document.createElement("div");
|
|
118
|
-
item.className = "search-clay-activity-item is-" + items[i].status;
|
|
119
|
-
item.innerHTML = '<i data-lucide="' + activityIcon(items[i].status) + '" aria-hidden="true"></i>';
|
|
120
|
-
var copy = document.createElement("span");
|
|
121
|
-
var label = document.createElement("strong");
|
|
122
|
-
label.textContent = items[i].label;
|
|
123
|
-
copy.appendChild(label);
|
|
124
|
-
var detail = document.createElement("small");
|
|
125
|
-
detail.textContent = items[i].detail || "";
|
|
126
|
-
copy.appendChild(detail);
|
|
127
|
-
item.appendChild(copy);
|
|
128
|
-
list.appendChild(item);
|
|
129
|
-
}
|
|
130
|
-
panel.appendChild(list);
|
|
131
|
-
content.appendChild(panel);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function renderMessage(message, streaming) {
|
|
135
|
-
if (message.role === "question" && message.flow === "mcp_import") return createHomeDebateQuestionCard(message, respondToImport);
|
|
136
|
-
var row;
|
|
137
|
-
if (message.role === "user") {
|
|
138
|
-
row = createUserBubble({ text: message.text || "" });
|
|
139
|
-
row.classList.add("search-clay-message", "search-clay-message-user");
|
|
140
|
-
} else {
|
|
141
|
-
row = createAssistantBubble({ name: "Clay", avatarUrl: mateAvatarUrl(clayMate(), 28) });
|
|
142
|
-
row.classList.add("search-clay-message", "search-clay-message-assistant");
|
|
143
|
-
if (streaming) renderAssistantBubbleText(row, message.text || "", false);
|
|
144
|
-
else finalizeAssistantBubble(row, message.text || "", false);
|
|
145
|
-
if (message.activities && message.activities.length) {
|
|
146
|
-
appendActivityList(row.querySelector(".dm-bubble-content"), message.activities, message.activitiesExpanded === true, message.toggleActivities || function (expanded) { message.activitiesExpanded = expanded; });
|
|
147
|
-
row.classList.add("search-clay-activity-message");
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
row.setAttribute("role", "article");
|
|
151
|
-
row.setAttribute("aria-label", message.role === "user" ? "Your message" : "Message from Clay");
|
|
152
|
-
return row;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function activityIcon(status) {
|
|
156
|
-
if (status === "done") return "circle-check";
|
|
157
|
-
if (status === "error") return "circle-alert";
|
|
158
|
-
return "loader-circle";
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function updateActivity(message) {
|
|
162
|
-
var id = message.activityId || message.phase + ":" + (message.step || 0);
|
|
163
|
-
var activity = null;
|
|
164
|
-
for (var i = 0; i < state.activities.length; i++) if (state.activities[i].id === id) activity = state.activities[i];
|
|
165
|
-
if (!activity) {
|
|
166
|
-
activity = { id: id, label: message.label || "Working", detail: "0s elapsed", status: message.status || "active", startedAt: Date.now() };
|
|
167
|
-
state.activities.push(activity);
|
|
168
|
-
} else if (message.status === "active") {
|
|
169
|
-
activity.label = message.label || activity.label;
|
|
170
|
-
activity.status = "active";
|
|
171
|
-
} else {
|
|
172
|
-
var elapsed = Math.max(0, Math.floor((Date.now() - activity.startedAt) / 1000));
|
|
173
|
-
activity.detail = (message.label || "Complete") + (elapsed ? " \u00b7 " + elapsed + "s" : "");
|
|
174
|
-
activity.status = message.status || "done";
|
|
175
|
-
}
|
|
176
|
-
if (state.activities.length > 12) state.activities = state.activities.slice(state.activities.length - 12);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function takeActivities(finalLabel, finalStatus) {
|
|
180
|
-
var now = Date.now();
|
|
181
|
-
for (var i = 0; i < state.activities.length; i++) {
|
|
182
|
-
if (state.activities[i].status !== "active") continue;
|
|
183
|
-
var elapsed = Math.max(0, Math.floor((now - state.activities[i].startedAt) / 1000));
|
|
184
|
-
state.activities[i].status = finalStatus || "done";
|
|
185
|
-
state.activities[i].detail = finalLabel + (elapsed ? " \u00b7 " + elapsed + "s" : "");
|
|
186
|
-
}
|
|
187
|
-
var items = state.activities.slice();
|
|
188
|
-
state.activities = [];
|
|
189
|
-
return items;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function submit(input, sendButton) {
|
|
193
|
-
var text = input.value.trim();
|
|
194
|
-
if (!state || !text || !state.sessionId) return;
|
|
195
|
-
if (!send({ type: "home_mate_send", mateId: state.mateId, sessionId: state.sessionId, requestId: state.requestId, text: text })) return;
|
|
196
|
-
if (state.processing) {
|
|
197
|
-
state.queuedUsers.push({ role: "user", text: text });
|
|
198
|
-
} else {
|
|
199
|
-
state.messages.push({ role: "user", text: text });
|
|
200
|
-
state.processing = true;
|
|
201
|
-
state.awaitingCompletion = true;
|
|
202
|
-
state.stream = "";
|
|
203
|
-
state.activity = "thinking";
|
|
204
|
-
state.step = 0;
|
|
205
|
-
state.activities = [];
|
|
206
|
-
state.activityExpanded = false;
|
|
207
|
-
state.startedAt = Date.now();
|
|
208
|
-
}
|
|
209
|
-
state.pendingTurns++;
|
|
210
|
-
state.updatedAt = Date.now();
|
|
211
|
-
startProgressTimer();
|
|
212
|
-
state.draft = "";
|
|
213
|
-
input.value = "";
|
|
214
|
-
sendButton.disabled = true;
|
|
215
|
-
render();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function stopSearchClayChat() {
|
|
219
|
-
if (!state || !state.processing || state.stopping || !state.mateId || !state.sessionId) return false;
|
|
220
|
-
if (!send({ type: "home_mate_stop", mateId: state.mateId, sessionId: state.sessionId, requestId: state.requestId })) return false;
|
|
221
|
-
state.stopping = true;
|
|
222
|
-
render();
|
|
223
|
-
return true;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function respondToImport(message, action, opener, answers) {
|
|
227
|
-
if (!state || message.status !== 'pending') return;
|
|
228
|
-
if (!send({ type: 'home_mcp_import_response', mateId: state.mateId, sessionId: state.sessionId, requestId: state.requestId, toolId: message.toolId, answers: answers || {} })) return;
|
|
229
|
-
markHomeDebateQuestionSubmitting(message, opener);
|
|
230
|
-
store.set({ searchClayChatState: state }); render();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function respondToPermission(permission, decision) {
|
|
234
|
-
if (!state || permission.status !== "pending") return false;
|
|
235
|
-
if (!send({ type: "home_mate_permission_response", mateId: state.mateId, sessionId: state.sessionId, requestId: state.requestId, permissionRequestId: permission.permissionRequestId, decision: decision })) return false;
|
|
236
|
-
permission.status = "answering";
|
|
237
|
-
render();
|
|
238
|
-
return true;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function expand() {
|
|
242
|
-
if (!state || !state.mateId || !state.localId) return;
|
|
243
|
-
if (closeHandler) closeHandler();
|
|
244
|
-
openProjectSession('mate-' + state.mateId, state.localId);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function render() {
|
|
248
|
-
if (!hostEl || !state) return;
|
|
249
|
-
var shell = hostEl.querySelector(".search-clay-chat");
|
|
250
|
-
var transcript = shell ? shell.querySelector(".search-clay-transcript") : null;
|
|
251
|
-
var previousTop = transcript ? transcript.scrollTop : 0;
|
|
252
|
-
var follow = !transcript || transcript.scrollHeight - transcript.scrollTop - transcript.clientHeight < 40;
|
|
253
|
-
if (!shell) {
|
|
254
|
-
hostEl.innerHTML = "";
|
|
255
|
-
shell = document.createElement("section");
|
|
256
|
-
shell.className = "search-clay-chat";
|
|
257
|
-
shell.setAttribute("aria-label", "Chat with Clay");
|
|
258
|
-
var header = document.createElement("header");
|
|
259
|
-
header.className = "search-clay-header";
|
|
260
|
-
var identity = document.createElement("div");
|
|
261
|
-
identity.className = "search-clay-identity";
|
|
262
|
-
identity.innerHTML = '<span><strong>Clay</strong><small>Workspace search</small></span>';
|
|
263
|
-
header.appendChild(identity);
|
|
264
|
-
var actions = document.createElement("div");
|
|
265
|
-
actions.className = "search-clay-header-actions";
|
|
266
|
-
actions.appendChild(button("search", "Search", "Back to search", function () { detachSearchClayChat(); if (backHandler) backHandler(); }));
|
|
267
|
-
actions.appendChild(button("maximize-2", "Expand", "Open this conversation in project chat", expand));
|
|
268
|
-
header.appendChild(actions);
|
|
269
|
-
shell.appendChild(header);
|
|
270
|
-
transcript = document.createElement("div");
|
|
271
|
-
transcript.className = "search-clay-transcript";
|
|
272
|
-
transcript.setAttribute("aria-live", "polite");
|
|
273
|
-
shell.appendChild(transcript);
|
|
274
|
-
var composer = document.createElement("div");
|
|
275
|
-
composer.className = "search-clay-composer";
|
|
276
|
-
var freshInput = document.createElement("textarea");
|
|
277
|
-
freshInput.rows = 1;
|
|
278
|
-
freshInput.value = state.draft || "";
|
|
279
|
-
freshInput.setAttribute("aria-label", "Message Clay");
|
|
280
|
-
var freshSendButton = document.createElement("button");
|
|
281
|
-
freshSendButton.type = "button";
|
|
282
|
-
freshSendButton.className = "search-clay-send";
|
|
283
|
-
freshSendButton.setAttribute("aria-label", "Send to Clay");
|
|
284
|
-
freshSendButton.innerHTML = '<i data-lucide="arrow-up" aria-hidden="true"></i>';
|
|
285
|
-
freshInput.addEventListener("input", function () { state.draft = freshInput.value; freshSendButton.disabled = state.processing ? (!state.sessionId || state.stopping) : (!state.sessionId || !freshInput.value.trim()); });
|
|
286
|
-
freshInput.addEventListener("keydown", function (event) { if (event.key === "Enter" && !event.shiftKey && !event.isComposing) { event.preventDefault(); submit(freshInput, freshSendButton); } });
|
|
287
|
-
freshSendButton.addEventListener("click", function () { if (state.processing) stopSearchClayChat(); else submit(freshInput, freshSendButton); });
|
|
288
|
-
composer.appendChild(freshInput);
|
|
289
|
-
composer.appendChild(freshSendButton);
|
|
290
|
-
shell.appendChild(composer);
|
|
291
|
-
hostEl.appendChild(shell);
|
|
292
|
-
}
|
|
293
|
-
transcript.innerHTML = "";
|
|
294
|
-
for (var i = 0; i < state.messages.length; i++) transcript.appendChild(renderMessage(state.messages[i], false));
|
|
295
|
-
if (state.activities.length || state.stream) transcript.appendChild(renderMessage({ role: "assistant", text: state.stream, activities: state.activities, activitiesExpanded: state.activityExpanded, toggleActivities: function (expanded) { state.activityExpanded = expanded; } }, true));
|
|
296
|
-
for (var p = 0; p < state.permissions.length; p++) transcript.appendChild(createSearchPermissionCard(state.permissions[p], respondToPermission));
|
|
297
|
-
if (state.processing && !state.stream && !state.activities.length) {
|
|
298
|
-
var progress = progressCopy();
|
|
299
|
-
var pending = document.createElement("div");
|
|
300
|
-
pending.className = "search-clay-pending";
|
|
301
|
-
pending.setAttribute("role", "status");
|
|
302
|
-
var pendingCopy = document.createElement("span");
|
|
303
|
-
pendingCopy.className = "search-clay-pending-copy";
|
|
304
|
-
var pendingLabel = document.createElement("strong");
|
|
305
|
-
pendingLabel.textContent = progress.label;
|
|
306
|
-
var pendingDetail = document.createElement("small");
|
|
307
|
-
pendingDetail.textContent = progress.detail;
|
|
308
|
-
pendingCopy.appendChild(pendingLabel);
|
|
309
|
-
pendingCopy.appendChild(pendingDetail);
|
|
310
|
-
pending.appendChild(pendingCopy);
|
|
311
|
-
var dots = document.createElement("span");
|
|
312
|
-
dots.className = "search-clay-dots";
|
|
313
|
-
dots.setAttribute("aria-hidden", "true");
|
|
314
|
-
dots.innerHTML = "<i></i><i></i><i></i>";
|
|
315
|
-
pending.appendChild(dots);
|
|
316
|
-
transcript.appendChild(pending);
|
|
317
|
-
}
|
|
318
|
-
for (var q = 0; q < state.queuedUsers.length; q++) transcript.appendChild(renderMessage(state.queuedUsers[q], false));
|
|
319
|
-
var input = shell.querySelector(".search-clay-composer textarea");
|
|
320
|
-
var sendButton = shell.querySelector(".search-clay-send");
|
|
321
|
-
input.placeholder = state.sessionId ? "Message Clay…" : "Starting Clay…";
|
|
322
|
-
input.disabled = !state.sessionId;
|
|
323
|
-
sendButton.disabled = state.processing ? (!state.sessionId || state.stopping) : (!state.sessionId || !input.value.trim());
|
|
324
|
-
sendButton.setAttribute("aria-label", state.processing ? (state.stopping ? "Stopping Clay" : "Stop Clay") : "Send to Clay");
|
|
325
|
-
sendButton.innerHTML = state.processing ? '<i data-lucide="square" aria-hidden="true"></i>' : '<i data-lucide="arrow-up" aria-hidden="true"></i>';
|
|
326
|
-
var expandButton = shell.querySelector('.search-clay-icon-button[aria-label="Open this conversation in project chat"]');
|
|
327
|
-
if (expandButton) expandButton.disabled = !state.localId;
|
|
328
|
-
refreshIcons();
|
|
329
|
-
transcript.scrollTop = follow ? transcript.scrollHeight : previousTop;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
export function startSearchClayChat(query, host, onBack, onClose) {
|
|
333
|
-
var clean = typeof query === "string" ? query.trim().slice(0, 12000) : "";
|
|
334
|
-
if (!clean) return false;
|
|
335
|
-
hostEl = host;
|
|
336
|
-
backHandler = onBack;
|
|
337
|
-
closeHandler = onClose;
|
|
338
|
-
var startedAt = Date.now();
|
|
339
|
-
state = { requestId: requestId(), mateId: null, sessionId: null, localId: null, messages: [{ role: "user", text: clean }], queuedUsers: [], pendingTurns: 1, activities: [], permissions: [], activityExpanded: false, stream: "", draft: "", processing: true, stopping: false, awaitingCompletion: true, activity: "thinking", step: 0, startedAt: startedAt, updatedAt: startedAt, query: clean };
|
|
340
|
-
store.set({ searchClayChatState: state });
|
|
341
|
-
startProgressTimer();
|
|
342
|
-
render();
|
|
343
|
-
if (!send({ type: "home_clay_ask", requestId: state.requestId, text: clean })) {
|
|
344
|
-
state.processing = false;
|
|
345
|
-
state.awaitingCompletion = false;
|
|
346
|
-
state.pendingTurns = 0;
|
|
347
|
-
stopProgressTimer();
|
|
348
|
-
state.messages.push({ role: "assistant", text: "Clay is offline. Reconnect and try again." });
|
|
349
|
-
render();
|
|
350
|
-
}
|
|
351
|
-
return true;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
export function attachSearchClayChat(host, onBack, onClose) {
|
|
355
|
-
if (!state) return false;
|
|
356
|
-
hostEl = host;
|
|
357
|
-
backHandler = onBack;
|
|
358
|
-
closeHandler = onClose;
|
|
359
|
-
if (state.processing) send({ type: "home_clay_ask", requestId: state.requestId, text: state.query });
|
|
360
|
-
render();
|
|
361
|
-
return true;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
export function getSearchClayChatSummary() {
|
|
365
|
-
if (!state) return null;
|
|
366
|
-
var preview = "";
|
|
367
|
-
var candidates = state.queuedUsers.length ? state.queuedUsers : state.messages;
|
|
368
|
-
for (var i = candidates.length - 1; i >= 0; i--) {
|
|
369
|
-
if (!candidates[i] || typeof candidates[i].text !== "string" || !candidates[i].text.trim()) continue;
|
|
370
|
-
preview = candidates[i].text.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
371
|
-
break;
|
|
372
|
-
}
|
|
373
|
-
return { sessionId: state.sessionId, processing: state.processing === true, preview: preview, updatedAt: state.updatedAt || state.startedAt || null };
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
export function detachSearchClayChat() { hostEl = null; }
|
|
377
|
-
|
|
378
|
-
export function handleSearchClayMessage(msg) {
|
|
379
|
-
if (!isExactSearchControlMessage(state, msg)) return false;
|
|
380
|
-
state.updatedAt = Date.now();
|
|
381
|
-
if (msg.mateId) state.mateId = msg.mateId;
|
|
382
|
-
if (msg.type === "home_mate_session_identity" && msg.sessionId) state.sessionId = msg.sessionId;
|
|
383
|
-
if (msg.type === 'home_mcp_import_question') {
|
|
384
|
-
if (state.stream) { state.messages.push({ role: 'assistant', text: state.stream }); state.stream = ''; }
|
|
385
|
-
state.messages = applyHomeDebateQuestion(state.messages, msg);
|
|
386
|
-
} else if (msg.type === 'home_mcp_import_question_resolved') {
|
|
387
|
-
state.messages = resolveHomeDebateQuestion(state.messages, msg);
|
|
388
|
-
} else if (msg.type === "home_clay_activity") {
|
|
389
|
-
if (!state.awaitingCompletion) return true;
|
|
390
|
-
state.activity = msg.phase || state.activity;
|
|
391
|
-
state.step = typeof msg.step === "number" ? msg.step : state.step;
|
|
392
|
-
updateActivity(msg);
|
|
393
|
-
} else if (msg.type === "home_mate_history") {
|
|
394
|
-
state.sessionId = msg.sessionId || state.sessionId;
|
|
395
|
-
state.localId = typeof msg.localId === "number" ? msg.localId : state.localId;
|
|
396
|
-
state.messages = Array.isArray(msg.messages) ? msg.messages.filter(function (item) { return item && (item.role === "user" || item.role === "assistant" || item.role === "question" && item.flow === "mcp_import"); }).map(function (item) { return item.role === "question" ? Object.assign({}, item) : { role: item.role, text: item.text || "" }; }) : state.messages;
|
|
397
|
-
state.processing = msg.isProcessing === true;
|
|
398
|
-
state.awaitingCompletion = state.processing;
|
|
399
|
-
state.pendingTurns = state.processing ? Math.max(1, state.pendingTurns) : 0;
|
|
400
|
-
if (state.processing) startProgressTimer();
|
|
401
|
-
state.stream = "";
|
|
402
|
-
state.stopping = false;
|
|
403
|
-
replaceSearchPermissions(state, msg.pendingPermissions);
|
|
404
|
-
} else if (msg.type === "home_mate_permission_request" || msg.type === "home_mate_permission_resolved" || msg.type === "home_mate_permission_cancelled") {
|
|
405
|
-
applySearchPermissionMessage(state, msg);
|
|
406
|
-
} else if (msg.type === "home_mate_stopping") {
|
|
407
|
-
state.stopping = true;
|
|
408
|
-
} else if (msg.type === "home_mate_delta") {
|
|
409
|
-
if (!state.awaitingCompletion) return true;
|
|
410
|
-
state.sessionId = msg.sessionId || state.sessionId;
|
|
411
|
-
state.processing = true;
|
|
412
|
-
state.pendingTurns = Math.max(1, state.pendingTurns);
|
|
413
|
-
state.stream += msg.text || "";
|
|
414
|
-
} else if (msg.type === "home_mate_done") {
|
|
415
|
-
if (!state.awaitingCompletion) return true;
|
|
416
|
-
var completedActivities = takeActivities("Response complete", "done");
|
|
417
|
-
if (state.stream || msg.text || completedActivities.length) state.messages.push({ role: "assistant", text: state.stream || msg.text || "", activities: completedActivities, activitiesExpanded: state.activityExpanded });
|
|
418
|
-
if (state.queuedUsers.length) state.messages.push(state.queuedUsers.shift());
|
|
419
|
-
state.stream = "";
|
|
420
|
-
state.activityExpanded = false;
|
|
421
|
-
state.pendingTurns = Math.max(0, state.pendingTurns - 1);
|
|
422
|
-
state.processing = state.pendingTurns > 0;
|
|
423
|
-
state.stopping = false;
|
|
424
|
-
state.awaitingCompletion = state.processing;
|
|
425
|
-
state.startedAt = Date.now();
|
|
426
|
-
if (!state.processing) stopProgressTimer();
|
|
427
|
-
} else if (msg.type === "home_mate_error") {
|
|
428
|
-
if (!state.awaitingCompletion) return true;
|
|
429
|
-
var failedActivities = takeActivities("Stopped", "error");
|
|
430
|
-
state.stream = "";
|
|
431
|
-
state.messages.push({ role: "assistant", text: msg.text || "Clay could not complete that search.", activities: failedActivities, activitiesExpanded: state.activityExpanded });
|
|
432
|
-
if (state.queuedUsers.length) state.messages.push(state.queuedUsers.shift());
|
|
433
|
-
state.pendingTurns = Math.max(0, state.pendingTurns - 1);
|
|
434
|
-
state.activityExpanded = false;
|
|
435
|
-
state.processing = state.pendingTurns > 0;
|
|
436
|
-
state.stopping = false;
|
|
437
|
-
state.awaitingCompletion = state.processing;
|
|
438
|
-
state.startedAt = Date.now();
|
|
439
|
-
if (!state.processing) stopProgressTimer();
|
|
440
|
-
}
|
|
441
|
-
render();
|
|
442
|
-
return true;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
store.subscribe(function (appState, previous) {
|
|
446
|
-
if (!state || appState.connected === previous.connected) return;
|
|
447
|
-
if (!appState.connected) {
|
|
448
|
-
replaceSearchPermissions(state, []);
|
|
449
|
-
state.stopping = false;
|
|
450
|
-
render();
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
if (state.processing) send({ type: "home_clay_ask", requestId: state.requestId, text: state.query });
|
|
454
|
-
});
|
|
1
|
+
// Search is an entry point. The sole chat renderer is the contextual Mate pane.
|
|
2
|
+
import { startContextualSearch, handleContextualSearchMessage, retryContextualSearch } from './contextual-search.js';
|
|
3
|
+
export function startSearchClayChat(query) { return startContextualSearch(query); }
|
|
4
|
+
export function handleSearchClayMessage(message) { return handleContextualSearchMessage(message); }
|
|
5
|
+
export function retrySearchClayAsk() { return retryContextualSearch(); }
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { registerStudioPaint } from './clay-studio-render.js';
|
|
1
2
|
import { browserLinkTarget, initBrowserLinks } from './clay-browser-links.js';
|
|
2
3
|
import { browserSettingsHtml, bindBrowserSettings, renderBrowserSettings, closeBrowserSettings, handleBrowserSettingsMessage } from './shared-browser-settings.js';
|
|
3
4
|
import { renderBrowserTabs } from './shared-browser-tabs.js';
|
|
@@ -229,6 +230,7 @@ export function handleSharedBrowserMessage(msg) {
|
|
|
229
230
|
var canvas = panel().querySelector('canvas'); canvas.width = image.naturalWidth; canvas.height = image.naturalHeight;
|
|
230
231
|
canvas.getContext('2d').drawImage(image, 0, 0);
|
|
231
232
|
ui({ decoding: false, hasFrame: true }); render();
|
|
233
|
+
registerStudioPaint(msg, canvas, null, canvas);
|
|
232
234
|
}
|
|
233
235
|
};
|
|
234
236
|
image.onerror = function () { if (store.get('activeSessionId') === sessionId) ui({ decoding: false }); };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { contextualMate } from './contextual-mate-identity.js';
|
|
2
|
+
import { activateContextualMate, isMateWorkspace } from './project-mate-navigation.js';
|
|
2
3
|
import { appendGithubWork } from './session-github.js';
|
|
3
4
|
// sidebar-mobile.js - Mobile sheet overlays, tab bar, and mobile-specific rendering
|
|
4
5
|
// Extracted from sidebar.js (PR-38)
|
|
@@ -258,7 +259,7 @@ function renderSheetSessions(listEl) {
|
|
|
258
259
|
}
|
|
259
260
|
|
|
260
261
|
var visibleChipMates = getCachedMates().filter(function (m) {
|
|
261
|
-
return m && !m.archived;
|
|
262
|
+
return m && !m.archived && contextualMate(m.id);
|
|
262
263
|
});
|
|
263
264
|
var sortedChipMates = visibleChipMates.sort(function (a, b) {
|
|
264
265
|
var aBuiltin = a.builtinKey ? 1 : 0;
|
|
@@ -327,7 +328,7 @@ function renderSheetSessions(listEl) {
|
|
|
327
328
|
renderMobileSessionsInto(sessionListEl);
|
|
328
329
|
} else if (type === "mate") {
|
|
329
330
|
closeMobileSheet();
|
|
330
|
-
|
|
331
|
+
activateContextualMate(mateId);
|
|
331
332
|
}
|
|
332
333
|
|
|
333
334
|
refreshIcons();
|
|
@@ -822,6 +822,7 @@ function createIconItem(p, currentSlug) {
|
|
|
822
822
|
var el = document.createElement("a");
|
|
823
823
|
var isActive = p.slug === currentSlug && !currentDmUserId;
|
|
824
824
|
el.className = "icon-strip-item" + (isActive ? " active" : "");
|
|
825
|
+
el.dataset.controlRuntime = p.controlRuntimeId || "";
|
|
825
826
|
el.href = "/p/" + p.slug + "/";
|
|
826
827
|
el.dataset.slug = p.slug;
|
|
827
828
|
|
|
@@ -826,6 +826,7 @@ function renderSessionItem(s, options) {
|
|
|
826
826
|
el.className = "session-item" + (displaySession.active ? " active" : "") + (isMatch ? " search-match" : "");
|
|
827
827
|
if (itemOptions.worker) el.classList.add("session-worker-item");
|
|
828
828
|
el.dataset.sessionId = s.id;
|
|
829
|
+
el.dataset.controlSessionOrigin = s.sessionOriginId || '';
|
|
829
830
|
|
|
830
831
|
var textSpan = document.createElement("span");
|
|
831
832
|
textSpan.className = "session-item-text";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { adoptDocumentSource } from './clay-studio-document.js';
|
|
2
|
+
import { trustedStudioFrame } from './clay-studio-render.js';
|
|
1
3
|
import { handlePaneBrowserMessage } from './pane-browser-bridge.js';
|
|
2
4
|
import { openWireframe } from './wireframe-workbench.js';
|
|
3
5
|
// Two-pane iframe shell for the split-view spike.
|
|
@@ -144,22 +146,11 @@ function handlePaneMessage(event) {
|
|
|
144
146
|
if (event.origin !== window.location.origin) return;
|
|
145
147
|
var msg = event.data;
|
|
146
148
|
if (!msg || !host) return;
|
|
147
|
-
if (msg.type === "clay-pane-present-wireframe") {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return split && split.panes.some(function (pane) {
|
|
153
|
-
var expected = new URL('/p/' + encodeURIComponent(pane.slug) + '/?pane=1&session=' + encodeURIComponent(pane.sessionId), window.location.href).href;
|
|
154
|
-
return pane.slug === msg.projectSlug && String(pane.sessionId) === String(msg.sessionId) && frame.src === expected;
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
if (trusted && msg.message) openWireframe(msg.message);
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
if (msg.type === "clay-pane-present-markdown") {
|
|
161
|
-
var present = msg.message;
|
|
162
|
-
if (present) presentMarkdownEdit(present);
|
|
149
|
+
if (msg.type === "clay-pane-present-wireframe" || msg.type === "clay-pane-present-markdown") {
|
|
150
|
+
if (msg.message && !msg.message.controlPresentation && trustedStudioFrame(event, msg)) {
|
|
151
|
+
if (msg.type === "clay-pane-present-wireframe") openWireframe(msg.message);
|
|
152
|
+
else { adoptDocumentSource(event, msg, trustedStudioFrame(event, msg)); presentMarkdownEdit(msg.message); }
|
|
153
|
+
}
|
|
163
154
|
return;
|
|
164
155
|
}
|
|
165
156
|
// Both panes can report auth_required for their own sessions. The shell runs
|
|
@@ -25,6 +25,7 @@ function bindComposer(id, inputId, wrapperId) {
|
|
|
25
25
|
if (!button || !input || !wrapper || button.dataset.speechBound) return;
|
|
26
26
|
var composer = document.getElementById(id === 'stt-btn' ? 'input-row' : 'home-mate-chat-composer') || wrapper;
|
|
27
27
|
var toolbar = document.getElementById(id === 'stt-btn' ? 'input-bottom' : 'home-mate-chat-composer') || composer;
|
|
28
|
+
button.addEventListener('click', refreshSpeechBrowser);
|
|
28
29
|
button.dataset.speechBound = 'true'; button.classList.add('stt-button');
|
|
29
30
|
var group = document.createElement('span'); group.className = 'stt-controls';
|
|
30
31
|
button.before(group); group.appendChild(button);
|
|
@@ -32,7 +33,7 @@ function bindComposer(id, inputId, wrapperId) {
|
|
|
32
33
|
picker.className = 'stt-picker-toggle'; picker.innerHTML = iconHtml('chevron-down');
|
|
33
34
|
picker.setAttribute('aria-label', 'Choose voice model'); picker.setAttribute('aria-haspopup', 'dialog'); picker.setAttribute('aria-expanded', 'false');
|
|
34
35
|
picker.title = 'Choose voice model'; group.appendChild(picker);
|
|
35
|
-
picker.addEventListener('click', function () { openSpeechPicker(picker); });
|
|
36
|
+
picker.addEventListener('click', function () { refreshSpeechBrowser(); openSpeechPicker(picker); });
|
|
36
37
|
var row = document.createElement('div'); row.className = 'stt-progress'; row.hidden = true;
|
|
37
38
|
var status = document.createElement('span'); status.id = id + '-status'; status.className = 'stt-status'; status.setAttribute('role', 'status');
|
|
38
39
|
var timer = document.createElement('span'); timer.className = 'stt-timer'; timer.setAttribute('aria-hidden', 'true');
|
|
@@ -70,7 +71,7 @@ function bindComposer(id, inputId, wrapperId) {
|
|
|
70
71
|
function render() {
|
|
71
72
|
var active = store.get('speechActive'); var own = !!active && active.id === id;
|
|
72
73
|
var model = voiceModel(); var provider = voiceProvider(model.provider);
|
|
73
|
-
var browser = model.provider === 'browser' ?
|
|
74
|
+
var browser = model.provider === 'browser' ? store.get('speechBrowserIdentity') : null;
|
|
74
75
|
var pending = own && active.model && active.phase !== 'recording';
|
|
75
76
|
var autoSend = own && !!active.autoSend;
|
|
76
77
|
composer.classList.toggle('stt-recording', own);
|
|
@@ -117,7 +118,11 @@ function bindComposer(id, inputId, wrapperId) {
|
|
|
117
118
|
observer.observe(input, { attributes: true, attributeFilter: ['disabled', 'readonly'] });
|
|
118
119
|
render();
|
|
119
120
|
}
|
|
121
|
+
// Browser identity may read layout; refresh on entry and interaction, not transcript updates.
|
|
122
|
+
function refreshSpeechBrowser() { store.set({ speechBrowserIdentity: browserSpeechInfo() }); }
|
|
120
123
|
export function initSTT() {
|
|
124
|
+
refreshSpeechBrowser();
|
|
125
|
+
window.addEventListener('focus', refreshSpeechBrowser);
|
|
121
126
|
initSpeechLifecycle(); initSpeechPicker();
|
|
122
127
|
bindComposer('stt-btn', 'input', 'input-wrapper');
|
|
123
128
|
bindComposer('home-stt-btn', 'home-mate-chat-input', 'home-mate-chat-composer-frame');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
1
2
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
2
3
|
import { closeSidebar } from './sidebar.js';
|
|
3
4
|
import { claimRightWorkbench, registerRightWorkbench, releaseRightWorkbench } from './right-workbench.js';
|
|
@@ -538,6 +539,8 @@ function renderTabBar() {
|
|
|
538
539
|
(function (t) {
|
|
539
540
|
var el = document.createElement("div");
|
|
540
541
|
el.className = "terminal-tab";
|
|
542
|
+
el.dataset.controlTerminalId = String(t.id);
|
|
543
|
+
el.dataset.controlRuntime = store.get("controlRuntimeId") || "";
|
|
541
544
|
if (t.id === activeTabId) el.classList.add("active");
|
|
542
545
|
if (t.exited) el.classList.add("exited");
|
|
543
546
|
|
|
@@ -696,6 +699,7 @@ function updateTerminalBadge() {
|
|
|
696
699
|
// --- Handle server messages ---
|
|
697
700
|
|
|
698
701
|
export function handleTermList(msg) {
|
|
702
|
+
store.set({ clayControlTerminalViews: (msg.terminals || []).map(function (item) { return { id: item.id, identity: item.controlIdentity, revision: item.controlRevision, runtimeId: store.get('controlRuntimeId') }; }) });
|
|
699
703
|
// TUI session terminals are owned by session-tui-view.js and must not
|
|
700
704
|
// appear in the bottom terminal panel. Filter them out before any tab
|
|
701
705
|
// bookkeeping so the panel never tries to render or auto-attach them.
|
|
@@ -762,7 +766,11 @@ export function handleTermCreated(msg) {
|
|
|
762
766
|
}
|
|
763
767
|
}
|
|
764
768
|
|
|
769
|
+
export function handleTerminalProjection(msg) {
|
|
770
|
+
if (msg.controlIdentity && msg.controlRevision) store.set({ clayControlTerminalViews: (store.get('clayControlTerminalViews') || []).map(function (item) { return item.id === msg.id && item.identity === msg.controlIdentity ? Object.assign({}, item, { revision: msg.controlRevision }) : item; }) });
|
|
771
|
+
}
|
|
765
772
|
export function handleTermOutput(msg) {
|
|
773
|
+
handleTerminalProjection(msg);
|
|
766
774
|
if (!msg.id) return;
|
|
767
775
|
var tab = tabs.get(msg.id);
|
|
768
776
|
if (tab && tab.xterm && msg.data) {
|
|
@@ -771,6 +779,7 @@ export function handleTermOutput(msg) {
|
|
|
771
779
|
}
|
|
772
780
|
|
|
773
781
|
export function handleTermResized(msg) {
|
|
782
|
+
handleTerminalProjection(msg);
|
|
774
783
|
if (!msg.id) return;
|
|
775
784
|
var tab = tabs.get(msg.id);
|
|
776
785
|
if (tab && tab.xterm && msg.cols > 0 && msg.rows > 0) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderProductReview } from './product-review.js';
|
|
1
2
|
import { clayToolGroupSummary } from './clay-tool-presentation.js';
|
|
2
3
|
import { applyClayToolItem, applyClayToolResult, finishClayToolItem, findEndedClayTool, clayToolResultGroup, bindToolGroupDisclosure, syncToolGroupDisclosure, syncClayToolGroup } from './clay-tool-activity.js';
|
|
3
4
|
import { escapeHtml, copyToClipboard } from './utils.js';
|
|
@@ -298,6 +299,7 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
298
299
|
var qText = document.createElement("div");
|
|
299
300
|
qText.className = "ask-user-question-text";
|
|
300
301
|
qText.textContent = q.question || "";
|
|
302
|
+
if (renderProductReview(qText, q)) qDiv.dataset.answerLabel = q.review.action;
|
|
301
303
|
qDiv.appendChild(qText);
|
|
302
304
|
|
|
303
305
|
var optionsDiv = document.createElement("div");
|
|
@@ -476,7 +478,8 @@ function showAnswerSummary(container, questions, answers) {
|
|
|
476
478
|
var row = document.createElement("div");
|
|
477
479
|
row.className = "ask-user-answer-row";
|
|
478
480
|
var qi = parseInt(key, 10);
|
|
479
|
-
var
|
|
481
|
+
var questionNode = container.querySelectorAll(".ask-user-question")[qi];
|
|
482
|
+
var label = questionNode && questionNode.dataset.answerLabel || (questions && questions[qi] && (questions[qi].header || questions[qi].question)) || "Answer";
|
|
480
483
|
row.innerHTML = '<span class="ask-user-answer-label">' + escapeHtml(label) + '</span>' +
|
|
481
484
|
'<span class="ask-user-answer-value">' + escapeHtml(String(answers[key])) + '</span>';
|
|
482
485
|
summary.appendChild(row);
|