clay-server 4.0.0-beta.8 → 4.0.0
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/capsule-display-floor.js +51 -0
- package/lib/capsule-frame-server.js +255 -0
- package/lib/capsule-mate-turn.js +105 -0
- package/lib/capsule-pig-logic.js +300 -0
- package/lib/capsule-server-runtimes.js +39 -0
- package/lib/capsules/pig/display.js +198 -0
- package/lib/capsules/pig/manifest.json +9 -0
- package/lib/capsules/pig/ui.json +84 -0
- package/lib/config.js +25 -1
- package/lib/daemon-projects.js +13 -8
- package/lib/daemon.js +127 -14
- package/lib/git-cli.js +95 -1
- package/lib/knowledge-import.js +436 -0
- package/lib/knowledge-record-store.js +188 -0
- package/lib/knowledge-search.js +240 -0
- package/lib/mate-knowledge-mcp-server.js +151 -0
- package/lib/mate-knowledge-migration.js +283 -0
- package/lib/mate-knowledge-service.js +488 -0
- package/lib/mate-knowledge-sync.js +482 -0
- package/lib/migrate-single-user.js +2 -0
- package/lib/notes-lifecycle.js +149 -0
- package/lib/notes.js +60 -3
- package/lib/os-users.js +3 -1
- package/lib/project-capsule-catalog.js +9 -1
- package/lib/project-capsule-turn.js +96 -0
- package/lib/project-connection.js +15 -1
- package/lib/project-file-history.js +223 -0
- package/lib/project-file-watch.js +77 -49
- package/lib/project-filesystem.js +31 -220
- package/lib/project-http.js +15 -1
- package/lib/project-knowledge.js +22 -0
- package/lib/project-log-context.js +172 -0
- package/lib/project-log-feedback-delivery.js +118 -0
- package/lib/project-logs-comments.js +137 -0
- package/lib/project-logs-context-state.js +42 -0
- package/lib/project-logs-mcp-server.js +328 -0
- package/lib/project-logs-query.js +185 -0
- package/lib/project-logs-root.js +75 -0
- package/lib/project-logs-schema.js +259 -0
- package/lib/project-logs-service.js +463 -0
- package/lib/project-logs-snapshot.js +205 -0
- package/lib/project-logs-store.js +495 -0
- package/lib/project-logs-versioning.js +132 -0
- package/lib/project-logs.js +400 -0
- package/lib/project-mate-interaction.js +14 -0
- package/lib/project-mate-knowledge.js +110 -0
- package/lib/project-memory.js +22 -0
- package/lib/project-message-delivery.js +70 -0
- package/lib/project-pair-lifecycle.js +460 -0
- package/lib/project-request-access.js +66 -0
- package/lib/project-session-handoff.js +1 -1
- package/lib/project-session-notes.js +64 -13
- package/lib/project-session-pair.js +159 -146
- package/lib/project-session-spawn.js +1 -1
- package/lib/project-sessions.js +58 -13
- package/lib/project-user-message.js +53 -4
- package/lib/project-worker-permission.js +430 -0
- package/lib/project-worker-proposal.js +208 -62
- package/lib/project.js +185 -6
- package/lib/public/app.js +63 -35
- package/lib/public/css/admin.css +2 -2
- package/lib/public/css/capsule-ui.css +38 -0
- package/lib/public/css/command-palette.css +19 -9
- package/lib/public/css/git-placard.css +154 -0
- package/lib/public/css/home-hub.css +4 -0
- package/lib/public/css/home-session-actions.css +66 -0
- package/lib/public/css/home-sidebar.css +66 -0
- package/lib/public/css/input.css +84 -3
- package/lib/public/css/messages.css +40 -1
- package/lib/public/css/mobile-nav.css +80 -0
- package/lib/public/css/notifications-center.css +67 -0
- package/lib/public/css/pane.css +97 -10
- package/lib/public/css/project-logs.css +198 -0
- package/lib/public/css/scheduler.css +1 -1
- package/lib/public/css/session-actions.css +16 -101
- package/lib/public/css/sidebar.css +103 -0
- package/lib/public/css/sticky-notes.css +237 -229
- package/lib/public/css/worker-proposal.css +36 -3
- package/lib/public/index.html +43 -11
- package/lib/public/modules/admin.js +8 -8
- package/lib/public/modules/app-connection.js +124 -6
- package/lib/public/modules/app-home-hub.js +12 -8
- package/lib/public/modules/app-message-cards.js +2 -1
- package/lib/public/modules/app-messages.js +92 -11
- package/lib/public/modules/app-misc.js +2 -14
- package/lib/public/modules/app-notifications.js +11 -7
- package/lib/public/modules/app-panels.js +3 -2
- package/lib/public/modules/app-projects.js +56 -18
- package/lib/public/modules/app-rendering.js +1 -0
- package/lib/public/modules/capsule-preference.js +44 -0
- package/lib/public/modules/chat-bubble-renderer.js +1 -1
- package/lib/public/modules/clay-log-links.js +70 -0
- package/lib/public/modules/command-palette.js +52 -15
- package/lib/public/modules/context-sources.js +0 -3
- package/lib/public/modules/git-agent-sessions.js +85 -0
- package/lib/public/modules/git-panel.js +111 -84
- package/lib/public/modules/git-placard.js +161 -0
- package/lib/public/modules/home-chat-empty-state.js +39 -0
- package/lib/public/modules/home-chat-identity.js +9 -0
- package/lib/public/modules/home-conversations-sheet.js +102 -48
- package/lib/public/modules/home-mate-chat.js +15 -35
- package/lib/public/modules/home-session-actions.js +6 -0
- package/lib/public/modules/home-sidebar-chat-list.js +101 -41
- package/lib/public/modules/home-sidebar.js +7 -0
- package/lib/public/modules/home-surface-boot.js +7 -3
- package/lib/public/modules/home-tool-frame.js +182 -0
- package/lib/public/modules/home-tools.js +138 -1
- package/lib/public/modules/input.js +38 -7
- package/lib/public/modules/markdown.js +2 -0
- package/lib/public/modules/mate-sidebar.js +0 -8
- package/lib/public/modules/message-delivery.js +97 -0
- package/lib/public/modules/paste-modal.js +84 -0
- package/lib/public/modules/project-activation.js +45 -0
- package/lib/public/modules/project-logs-render.js +405 -0
- package/lib/public/modules/project-logs.js +461 -0
- package/lib/public/modules/project-removal-target.js +26 -0
- package/lib/public/modules/scheduler.js +17 -3
- package/lib/public/modules/session-actions.js +29 -105
- package/lib/public/modules/session-hierarchy.js +54 -0
- package/lib/public/modules/sidebar-mobile.js +40 -15
- package/lib/public/modules/sidebar-session-hierarchy.js +214 -0
- package/lib/public/modules/sidebar-sessions.js +77 -11
- package/lib/public/modules/sidebar.js +17 -5
- package/lib/public/modules/split-group-helpers.js +8 -0
- package/lib/public/modules/split-pair-ui.js +15 -4
- package/lib/public/modules/split-view.js +5 -2
- package/lib/public/modules/split-worker-runtime.js +24 -0
- package/lib/public/modules/sticky-note-markdown.js +5 -0
- package/lib/public/modules/sticky-notes-browser.js +326 -0
- package/lib/public/modules/sticky-notes-card.js +360 -0
- package/lib/public/modules/sticky-notes-editor.js +291 -0
- package/lib/public/modules/sticky-notes-shared.js +90 -0
- package/lib/public/modules/sticky-notes.js +170 -946
- package/lib/public/modules/thinking-lifecycle.js +175 -0
- package/lib/public/modules/thinking-summary.js +28 -0
- package/lib/public/modules/thinking-view.js +75 -0
- package/lib/public/modules/tool-palette-order.js +143 -0
- package/lib/public/modules/tool-palette-overlays.js +159 -0
- package/lib/public/modules/tool-palette.js +21 -188
- package/lib/public/modules/tools.js +31 -123
- package/lib/public/modules/update-snooze.js +169 -0
- package/lib/public/modules/user-settings.js +4 -0
- package/lib/public/modules/worker-pane-lock.js +176 -0
- package/lib/public/modules/worker-proposal-state.js +16 -0
- package/lib/public/modules/worker-proposal.js +49 -20
- package/lib/public/style.css +3 -1
- package/lib/sdk-bridge.js +135 -46
- package/lib/sdk-message-processor.js +36 -19
- package/lib/server-experimental-settings.js +49 -0
- package/lib/server-global-ws.js +11 -0
- package/lib/server-home-chat-events.js +31 -1
- package/lib/server-home-chat.js +27 -4
- package/lib/server-home-clay-entry.js +1 -1
- package/lib/server-home-clay-session-links.js +34 -5
- package/lib/server-settings.js +5 -0
- package/lib/server-tools.js +127 -9
- package/lib/server.js +137 -22
- package/lib/session-driver-eligibility.js +38 -0
- package/lib/session-driver-orchestration.js +31 -0
- package/lib/session-hygiene.js +3 -0
- package/lib/session-notes-mcp-server.js +25 -5
- package/lib/session-pair-factory.js +247 -0
- package/lib/session-pair-mcp-server.js +46 -8
- package/lib/session-pair-prompts.js +79 -0
- package/lib/session-pair-turn-control.js +153 -0
- package/lib/session-provenance.js +119 -0
- package/lib/session-spawn-mcp-server.js +1 -1
- package/lib/session-split-groups.js +4 -1
- package/lib/session-title-policy.js +60 -0
- package/lib/session-visibility.js +41 -0
- package/lib/sessions.js +57 -10
- package/lib/tools-registry.js +89 -10
- package/lib/update-snooze.js +437 -0
- package/lib/users-experimental-preferences.js +30 -0
- package/lib/users-permissions.js +6 -6
- package/lib/users.js +22 -16
- package/lib/workspace-query-access.js +102 -0
- package/lib/workspace-query-service.js +24 -17
- package/lib/worktree.js +25 -38
- package/lib/ws-schema.js +38 -7
- package/lib/yoke/adapters/claude-worker.js +16 -6
- package/lib/yoke/adapters/claude.js +12 -0
- package/lib/yoke/adapters/codex.js +24 -14
- package/lib/yoke/vendor-registry.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// home-chat-empty-state.js - The Home mate chat's empty conversation stage.
|
|
2
|
+
|
|
3
|
+
import { getHomeMateShortBio } from './home-mate-selection.js';
|
|
4
|
+
|
|
5
|
+
export function renderHomeChatEmptyState(messagesEl, suggestionsEl, mate, mateName, onSuggestion) {
|
|
6
|
+
var empty = document.createElement("div");
|
|
7
|
+
empty.className = "home-mate-chat-empty";
|
|
8
|
+
var brand = document.createElement("div");
|
|
9
|
+
brand.className = "home-mate-chat-brand";
|
|
10
|
+
var symbol = document.createElement("img");
|
|
11
|
+
symbol.src = "/clay-studio-symbol.png";
|
|
12
|
+
symbol.alt = "";
|
|
13
|
+
brand.appendChild(symbol);
|
|
14
|
+
var wordmark = document.createElement("span");
|
|
15
|
+
wordmark.className = "home-sidebar-brand-wordmark home-mate-chat-brand-wordmark";
|
|
16
|
+
wordmark.textContent = "Clay Studio";
|
|
17
|
+
brand.appendChild(wordmark);
|
|
18
|
+
empty.appendChild(brand);
|
|
19
|
+
var greeting = document.createElement("h2");
|
|
20
|
+
greeting.textContent = mate ? "What should we work on, " + mateName + "?" : "Getting Home ready...";
|
|
21
|
+
empty.appendChild(greeting);
|
|
22
|
+
var detail = document.createElement("p");
|
|
23
|
+
detail.textContent = mate ? getHomeMateShortBio(mate) : "Loading your Mate and recent conversation.";
|
|
24
|
+
empty.appendChild(detail);
|
|
25
|
+
messagesEl.appendChild(empty);
|
|
26
|
+
suggestionsEl.innerHTML = "";
|
|
27
|
+
if (!mate) return;
|
|
28
|
+
var suggestions = ["Make me a small tool"];
|
|
29
|
+
for (var i = 0; i < suggestions.length; i++) {
|
|
30
|
+
(function (suggestion) {
|
|
31
|
+
var chip = document.createElement("button");
|
|
32
|
+
chip.type = "button";
|
|
33
|
+
chip.className = "home-mate-chat-suggestion";
|
|
34
|
+
chip.textContent = suggestion;
|
|
35
|
+
chip.addEventListener("click", function () { onSuggestion(suggestion); });
|
|
36
|
+
suggestionsEl.appendChild(chip);
|
|
37
|
+
})(suggestions[i]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -33,3 +33,12 @@ export function createHomeOrdinaryTyping(mate, mateName) {
|
|
|
33
33
|
}
|
|
34
34
|
return row;
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
// A Capsule engagement note: a quiet centered system line, not a speech
|
|
38
|
+
// bubble, because no one typed it.
|
|
39
|
+
export function createCapsuleTurnNote(message) {
|
|
40
|
+
var note = document.createElement("div");
|
|
41
|
+
note.className = "home-capsule-turn-note";
|
|
42
|
+
note.textContent = (message && message.text) || "";
|
|
43
|
+
return note;
|
|
44
|
+
}
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
import { store } from './store.js';
|
|
4
4
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
5
5
|
import { getHomeSessionConversations, createHomeSessionActionsTrigger, disposeHomeSessionActionsMenu } from './home-session-actions.js';
|
|
6
|
+
import { buildSessionHierarchy } from './session-hierarchy.js';
|
|
6
7
|
|
|
7
8
|
var overlay = null;
|
|
8
9
|
var searchInput = null;
|
|
9
10
|
var listEl = null;
|
|
10
11
|
var sheetOpener = null;
|
|
11
12
|
var selectConversation = null;
|
|
13
|
+
var hierarchyExpansion = new Map();
|
|
12
14
|
|
|
13
15
|
function closeSheet(restoreFocus) {
|
|
14
16
|
if (!overlay) return;
|
|
@@ -54,66 +56,118 @@ function handleKeydown(event) {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
function conversationMatches(conversation, query) {
|
|
60
|
+
if (!query) return true;
|
|
61
|
+
return conversation.title.toLowerCase().indexOf(query) !== -1 || conversation.mateName.toLowerCase().indexOf(query) !== -1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function createSheetItem(conversation, worker) {
|
|
65
|
+
var item = document.createElement("div");
|
|
66
|
+
item.className = "home-conversations-sheet-item" + (worker ? " home-conversations-worker-item" : "");
|
|
67
|
+
var row = document.createElement("button");
|
|
68
|
+
row.type = "button";
|
|
69
|
+
row.className = "home-conversations-sheet-row";
|
|
70
|
+
var copy = document.createElement("span");
|
|
71
|
+
copy.className = "home-conversations-sheet-copy";
|
|
72
|
+
var title = document.createElement("span");
|
|
73
|
+
title.className = "home-conversations-sheet-row-title";
|
|
74
|
+
title.textContent = conversation.title;
|
|
75
|
+
copy.appendChild(title);
|
|
76
|
+
var mate = document.createElement("span");
|
|
77
|
+
mate.className = "home-conversations-sheet-row-mate";
|
|
78
|
+
mate.textContent = worker && conversation.workerGeneration ? conversation.mateName + " · Worker generation " + conversation.workerGeneration : conversation.mateName;
|
|
79
|
+
copy.appendChild(mate);
|
|
80
|
+
row.appendChild(copy);
|
|
81
|
+
if (conversation.isProcessing) {
|
|
82
|
+
var activity = document.createElement("span");
|
|
83
|
+
activity.className = "home-sidebar-processing";
|
|
84
|
+
activity.setAttribute("aria-label", "Processing");
|
|
85
|
+
row.appendChild(activity);
|
|
86
|
+
}
|
|
87
|
+
row.addEventListener("click", function () {
|
|
88
|
+
var onSelect = selectConversation;
|
|
89
|
+
closeSheet();
|
|
90
|
+
if (onSelect) onSelect(conversation.mateId, conversation.sessionId);
|
|
91
|
+
});
|
|
92
|
+
var active = conversation.mateId === store.get('homeChatMateId') && conversation.sessionId === store.get('homeChatSessionId');
|
|
93
|
+
if (active) {
|
|
94
|
+
item.classList.add("is-active");
|
|
95
|
+
row.setAttribute("aria-current", "page");
|
|
96
|
+
}
|
|
97
|
+
var detailsReturn = sheetOpener;
|
|
98
|
+
var actions = createHomeSessionActionsTrigger(conversation, {
|
|
99
|
+
detailsOpener: detailsReturn,
|
|
100
|
+
beforeOpenDetails: function () { closeSheet(false); },
|
|
101
|
+
});
|
|
102
|
+
item.appendChild(row);
|
|
103
|
+
item.appendChild(actions);
|
|
104
|
+
return item;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function createSheetHierarchy(root, query) {
|
|
108
|
+
if (!root.workers.length) return createSheetItem(root.driver, false);
|
|
109
|
+
var key = root.driver.hierarchyId;
|
|
110
|
+
var expanded = hierarchyExpansion.has(key) ? hierarchyExpansion.get(key) : !!query;
|
|
111
|
+
for (var ai = 0; ai < root.workers.length; ai++) {
|
|
112
|
+
if (root.workers[ai].mateId === store.get('homeChatMateId') && root.workers[ai].sessionId === store.get('homeChatSessionId')) expanded = true;
|
|
113
|
+
}
|
|
114
|
+
var wrapper = document.createElement("div");
|
|
115
|
+
wrapper.className = "home-conversations-driver-hierarchy";
|
|
116
|
+
var header = document.createElement("div");
|
|
117
|
+
header.className = "home-conversations-driver-header";
|
|
118
|
+
var toggle = document.createElement("button");
|
|
119
|
+
toggle.type = "button";
|
|
120
|
+
toggle.className = "home-conversations-driver-toggle";
|
|
121
|
+
var childrenId = "home-sheet-workers-" + String(key).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
122
|
+
toggle.setAttribute("aria-expanded", String(expanded));
|
|
123
|
+
toggle.setAttribute("aria-controls", childrenId);
|
|
124
|
+
toggle.setAttribute("aria-label", (expanded ? "Collapse" : "Expand") + " Workers for " + (root.driver.title || "Unavailable Driver"));
|
|
125
|
+
toggle.innerHTML = iconHtml("chevron-right");
|
|
126
|
+
if (!root.driver.sessionId) toggle.insertAdjacentHTML("beforeend", "<span>Unavailable Driver</span><span>" + root.workers.length + "</span>");
|
|
127
|
+
toggle.addEventListener("click", function () {
|
|
128
|
+
hierarchyExpansion.set(key, !expanded);
|
|
129
|
+
renderRows();
|
|
130
|
+
});
|
|
131
|
+
header.appendChild(toggle);
|
|
132
|
+
if (root.driver.sessionId) header.appendChild(createSheetItem(root.driver, false));
|
|
133
|
+
wrapper.appendChild(header);
|
|
134
|
+
var children = document.createElement("div");
|
|
135
|
+
children.id = childrenId;
|
|
136
|
+
children.className = "home-conversations-worker-children";
|
|
137
|
+
children.setAttribute("role", "group");
|
|
138
|
+
children.setAttribute("aria-label", "Workers for " + (root.driver.title || "Unavailable Driver"));
|
|
139
|
+
children.hidden = !expanded;
|
|
140
|
+
var driverMatched = root.driver.sessionId && conversationMatches(root.driver, query);
|
|
141
|
+
for (var i = 0; i < root.workers.length; i++) {
|
|
142
|
+
if (!query || driverMatched || conversationMatches(root.workers[i], query)) children.appendChild(createSheetItem(root.workers[i], true));
|
|
143
|
+
}
|
|
144
|
+
wrapper.appendChild(children);
|
|
145
|
+
return wrapper;
|
|
146
|
+
}
|
|
147
|
+
|
|
57
148
|
function renderRows() {
|
|
58
149
|
if (!listEl) return;
|
|
59
150
|
var query = searchInput ? searchInput.value.trim().toLowerCase() : "";
|
|
60
|
-
var
|
|
61
|
-
|
|
62
|
-
|
|
151
|
+
var hierarchy = buildSessionHierarchy(getHomeSessionConversations());
|
|
152
|
+
var roots = hierarchy.roots.filter(function (root) {
|
|
153
|
+
if (conversationMatches(root.driver, query)) return true;
|
|
154
|
+
for (var i = 0; i < root.workers.length; i++) if (conversationMatches(root.workers[i], query)) return true;
|
|
155
|
+
return false;
|
|
63
156
|
});
|
|
157
|
+
var orphans = hierarchy.orphans.filter(function (worker) { return conversationMatches(worker, query); });
|
|
64
158
|
disposeHomeSessionActionsMenu();
|
|
65
159
|
listEl.innerHTML = "";
|
|
66
|
-
if (!
|
|
160
|
+
if (!roots.length && !orphans.length) {
|
|
67
161
|
var empty = document.createElement("div");
|
|
68
162
|
empty.className = "home-conversations-sheet-empty";
|
|
69
163
|
empty.textContent = query ? "No chats match your search." : "No chats yet.";
|
|
70
164
|
listEl.appendChild(empty);
|
|
71
165
|
return;
|
|
72
166
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
var row = document.createElement("button");
|
|
78
|
-
row.type = "button";
|
|
79
|
-
row.className = "home-conversations-sheet-row";
|
|
80
|
-
var copy = document.createElement("span");
|
|
81
|
-
copy.className = "home-conversations-sheet-copy";
|
|
82
|
-
var title = document.createElement("span");
|
|
83
|
-
title.className = "home-conversations-sheet-row-title";
|
|
84
|
-
title.textContent = conversation.title;
|
|
85
|
-
copy.appendChild(title);
|
|
86
|
-
var mate = document.createElement("span");
|
|
87
|
-
mate.className = "home-conversations-sheet-row-mate";
|
|
88
|
-
mate.textContent = conversation.mateName;
|
|
89
|
-
copy.appendChild(mate);
|
|
90
|
-
row.appendChild(copy);
|
|
91
|
-
if (conversation.isProcessing) {
|
|
92
|
-
var activity = document.createElement("span");
|
|
93
|
-
activity.className = "home-sidebar-processing";
|
|
94
|
-
activity.setAttribute("aria-label", "Processing");
|
|
95
|
-
row.appendChild(activity);
|
|
96
|
-
}
|
|
97
|
-
row.addEventListener("click", function () {
|
|
98
|
-
var onSelect = selectConversation;
|
|
99
|
-
closeSheet();
|
|
100
|
-
if (onSelect) onSelect(conversation.mateId, conversation.sessionId);
|
|
101
|
-
});
|
|
102
|
-
var active = conversation.mateId === store.get('homeChatMateId') && conversation.sessionId === store.get('homeChatSessionId');
|
|
103
|
-
if (active) {
|
|
104
|
-
item.classList.add("is-active");
|
|
105
|
-
row.setAttribute("aria-current", "page");
|
|
106
|
-
}
|
|
107
|
-
var detailsReturn = sheetOpener;
|
|
108
|
-
var actions = createHomeSessionActionsTrigger(conversation, {
|
|
109
|
-
detailsOpener: detailsReturn,
|
|
110
|
-
beforeOpenDetails: function () { closeSheet(false); },
|
|
111
|
-
});
|
|
112
|
-
item.appendChild(row);
|
|
113
|
-
item.appendChild(actions);
|
|
114
|
-
listEl.appendChild(item);
|
|
115
|
-
})(all[i]);
|
|
116
|
-
}
|
|
167
|
+
roots.sort(function (a, b) { return b.lastActivity - a.lastActivity; });
|
|
168
|
+
for (var i = 0; i < roots.length; i++) listEl.appendChild(createSheetHierarchy(roots[i], query));
|
|
169
|
+
if (orphans.length) listEl.appendChild(createSheetHierarchy({ driver: { hierarchyId: "orphan-sheet", title: "Unavailable Driver" }, workers: orphans }, query));
|
|
170
|
+
refreshIcons();
|
|
117
171
|
}
|
|
118
172
|
|
|
119
173
|
export function openHomeConversationsSheet(onSelect, opener) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { store } from './store.js';
|
|
3
3
|
import { getWs } from './ws-ref.js';
|
|
4
4
|
import { renderAssistantBubbleText, finalizeAssistantBubble, disposeChatBubbleTree } from './chat-bubble-renderer.js';
|
|
5
|
-
import { createHomeOrdinaryBubble, createHomeOrdinaryTyping } from './home-chat-identity.js';
|
|
5
|
+
import { createHomeOrdinaryBubble, createHomeOrdinaryTyping, createCapsuleTurnNote } from './home-chat-identity.js';
|
|
6
6
|
import { openHomeMateSettings, closeHomeMateSettings } from './home-mate-settings.js';
|
|
7
7
|
import { forgetHomeSession, rememberHomeMate, rememberHomeSession } from './home-surface.js';
|
|
8
8
|
import { isOwnedHomeSessionMessage, resolveHomeSessionIdentity, appendHomeStreamText, finalizeHomeAssistant } from './home-chat-stream-state.js';
|
|
@@ -16,7 +16,8 @@ import { setHomeSubSurface } from './home-sub-surface.js';
|
|
|
16
16
|
import { createWorkspaceAssignmentCard, applyHomeWorkspaceAssignment } from './workspace-assignment-card.js';
|
|
17
17
|
import { markHomeChatActivity, followHomeChatNextRender, captureHomeChatScroll, restoreHomeChatScroll } from './home-chat-scroll.js';
|
|
18
18
|
import { createHomeMateProposalCard, createHomeMateProposalResponder, applyHomeMateProposal, resolveHomeMateProposal, restoreHomeMateProposalFocus } from './home-mate-creation.js';
|
|
19
|
-
import { findHomeMate, getHomeMateName
|
|
19
|
+
import { findHomeMate, getHomeMateName } from './home-mate-selection.js';
|
|
20
|
+
import { renderHomeChatEmptyState } from './home-chat-empty-state.js';
|
|
20
21
|
var messages = [], streamingText = "", streaming = false, bound = false, animateSwitch = false;
|
|
21
22
|
var chatEl = null, stageEl = null, messagesEl = null, suggestionsEl = null, inputEl = null, sendBtn = null;
|
|
22
23
|
var sessionModelEl = null, sessionModelValueEl = null, sessionModelChooseEl = null, sessionRequestSequence = 0, activeSessionRequestId = null, mateCreationActive = false;
|
|
@@ -167,6 +168,7 @@ function ensureDom() {
|
|
|
167
168
|
}
|
|
168
169
|
function formatTime(timestamp) { var date = timestamp ? new Date(timestamp) : null; return date ? date.getHours().toString().padStart(2, "0") + ":" + date.getMinutes().toString().padStart(2, "0") : ""; }
|
|
169
170
|
function appendMessage(message, mate, mateName, finalize) {
|
|
171
|
+
if (message.role === "capsule_turn") return createCapsuleTurnNote(message);
|
|
170
172
|
if (message.role === "assignment") return createWorkspaceAssignmentCard(message.assignment, { home: true, context: { mateId: store.get('homeChatMateId'), sessionId: store.get('homeChatSessionId'), requestId: activeSessionRequestId } });
|
|
171
173
|
if (message.role === "mate_proposal") return createHomeMateProposalCard(message, respondToMateProposal, function (created) { openHomeChat(created.mateId); });
|
|
172
174
|
if (message.role === "proposal" || message.role === "question") return createHomeDebateTranscriptCard(message, respondToDebateTranscript);
|
|
@@ -182,39 +184,7 @@ function appendMessage(message, mate, mateName, finalize) {
|
|
|
182
184
|
return row;
|
|
183
185
|
}
|
|
184
186
|
function renderEmptyState(mate, mateName) {
|
|
185
|
-
|
|
186
|
-
empty.className = "home-mate-chat-empty";
|
|
187
|
-
var brand = document.createElement("div");
|
|
188
|
-
brand.className = "home-mate-chat-brand";
|
|
189
|
-
var symbol = document.createElement("img");
|
|
190
|
-
symbol.src = "/clay-studio-symbol.png";
|
|
191
|
-
symbol.alt = "";
|
|
192
|
-
brand.appendChild(symbol);
|
|
193
|
-
var wordmark = document.createElement("span");
|
|
194
|
-
wordmark.className = "home-sidebar-brand-wordmark home-mate-chat-brand-wordmark";
|
|
195
|
-
wordmark.textContent = "Clay Studio";
|
|
196
|
-
brand.appendChild(wordmark);
|
|
197
|
-
empty.appendChild(brand);
|
|
198
|
-
var greeting = document.createElement("h2");
|
|
199
|
-
greeting.textContent = mate ? "What should we work on, " + mateName + "?" : "Getting Home ready...";
|
|
200
|
-
empty.appendChild(greeting);
|
|
201
|
-
var detail = document.createElement("p");
|
|
202
|
-
detail.textContent = mate ? getHomeMateShortBio(mate) : "Loading your Mate and recent conversation.";
|
|
203
|
-
empty.appendChild(detail);
|
|
204
|
-
messagesEl.appendChild(empty);
|
|
205
|
-
suggestionsEl.innerHTML = "";
|
|
206
|
-
if (!mate) return;
|
|
207
|
-
var suggestions = ["Make me a small tool"];
|
|
208
|
-
for (var i = 0; i < suggestions.length; i++) {
|
|
209
|
-
(function (suggestion) {
|
|
210
|
-
var chip = document.createElement("button");
|
|
211
|
-
chip.type = "button";
|
|
212
|
-
chip.className = "home-mate-chat-suggestion";
|
|
213
|
-
chip.textContent = suggestion;
|
|
214
|
-
chip.addEventListener("click", function () { submitSuggestion(suggestion); });
|
|
215
|
-
suggestionsEl.appendChild(chip);
|
|
216
|
-
})(suggestions[i]);
|
|
217
|
-
}
|
|
187
|
+
renderHomeChatEmptyState(messagesEl, suggestionsEl, mate, mateName, submitSuggestion);
|
|
218
188
|
}
|
|
219
189
|
export function renderHomeChat() {
|
|
220
190
|
if (!ensureDom()) return;
|
|
@@ -396,6 +366,16 @@ export function handleHomeWorkspaceAssignment(msg) {
|
|
|
396
366
|
messages = applyHomeWorkspaceAssignment(messages, msg);
|
|
397
367
|
renderHomeChat();
|
|
398
368
|
}
|
|
369
|
+
// A tool call ended the mate's spoken burst: seal what has streamed so far
|
|
370
|
+
// into its own bubble; later deltas start a fresh one. Streaming stays on;
|
|
371
|
+
// the turn is not over.
|
|
372
|
+
export function handleHomeMateSegment(msg) {
|
|
373
|
+
if (!isCurrentSessionMessage(msg) || !streamingText) return;
|
|
374
|
+
messages.push({ role: "assistant", text: streamingText, ts: Date.now() });
|
|
375
|
+
streamingText = "";
|
|
376
|
+
renderHomeChat();
|
|
377
|
+
}
|
|
378
|
+
|
|
399
379
|
export function handleHomeMateDone(msg) {
|
|
400
380
|
if (!isCurrentSessionMessage(msg)) return;
|
|
401
381
|
markHomeChatActivity();
|
|
@@ -53,6 +53,12 @@ export function getHomeSessionConversations() {
|
|
|
53
53
|
createdAt: typeof sessions[j].createdAt === "number" ? sessions[j].createdAt : 0,
|
|
54
54
|
lastActivity: typeof sessions[j].lastActivity === "number" ? sessions[j].lastActivity : 0,
|
|
55
55
|
isProcessing: sessions[j].isProcessing === true,
|
|
56
|
+
sessionRole: sessions[j].sessionRole === "worker" ? "worker" : "driver",
|
|
57
|
+
parentSessionId: safeText(sessions[j].parentSessionId, null),
|
|
58
|
+
parentAvailable: sessions[j].parentAvailable === true,
|
|
59
|
+
workerGeneration: typeof sessions[j].workerGeneration === "number" ? sessions[j].workerGeneration : null,
|
|
60
|
+
hierarchyId: mateIds[i] + ":" + sessions[j].id,
|
|
61
|
+
parentHierarchyId: sessions[j].parentSessionId ? mateIds[i] + ":" + sessions[j].parentSessionId : null,
|
|
56
62
|
});
|
|
57
63
|
}
|
|
58
64
|
}
|
|
@@ -1,7 +1,98 @@
|
|
|
1
|
-
// Complete
|
|
1
|
+
// Complete Home chat archive rendered as provenance-preserving session trees.
|
|
2
2
|
|
|
3
3
|
import { store } from './store.js';
|
|
4
|
+
import { iconHtml, refreshIcons } from './icons.js';
|
|
4
5
|
import { getHomeSessionConversations, createHomeSessionActionsTrigger, disposeHomeSessionActionsMenu } from './home-session-actions.js';
|
|
6
|
+
import { buildSessionHierarchy } from './session-hierarchy.js';
|
|
7
|
+
|
|
8
|
+
var expansion = new Map();
|
|
9
|
+
|
|
10
|
+
function isExpanded(key, workers) {
|
|
11
|
+
if (expansion.has(key)) return expansion.get(key);
|
|
12
|
+
for (var i = 0; i < workers.length; i++) {
|
|
13
|
+
if (workers[i].mateId === store.get('homeChatMateId') && workers[i].sessionId === store.get('homeChatSessionId')) return true;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createChatItem(chat, openConversation, worker) {
|
|
19
|
+
var item = document.createElement("div");
|
|
20
|
+
item.className = "home-sidebar-recent-item" + (worker ? " home-sidebar-worker-item" : "");
|
|
21
|
+
var row = document.createElement("button");
|
|
22
|
+
row.type = "button";
|
|
23
|
+
row.className = "home-sidebar-recent-row";
|
|
24
|
+
row.setAttribute("aria-label", chat.title + ", with " + chat.mateName);
|
|
25
|
+
if (chat.mateId === store.get('homeChatMateId') && chat.sessionId === store.get('homeChatSessionId')) {
|
|
26
|
+
item.classList.add("is-active");
|
|
27
|
+
row.setAttribute("aria-current", "page");
|
|
28
|
+
}
|
|
29
|
+
var copy = document.createElement("span");
|
|
30
|
+
copy.className = "home-sidebar-recent-copy";
|
|
31
|
+
var title = document.createElement("span");
|
|
32
|
+
title.className = "home-sidebar-recent-title";
|
|
33
|
+
title.textContent = chat.title;
|
|
34
|
+
var mate = document.createElement("span");
|
|
35
|
+
mate.className = "home-sidebar-recent-mate";
|
|
36
|
+
mate.textContent = worker && chat.workerGeneration ? chat.mateName + " · Worker generation " + chat.workerGeneration : chat.mateName;
|
|
37
|
+
copy.appendChild(title);
|
|
38
|
+
copy.appendChild(mate);
|
|
39
|
+
row.appendChild(copy);
|
|
40
|
+
if (chat.isProcessing) {
|
|
41
|
+
var activity = document.createElement("span");
|
|
42
|
+
activity.className = "home-sidebar-processing";
|
|
43
|
+
activity.setAttribute("aria-label", "Processing");
|
|
44
|
+
row.appendChild(activity);
|
|
45
|
+
}
|
|
46
|
+
row.addEventListener("click", function () {
|
|
47
|
+
if (typeof openConversation === "function") openConversation(chat.mateId, chat.sessionId);
|
|
48
|
+
});
|
|
49
|
+
item.appendChild(row);
|
|
50
|
+
item.appendChild(createHomeSessionActionsTrigger(chat));
|
|
51
|
+
return item;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createHierarchy(root, openConversation) {
|
|
55
|
+
if (!root.workers.length) return createChatItem(root.driver, openConversation, false);
|
|
56
|
+
var wrapper = document.createElement("div");
|
|
57
|
+
wrapper.className = "home-sidebar-driver-hierarchy";
|
|
58
|
+
var key = root.driver.hierarchyId;
|
|
59
|
+
var expanded = isExpanded(key, root.workers);
|
|
60
|
+
var childrenId = "home-sidebar-workers-" + String(key).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
61
|
+
var header = document.createElement("div");
|
|
62
|
+
header.className = "home-sidebar-driver-header";
|
|
63
|
+
var toggle = document.createElement("button");
|
|
64
|
+
toggle.type = "button";
|
|
65
|
+
toggle.className = "home-sidebar-driver-toggle";
|
|
66
|
+
toggle.setAttribute("aria-expanded", String(expanded));
|
|
67
|
+
toggle.setAttribute("aria-controls", childrenId);
|
|
68
|
+
toggle.setAttribute("aria-label", (expanded ? "Collapse" : "Expand") + " Workers for " + (root.driver.title || "Unavailable Driver"));
|
|
69
|
+
toggle.innerHTML = iconHtml("chevron-right");
|
|
70
|
+
toggle.addEventListener("click", function () {
|
|
71
|
+
expansion.set(key, !expanded);
|
|
72
|
+
renderHomeSidebarChats(openConversation);
|
|
73
|
+
});
|
|
74
|
+
header.appendChild(toggle);
|
|
75
|
+
if (root.driver.sessionId) header.appendChild(createChatItem(root.driver, openConversation, false));
|
|
76
|
+
wrapper.appendChild(header);
|
|
77
|
+
var children = document.createElement("div");
|
|
78
|
+
children.id = childrenId;
|
|
79
|
+
children.className = "home-sidebar-worker-children";
|
|
80
|
+
children.setAttribute("role", "group");
|
|
81
|
+
children.setAttribute("aria-label", "Workers for " + (root.driver.title || "Unavailable Driver"));
|
|
82
|
+
children.hidden = !expanded;
|
|
83
|
+
for (var i = 0; i < root.workers.length; i++) children.appendChild(createChatItem(root.workers[i], openConversation, true));
|
|
84
|
+
wrapper.appendChild(children);
|
|
85
|
+
return wrapper;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function createOrphans(workers, openConversation) {
|
|
89
|
+
var wrapper = createHierarchy({ driver: { hierarchyId: "orphan-home", title: "Unavailable Driver" }, workers: workers }, openConversation);
|
|
90
|
+
var toggle = wrapper.querySelector(".home-sidebar-driver-toggle");
|
|
91
|
+
toggle.classList.add("home-sidebar-orphan-toggle");
|
|
92
|
+
toggle.setAttribute("aria-label", "Toggle Workers whose Driver is unavailable");
|
|
93
|
+
toggle.insertAdjacentHTML("beforeend", "<span>Unavailable Driver</span><span>" + workers.length + "</span>");
|
|
94
|
+
return wrapper;
|
|
95
|
+
}
|
|
5
96
|
|
|
6
97
|
export function renderHomeSidebarChats(openConversation) {
|
|
7
98
|
var list = document.getElementById("home-sidebar-recent-list");
|
|
@@ -11,9 +102,7 @@ export function renderHomeSidebarChats(openConversation) {
|
|
|
11
102
|
var chats = getHomeSessionConversations();
|
|
12
103
|
var scope = store.get('homeChatScope') === "current" ? "current" : "all";
|
|
13
104
|
var activeMateId = store.get('homeChatMateId');
|
|
14
|
-
if (scope === "current") {
|
|
15
|
-
chats = chats.filter(function (chat) { return chat.mateId === activeMateId; });
|
|
16
|
-
}
|
|
105
|
+
if (scope === "current") chats = chats.filter(function (chat) { return chat.mateId === activeMateId; });
|
|
17
106
|
if (!chats.length) {
|
|
18
107
|
var empty = document.createElement("div");
|
|
19
108
|
empty.className = "home-sidebar-recent-empty";
|
|
@@ -21,43 +110,14 @@ export function renderHomeSidebarChats(openConversation) {
|
|
|
21
110
|
list.appendChild(empty);
|
|
22
111
|
return 0;
|
|
23
112
|
}
|
|
24
|
-
var
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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]);
|
|
113
|
+
var hierarchy = buildSessionHierarchy(chats);
|
|
114
|
+
var hasHierarchy = hierarchy.orphans.length > 0;
|
|
115
|
+
hierarchy.roots.sort(function (a, b) { return b.lastActivity - a.lastActivity; });
|
|
116
|
+
for (var i = 0; i < hierarchy.roots.length; i++) {
|
|
117
|
+
if (hierarchy.roots[i].workers.length) hasHierarchy = true;
|
|
118
|
+
list.appendChild(createHierarchy(hierarchy.roots[i], openConversation));
|
|
61
119
|
}
|
|
120
|
+
if (hierarchy.orphans.length) list.appendChild(createOrphans(hierarchy.orphans, openConversation));
|
|
121
|
+
if (hasHierarchy) refreshIcons();
|
|
62
122
|
return chats.length;
|
|
63
123
|
}
|
|
@@ -10,6 +10,7 @@ import { openHomeConversationsSheet, refreshHomeConversationsSheet } from './hom
|
|
|
10
10
|
import { renderHomeSidebarChats } from './home-sidebar-chat-list.js';
|
|
11
11
|
import { syncHomeSessionDetails } from './home-session-actions.js';
|
|
12
12
|
import { toggleHomeCapsules } from './home-dock.js';
|
|
13
|
+
import { openHomeScheduler } from './scheduler.js';
|
|
13
14
|
|
|
14
15
|
var initialized = false;
|
|
15
16
|
var requestedMateIds = {};
|
|
@@ -119,6 +120,11 @@ function toggleCapsulesFromSidebar() {
|
|
|
119
120
|
closeNarrowDrawer(!opening);
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
function openScheduledTasksFromSidebar() {
|
|
124
|
+
openHomeScheduler();
|
|
125
|
+
closeNarrowDrawer(false);
|
|
126
|
+
}
|
|
127
|
+
|
|
122
128
|
function handleSidebarKeydown(event) {
|
|
123
129
|
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
124
130
|
if (!document.body.classList.contains("home-active")) return;
|
|
@@ -137,6 +143,7 @@ export function initHomeSidebar() {
|
|
|
137
143
|
document.getElementById("home-sidebar-new").addEventListener("click", startConversationFromSidebar);
|
|
138
144
|
document.getElementById("home-sidebar-all").addEventListener("click", openAllConversations);
|
|
139
145
|
document.getElementById("home-sidebar-debate").addEventListener("click", openDebatesFromSidebar);
|
|
146
|
+
document.getElementById("home-scheduler-btn").addEventListener("click", openScheduledTasksFromSidebar);
|
|
140
147
|
document.getElementById("home-tools-btn").addEventListener("click", toggleCapsulesFromSidebar);
|
|
141
148
|
var scopeButtons = document.querySelectorAll("[data-home-chat-scope]");
|
|
142
149
|
for (var i = 0; i < scopeButtons.length; i++) scopeButtons[i].addEventListener("click", setChatScope);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// One-shot
|
|
1
|
+
// One-shot routing for a server-selected project or the no-project Home fallback.
|
|
2
2
|
import { store } from './store.js';
|
|
3
3
|
import { rememberHomePrimarySurface } from './home-surface.js';
|
|
4
4
|
|
|
@@ -10,9 +10,13 @@ function explicitProjectPath(pathname) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export function resolveHomeBootDestination(options) {
|
|
13
|
-
if (!options
|
|
13
|
+
if (!options) return "wait";
|
|
14
14
|
if (options.paneMode || explicitProjectPath(options.pathname)) return "project";
|
|
15
|
-
|
|
15
|
+
// The server-selected project embedded in the root shell is authoritative.
|
|
16
|
+
// Home is entered only through an explicit in-app action; reloading `/`
|
|
17
|
+
// returns to the project workspace even if Home was the last open surface.
|
|
18
|
+
if (options.currentSlug) return "project";
|
|
19
|
+
if (options.surfaceLoaded !== true) return "wait";
|
|
16
20
|
if (options.dockLoaded !== true) return "wait";
|
|
17
21
|
return "home";
|
|
18
22
|
}
|