clay-server 5.0.2-beta.1 → 5.1.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/LICENSES/README.md +4 -0
- package/LICENSES/dicebear-avatars.md +16 -0
- package/lib/daemon-project-access.js +7 -1
- package/lib/daemon.js +2 -0
- package/lib/dicebear-avatar.js +62 -0
- package/lib/knowledge-db-service.js +175 -0
- package/lib/knowledge-db-validation.js +0 -0
- package/lib/knowledge-document-index.js +49 -0
- package/lib/knowledge-draft-store.js +56 -0
- package/lib/knowledge-file-store.js +199 -0
- package/lib/knowledge-markdown.js +128 -0
- package/lib/mate-knowledge-mcp-server.js +29 -6
- package/lib/mate-knowledge-service.js +23 -2
- package/lib/mate-knowledge-sync.js +36 -21
- package/lib/mate-workspace-color.js +4 -0
- package/lib/mates.js +18 -0
- package/lib/project-connection.js +36 -2
- package/lib/project-debate-proposal.js +6 -0
- package/lib/project-debate-workspace.js +43 -0
- package/lib/project-debate.js +1 -0
- package/lib/project-file-path.js +2 -3
- package/lib/project-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- package/lib/project-request-access.js +13 -1
- package/lib/project-sessions.js +39 -2
- package/lib/project-user-knowledge.js +60 -0
- package/lib/project.js +59 -18
- package/lib/public/app.js +73 -34
- package/lib/public/clay-studio-wordmark-bold.svg +20 -0
- package/lib/public/css/clay-workspace.css +105 -0
- package/lib/public/css/debates-workbench.css +47 -0
- package/lib/public/css/filebrowser.css +10 -0
- package/lib/public/css/home-debate-live.css +26 -0
- package/lib/public/css/home-hub.css +3 -1
- package/lib/public/css/home-mate-model-picker.css +15 -131
- package/lib/public/css/home-mate-settings.css +168 -16
- package/lib/public/css/icon-strip.css +249 -32
- package/lib/public/css/mate-conversation.css +176 -0
- package/lib/public/css/mate-knowledge-workbench.css +118 -0
- package/lib/public/css/mate-workspace-color.css +16 -0
- package/lib/public/css/mates.css +28 -28
- package/lib/public/css/messages.css +1 -114
- package/lib/public/css/mobile-nav.css +16 -16
- package/lib/public/css/overlays.css +8 -0
- package/lib/public/css/project-logs.css +7 -0
- package/lib/public/css/project-mate-creation.css +105 -0
- package/lib/public/css/right-workbench.css +3 -3
- package/lib/public/css/session-folders.css +80 -21
- package/lib/public/css/sidebar.css +183 -107
- package/lib/public/css/title-bar.css +151 -0
- package/lib/public/css/worker-delegation.css +47 -0
- package/lib/public/css/worker-proposal.css +72 -150
- package/lib/public/css/you.css +74 -0
- package/lib/public/index.html +33 -101
- package/lib/public/modules/account-island.js +230 -0
- package/lib/public/modules/app-cursors.js +19 -43
- package/lib/public/modules/app-debate-ui.js +4 -3
- package/lib/public/modules/app-header.js +106 -0
- package/lib/public/modules/app-message-router.js +12 -3
- package/lib/public/modules/app-messages.js +34 -9
- package/lib/public/modules/app-notifications.js +4 -7
- package/lib/public/modules/app-projects.js +5 -38
- package/lib/public/modules/app-rendering.js +12 -13
- package/lib/public/modules/avatar.js +25 -9
- package/lib/public/modules/chat-render-runtime.js +16 -4
- package/lib/public/modules/command-palette.js +2 -15
- package/lib/public/modules/cursor-sharing-preference.js +3 -3
- package/lib/public/modules/debate-controls.js +299 -0
- package/lib/public/modules/debate.js +2 -0
- package/lib/public/modules/debates-workbench.js +339 -0
- package/lib/public/modules/default-ai.js +81 -65
- package/lib/public/modules/filebrowser.js +28 -8
- package/lib/public/modules/home-debate-controls.js +18 -289
- package/lib/public/modules/home-mate-avatar-editor.js +228 -0
- package/lib/public/modules/home-mate-color-picker.js +66 -0
- package/lib/public/modules/home-mate-creation.js +1 -1
- package/lib/public/modules/home-mate-instructions.js +90 -0
- package/lib/public/modules/home-mate-model-picker.js +80 -271
- package/lib/public/modules/home-mate-profile-editor.js +72 -0
- package/lib/public/modules/home-mate-settings.js +118 -125
- package/lib/public/modules/home-shell.js +3 -0
- package/lib/public/modules/home-surface-boot.js +1 -9
- package/lib/public/modules/html-preview.js +19 -0
- package/lib/public/modules/icon-strip-tooltip.js +95 -0
- package/lib/public/modules/knowledge-db-edit-state.js +35 -0
- package/lib/public/modules/knowledge-db-workbench.js +234 -0
- package/lib/public/modules/knowledge-history-state.js +55 -0
- package/lib/public/modules/knowledge-markdown-editor.js +57 -0
- package/lib/public/modules/knowledge-preview-links.js +70 -0
- package/lib/public/modules/knowledge-workbench-shell.js +21 -0
- package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
- package/lib/public/modules/mate-knowledge-workbench.js +500 -0
- package/lib/public/modules/mate-knowledge.js +11 -3
- package/lib/public/modules/mate-management.js +54 -10
- package/lib/public/modules/mate-sidebar.js +11 -1
- package/lib/public/modules/mate-workspace-color.js +33 -0
- package/lib/public/modules/mention.js +5 -13
- package/lib/public/modules/profile.js +51 -18
- package/lib/public/modules/project-chat-identity.js +79 -0
- package/lib/public/modules/project-debate-planning-workspace.js +250 -0
- package/lib/public/modules/project-debate-workspace.js +185 -0
- package/lib/public/modules/project-header-identity.js +127 -0
- package/lib/public/modules/project-logs-render.js +9 -4
- package/lib/public/modules/project-mate-creation-workspace.js +414 -0
- package/lib/public/modules/project-mate-navigation.js +238 -0
- package/lib/public/modules/project-session-navigation.js +29 -0
- package/lib/public/modules/project-switcher.js +6 -8
- package/lib/public/modules/projects-hub-view.js +5 -6
- package/lib/public/modules/projects-hub.js +2 -6
- package/lib/public/modules/qrcode.js +27 -8
- package/lib/public/modules/search-clay-chat.js +8 -11
- package/lib/public/modules/session-activity-tooltip.js +12 -0
- package/lib/public/modules/session-create-form.js +86 -14
- package/lib/public/modules/session-create.js +50 -7
- package/lib/public/modules/session-list-visibility.js +41 -0
- package/lib/public/modules/session-presence-ui.js +4 -1
- package/lib/public/modules/session-title-marquee.js +51 -0
- package/lib/public/modules/sidebar-mates.js +3 -50
- package/lib/public/modules/sidebar-mobile.js +63 -60
- package/lib/public/modules/sidebar-projects.js +84 -97
- package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
- package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
- package/lib/public/modules/sidebar-sessions.js +49 -50
- package/lib/public/modules/sidebar.js +11 -13
- package/lib/public/modules/thinking-lifecycle.js +7 -6
- package/lib/public/modules/tool-palette-order.js +4 -3
- package/lib/public/modules/tool-palette.js +13 -3
- package/lib/public/modules/tools.js +22 -22
- package/lib/public/modules/worker-proposal.js +42 -8
- package/lib/public/modules/worker-runtime-picker.js +115 -0
- package/lib/public/modules/you-activity.js +121 -0
- package/lib/public/modules/you.js +251 -0
- package/lib/public/style.css +16 -8
- package/lib/public/vendor/codemirror/LICENSE +21 -0
- package/lib/public/vendor/codemirror/codemirror.css +344 -0
- package/lib/public/vendor/codemirror/codemirror.js +9884 -0
- package/lib/public/vendor/codemirror/continuelist.js +101 -0
- package/lib/public/vendor/codemirror/markdown.js +886 -0
- package/lib/public/vendor/codemirror/show-hint.css +37 -0
- package/lib/public/vendor/codemirror/show-hint.js +523 -0
- package/lib/sdk-bridge.js +15 -3
- package/lib/server-admin.js +11 -0
- package/lib/server-home-chat-events.js +1 -1
- package/lib/server-home-chat.js +25 -3
- package/lib/server-home-debate-planning.js +4 -1
- package/lib/server-home-debates.js +2 -0
- package/lib/server-home-mate-creation.js +4 -1
- package/lib/server-mate-instructions.js +44 -0
- package/lib/server-mates.js +12 -3
- package/lib/server-palette.js +1 -1
- package/lib/server-settings.js +65 -1
- package/lib/server-user-knowledge.js +119 -0
- package/lib/server.js +21 -1
- package/lib/session-visibility.js +7 -2
- package/lib/sessions.js +32 -6
- package/lib/user-knowledge-service.js +167 -0
- package/lib/users-permissions.js +7 -0
- package/lib/users-project-mate-filter-preferences.js +39 -0
- package/lib/users.js +6 -0
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +50 -0
- package/package.json +10 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// Adapt project events to the shared Home debate presentation.
|
|
2
|
+
import { store } from './store.js';
|
|
3
|
+
import { getWs } from './ws-ref.js';
|
|
4
|
+
import { getMessagesEl } from './dom-refs.js';
|
|
5
|
+
import { addToMessages, scrollToBottom } from './chat-render-runtime.js';
|
|
6
|
+
import { isMateWorkspace } from './project-mate-navigation.js';
|
|
7
|
+
import { applyHomeDebateEvent, createHomeDebateLiveCard } from './home-debate-live.js';
|
|
8
|
+
import { createHomeDebateProposalCard, applyHomeDebateProposal, resolveHomeDebateProposal } from './home-debate-planning.js';
|
|
9
|
+
import { createDebateControls } from './debate-controls.js';
|
|
10
|
+
import { renderAssistantBubbleText, finalizeAssistantBubble, disposeChatBubbleTree } from './chat-bubble-renderer.js';
|
|
11
|
+
|
|
12
|
+
var transcriptEl = null;
|
|
13
|
+
var prependEl = null;
|
|
14
|
+
var controls = createDebateControls({
|
|
15
|
+
slotId: 'project-debate-controls',
|
|
16
|
+
composerId: 'input-area',
|
|
17
|
+
send: function (action, data, sessionId) {
|
|
18
|
+
var ws = getWs();
|
|
19
|
+
if (!ws || ws.readyState !== 1 || String(store.get('activeSessionId')) !== sessionId) return false;
|
|
20
|
+
ws.send(JSON.stringify({ type: 'project_debate_control', sessionId: store.get('activeSessionId'), action: action, text: data.text || '', response: data.response || null }));
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
function stateKey() {
|
|
26
|
+
return store.get('projectDebatePrepending') ? 'projectDebatePrependMessages' : 'projectDebateMessages';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ensureTranscript() {
|
|
30
|
+
var prepending = store.get('projectDebatePrepending');
|
|
31
|
+
var root = prepending ? prependEl : transcriptEl;
|
|
32
|
+
if (!root || !root.isConnected) {
|
|
33
|
+
root = document.createElement('section');
|
|
34
|
+
root.className = 'project-debate-transcript home-mate-chat-transcript home-chat-bubble-layout';
|
|
35
|
+
root.setAttribute('aria-label', 'Debate transcript');
|
|
36
|
+
addToMessages(root);
|
|
37
|
+
if (prepending) prependEl = root;
|
|
38
|
+
else transcriptEl = root;
|
|
39
|
+
}
|
|
40
|
+
return root;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function renderControls() {
|
|
44
|
+
var slot = document.getElementById('project-debate-controls');
|
|
45
|
+
var composer = document.getElementById('input-area');
|
|
46
|
+
if (!slot && composer) {
|
|
47
|
+
slot = document.createElement('div');
|
|
48
|
+
slot.id = 'project-debate-controls';
|
|
49
|
+
slot.className = 'home-debate-controls-slot project-debate-controls';
|
|
50
|
+
slot.hidden = true;
|
|
51
|
+
composer.parentNode.insertBefore(slot, composer);
|
|
52
|
+
}
|
|
53
|
+
controls.render(store.get('projectDebateMessages') || [], String(store.get('activeSessionId') || ''));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function respondToProposal(message, action, opener, answers, modelOverrides) {
|
|
57
|
+
var ws = getWs();
|
|
58
|
+
if (!ws || ws.readyState !== 1 || message.status === 'submitting') return;
|
|
59
|
+
ws.send(JSON.stringify({ type: 'debate_proposal_response', proposalId: message.proposal.proposalId, sessionId: store.get('activeSessionId'), action: action, modelOverrides: modelOverrides || [] }));
|
|
60
|
+
var messages = (store.get('projectDebateMessages') || []).map(function (item) {
|
|
61
|
+
return item === message ? Object.assign({}, item, { status: 'submitting' }) : item;
|
|
62
|
+
});
|
|
63
|
+
store.set({ projectDebateMessages: messages });
|
|
64
|
+
renderMessages(messages);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function renderMessages(messages) {
|
|
68
|
+
var root = ensureTranscript();
|
|
69
|
+
messages.forEach(function (message, index) {
|
|
70
|
+
var existing = root.children[index];
|
|
71
|
+
if (existing && existing._debateMessage === message) return;
|
|
72
|
+
if (existing && message.role === 'debate_turn' && existing.classList.contains('home-debate-live-turn')) {
|
|
73
|
+
var activity = existing.querySelector('.home-debate-live-activity');
|
|
74
|
+
if (message.status === 'done') {
|
|
75
|
+
if (activity) activity.remove();
|
|
76
|
+
finalizeAssistantBubble(existing, message.text || '', !store.get('replayingHistory'));
|
|
77
|
+
} else {
|
|
78
|
+
if (activity) {
|
|
79
|
+
var label = message.activity || (message.text ? 'Speaking' : 'Preparing');
|
|
80
|
+
activity.firstChild.textContent = label;
|
|
81
|
+
activity.setAttribute('aria-label', (message.mateName || 'Mate') + ' is ' + label.toLowerCase());
|
|
82
|
+
}
|
|
83
|
+
renderAssistantBubbleText(existing, message.text || '', false);
|
|
84
|
+
}
|
|
85
|
+
existing._debateMessage = message;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
var card = message.role === 'proposal'
|
|
89
|
+
? createHomeDebateProposalCard(message, respondToProposal)
|
|
90
|
+
: createHomeDebateLiveCard(message, message.status === 'done');
|
|
91
|
+
card._debateMessage = message;
|
|
92
|
+
if (existing) { disposeChatBubbleTree(existing); existing.replaceWith(card); }
|
|
93
|
+
else root.appendChild(card);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function resetProjectDebateWorkspace() {
|
|
98
|
+
store.set({ projectDebateMessages: [], projectDebatePrependMessages: [], projectDebatePrepending: false });
|
|
99
|
+
transcriptEl = null;
|
|
100
|
+
prependEl = null;
|
|
101
|
+
controls.render([], null);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function beginProjectDebatePrepend() {
|
|
105
|
+
prependEl = null;
|
|
106
|
+
store.set({ projectDebatePrepending: true, projectDebatePrependMessages: [] });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function endProjectDebatePrepend() {
|
|
110
|
+
prependEl = null;
|
|
111
|
+
store.set({ projectDebatePrepending: false, projectDebatePrependMessages: [] });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function handleProjectDebateMessage(msg) {
|
|
115
|
+
if (!isMateWorkspace(store.snap())) return false;
|
|
116
|
+
if (msg.type === 'project_debate_control_result') {
|
|
117
|
+
if (String(msg.sessionId) !== String(store.get('activeSessionId'))) return true;
|
|
118
|
+
if (!msg.ok) {
|
|
119
|
+
controls.render([], null);
|
|
120
|
+
renderControls();
|
|
121
|
+
var slot = document.getElementById('project-debate-controls');
|
|
122
|
+
var error = document.createElement('p');
|
|
123
|
+
error.className = 'project-debate-error';
|
|
124
|
+
error.setAttribute('role', 'alert');
|
|
125
|
+
error.textContent = msg.error || 'The debate action could not be completed.';
|
|
126
|
+
if (slot) slot.appendChild(error);
|
|
127
|
+
}
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
if (msg.type === 'history_done') {
|
|
131
|
+
renderControls();
|
|
132
|
+
var ws = getWs();
|
|
133
|
+
if (ws && ws.readyState === 1 && (store.get('projectDebateMessages') || []).length) {
|
|
134
|
+
ws.send(JSON.stringify({ type: 'project_debate_state', sessionId: store.get('activeSessionId') }));
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (msg.type === 'project_debate_state') {
|
|
139
|
+
if (String(msg.sessionId) !== String(store.get('activeSessionId')) || !msg.header) return true;
|
|
140
|
+
var restored = (store.get('projectDebateMessages') || []).slice();
|
|
141
|
+
var headerIndex = -1;
|
|
142
|
+
restored.forEach(function (item, index) { if (item.role === 'debate_header') headerIndex = index; });
|
|
143
|
+
if (headerIndex === -1) restored.unshift(msg.header);
|
|
144
|
+
else restored[headerIndex] = msg.header;
|
|
145
|
+
if (msg.header.phase !== 'live') restored = restored.map(function (item) {
|
|
146
|
+
return item.role === 'debate_turn' && item.status === 'active' ? Object.assign({}, item, { status: 'done', activity: '' }) : item;
|
|
147
|
+
});
|
|
148
|
+
store.set({ projectDebateMessages: restored });
|
|
149
|
+
renderMessages(restored);
|
|
150
|
+
renderControls();
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
if (msg.type === 'debate_preparing') {
|
|
154
|
+
var root = ensureTranscript();
|
|
155
|
+
var preparation = document.createElement('p');
|
|
156
|
+
preparation.className = 'debate-preparing-indicator home-debate-live-status';
|
|
157
|
+
preparation.setAttribute('role', 'status');
|
|
158
|
+
preparation.textContent = (msg.moderatorName || 'The moderator') + ' is preparing the debate…';
|
|
159
|
+
root.appendChild(preparation);
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (msg.type === 'tool_executing' && msg.name && msg.name.indexOf('propose_debate') !== -1) return true;
|
|
163
|
+
var types = ['debate_started', 'debate_turn', 'debate_activity', 'debate_stream', 'debate_turn_done', 'debate_tool_decision', 'debate_stop_requested', 'debate_stop_cancelled', 'debate_hand_raised', 'debate_conclude_confirm', 'debate_user_floor', 'debate_user_floor_done', 'debate_comment_injected', 'debate_user_resume', 'debate_resumed', 'debate_ended', 'debate_proposal', 'debate_proposal_resolved'];
|
|
164
|
+
if (types.indexOf(msg.type) === -1) return false;
|
|
165
|
+
var key = stateKey();
|
|
166
|
+
var messages = store.get(key) || [];
|
|
167
|
+
if (msg.type === 'debate_tool_decision') messages = messages.map(function (item) {
|
|
168
|
+
return item.role === 'debate_tool_decision' ? Object.assign({}, item, { entries: (item.entries || []).slice() }) : item;
|
|
169
|
+
});
|
|
170
|
+
if (msg.type === 'debate_proposal') messages = applyHomeDebateProposal(messages, msg);
|
|
171
|
+
else if (msg.type === 'debate_proposal_resolved') messages = resolveHomeDebateProposal(messages, msg);
|
|
172
|
+
else messages = applyHomeDebateEvent(messages, Object.assign({}, msg, { eventType: msg.type, speakerMateId: msg.mateId }));
|
|
173
|
+
if (msg.type === 'debate_ended') messages = messages.map(function (item) {
|
|
174
|
+
return item.role === 'debate_turn' && item.status === 'active' ? Object.assign({}, item, { status: 'done', activity: '' }) : item;
|
|
175
|
+
});
|
|
176
|
+
var patch = {};
|
|
177
|
+
patch[key] = messages;
|
|
178
|
+
store.set(patch);
|
|
179
|
+
var preparation = getMessagesEl().querySelector('.debate-preparing-indicator');
|
|
180
|
+
if (preparation) preparation.remove();
|
|
181
|
+
renderMessages(messages);
|
|
182
|
+
if (!store.get('projectDebatePrepending') && !store.get('replayingHistory')) renderControls();
|
|
183
|
+
scrollToBottom();
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Single renderer for ordinary-project and Mate identities in the sidebar header.
|
|
2
|
+
|
|
3
|
+
import { mateAvatarUrl } from './avatar.js';
|
|
4
|
+
import { VENDOR_AVATARS, VENDOR_NAMES } from './chat-render-runtime.js';
|
|
5
|
+
import { getHomeMateBio } from './home-mate-selection.js';
|
|
6
|
+
import { parseEmojis } from './markdown.js';
|
|
7
|
+
import { refreshIcons } from './icons.js';
|
|
8
|
+
|
|
9
|
+
function projectForState(state) {
|
|
10
|
+
var projects = state.projectsHubList || [];
|
|
11
|
+
for (var i = 0; i < projects.length; i++) {
|
|
12
|
+
if (projects[i] && projects[i].slug === state.currentSlug) return projects[i];
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function mateName(mate) {
|
|
18
|
+
var profile = mate && mate.profile ? mate.profile : {};
|
|
19
|
+
return profile.displayName || (mate && (mate.displayName || mate.name)) || 'Mate';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isMateHeaderWorkspace(state) {
|
|
23
|
+
var projects = state.projectsHubList || [];
|
|
24
|
+
for (var i = 0; i < projects.length; i++) {
|
|
25
|
+
if (projects[i] && projects[i].slug === state.currentSlug && projects[i].isMate === true) return true;
|
|
26
|
+
}
|
|
27
|
+
var mates = state.cachedMatesList || [];
|
|
28
|
+
for (var j = 0; j < mates.length; j++) {
|
|
29
|
+
if (mates[j] && state.currentSlug === 'mate-' + mates[j].id) return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function clearMateIdentity(icon, dropdown) {
|
|
35
|
+
icon.classList.remove('is-mate-avatar');
|
|
36
|
+
icon.classList.remove('is-clay-identity');
|
|
37
|
+
icon.removeAttribute('data-vendor');
|
|
38
|
+
delete dropdown.dataset.mateDefaults;
|
|
39
|
+
delete dropdown.dataset.mateBio;
|
|
40
|
+
delete dropdown.dataset.clayIdentity;
|
|
41
|
+
dropdown.removeAttribute('aria-label');
|
|
42
|
+
dropdown.removeAttribute('title');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function renderOrdinaryProjectHeader(state) {
|
|
46
|
+
var dropdown = document.getElementById('title-bar-project-dropdown');
|
|
47
|
+
var icon = document.getElementById('title-bar-project-icon');
|
|
48
|
+
var name = document.getElementById('title-bar-project-name');
|
|
49
|
+
var detail = document.getElementById('title-bar-project-default');
|
|
50
|
+
if (!dropdown || !icon || !name || !detail) return false;
|
|
51
|
+
var project = projectForState(state);
|
|
52
|
+
clearMateIdentity(icon, dropdown);
|
|
53
|
+
detail.textContent = '';
|
|
54
|
+
icon.textContent = '';
|
|
55
|
+
var projectIcon = project && project.icon ? project.icon : '';
|
|
56
|
+
if (projectIcon) {
|
|
57
|
+
icon.textContent = projectIcon;
|
|
58
|
+
icon.classList.add('has-icon');
|
|
59
|
+
parseEmojis(icon);
|
|
60
|
+
} else {
|
|
61
|
+
icon.classList.remove('has-icon');
|
|
62
|
+
}
|
|
63
|
+
if (project) name.textContent = project.title || project.project || project.name || state.projectName || '';
|
|
64
|
+
return !!project;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function renderMateProjectHeader(state, mate) {
|
|
68
|
+
var dropdown = document.getElementById('title-bar-project-dropdown');
|
|
69
|
+
var icon = document.getElementById('title-bar-project-icon');
|
|
70
|
+
var name = document.getElementById('title-bar-project-name');
|
|
71
|
+
var detail = document.getElementById('title-bar-project-default');
|
|
72
|
+
if (!dropdown || !icon || !name || !detail || !mate || state.homeShellVisible) return false;
|
|
73
|
+
var displayName = mateName(mate);
|
|
74
|
+
var vendor = mate.vendor || '';
|
|
75
|
+
var vendorName = VENDOR_NAMES[vendor] || vendor || 'Default vendor';
|
|
76
|
+
var bio = getHomeMateBio(mate).replace(/\s+/g, ' ').trim();
|
|
77
|
+
var isClay = mate.builtinKey === 'clay';
|
|
78
|
+
icon.textContent = '';
|
|
79
|
+
icon.classList.add('has-icon');
|
|
80
|
+
icon.classList.toggle('is-mate-avatar', !isClay);
|
|
81
|
+
icon.classList.toggle('is-clay-identity', isClay);
|
|
82
|
+
if (vendor) icon.dataset.vendor = vendor;
|
|
83
|
+
else icon.removeAttribute('data-vendor');
|
|
84
|
+
if (!isClay) {
|
|
85
|
+
var avatar = document.createElement('img');
|
|
86
|
+
avatar.className = 'title-bar-mate-avatar';
|
|
87
|
+
avatar.src = mateAvatarUrl(mate, 56);
|
|
88
|
+
avatar.alt = '';
|
|
89
|
+
avatar.draggable = false;
|
|
90
|
+
icon.appendChild(avatar);
|
|
91
|
+
}
|
|
92
|
+
if (!isClay && vendor && VENDOR_AVATARS[vendor]) {
|
|
93
|
+
var badge = document.createElement('img');
|
|
94
|
+
badge.className = 'title-bar-mate-vendor';
|
|
95
|
+
badge.src = VENDOR_AVATARS[vendor];
|
|
96
|
+
badge.alt = '';
|
|
97
|
+
badge.draggable = false;
|
|
98
|
+
badge.title = vendorName;
|
|
99
|
+
icon.appendChild(badge);
|
|
100
|
+
}
|
|
101
|
+
name.textContent = displayName;
|
|
102
|
+
detail.textContent = bio;
|
|
103
|
+
if (isClay) {
|
|
104
|
+
detail.textContent = '';
|
|
105
|
+
var badge = document.createElement('span');
|
|
106
|
+
badge.className = 'clay-role-badge';
|
|
107
|
+
var insignia = document.createElement('i');
|
|
108
|
+
insignia.className = 'clay-role-insignia';
|
|
109
|
+
insignia.setAttribute('data-lucide', 'crown');
|
|
110
|
+
insignia.setAttribute('aria-hidden', 'true');
|
|
111
|
+
var label = document.createElement('span');
|
|
112
|
+
label.className = 'clay-role-label';
|
|
113
|
+
label.textContent = 'Lead Mate';
|
|
114
|
+
badge.appendChild(insignia);
|
|
115
|
+
badge.appendChild(label);
|
|
116
|
+
detail.appendChild(badge);
|
|
117
|
+
refreshIcons();
|
|
118
|
+
}
|
|
119
|
+
dropdown.dataset.mateDefaults = 'true';
|
|
120
|
+
delete dropdown.dataset.clayIdentity;
|
|
121
|
+
delete dropdown.dataset.mateBio;
|
|
122
|
+
if (isClay) dropdown.dataset.clayIdentity = 'true';
|
|
123
|
+
else if (bio) dropdown.dataset.mateBio = 'true';
|
|
124
|
+
dropdown.setAttribute('aria-label', 'Open Mate settings for ' + displayName);
|
|
125
|
+
dropdown.title = 'Open Mate settings';
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
@@ -206,7 +206,7 @@ export function renderList(listEl, entries, onOpen, emptyState) {
|
|
|
206
206
|
|
|
207
207
|
// --- Detail --------------------------------------------------------------
|
|
208
208
|
|
|
209
|
-
function renderComments(entry) {
|
|
209
|
+
function renderComments(entry, handlers) {
|
|
210
210
|
var wrap = document.createElement("section");
|
|
211
211
|
wrap.className = "project-log-discussion";
|
|
212
212
|
var heading = document.createElement("h2");
|
|
@@ -242,6 +242,7 @@ function renderComments(entry) {
|
|
|
242
242
|
badge.className = "project-log-comment-status-badge";
|
|
243
243
|
badge.dataset.status = status;
|
|
244
244
|
badge.textContent = COMMENT_STATUS_LABELS[status] || status;
|
|
245
|
+
if (handlers && handlers.commentReviewer && status === "pending") badge.textContent = "Awaiting " + handlers.commentReviewer + " review";
|
|
245
246
|
item.appendChild(badge);
|
|
246
247
|
|
|
247
248
|
// The Driver's decision sits under the comment it answers.
|
|
@@ -251,6 +252,7 @@ function renderComments(entry) {
|
|
|
251
252
|
var responseMeta = document.createElement("p");
|
|
252
253
|
responseMeta.className = "project-log-comment-response-meta";
|
|
253
254
|
var parts = ["Project Driver"];
|
|
255
|
+
if (handlers && handlers.commentReviewer) parts[0] = handlers.commentReviewer;
|
|
254
256
|
if (comment.review.at) parts.push(relativeTime(comment.review.at));
|
|
255
257
|
if (comment.review.revision) parts.push("revision " + comment.review.revision);
|
|
256
258
|
responseMeta.textContent = parts.join(" · ");
|
|
@@ -391,19 +393,22 @@ export function renderDetail(detailEl, entry, handlers) {
|
|
|
391
393
|
|
|
392
394
|
var history = renderHistory(entry);
|
|
393
395
|
if (history) article.appendChild(history);
|
|
394
|
-
|
|
396
|
+
if (handlers && handlers.readOnly) { detailEl.appendChild(article); refreshIcons(); return; }
|
|
397
|
+
article.appendChild(renderComments(entry, handlers));
|
|
395
398
|
|
|
396
399
|
var form = document.createElement("form");
|
|
397
400
|
form.className = "project-log-comment-form";
|
|
401
|
+
var commentPrefix = handlers.commentPrefix || "project-log";
|
|
398
402
|
form.innerHTML =
|
|
399
403
|
'<label for="project-log-comment-input">Add a comment</label>' +
|
|
400
404
|
'<textarea id="project-log-comment-input" rows="3" required placeholder="Add context, a correction, or a question."></textarea>' +
|
|
401
405
|
'<p id="project-log-comment-status" class="project-log-comment-status" role="status"></p>' +
|
|
402
406
|
'<div class="project-log-comment-actions"><button class="primary" type="submit">Comment</button></div>';
|
|
407
|
+
form.innerHTML = form.innerHTML.replaceAll("project-log-comment-input", commentPrefix + "-comment-input").replaceAll('id="project-log-comment-status"', 'id="' + commentPrefix + '-comment-status"');
|
|
403
408
|
form.addEventListener("submit", function (event) {
|
|
404
409
|
event.preventDefault();
|
|
405
|
-
var input = form.querySelector("
|
|
406
|
-
var status = form.querySelector("
|
|
410
|
+
var input = form.querySelector("textarea");
|
|
411
|
+
var status = form.querySelector(".project-log-comment-status");
|
|
407
412
|
var value = input.value.trim();
|
|
408
413
|
if (!value) { status.textContent = "A comment cannot be empty."; return; }
|
|
409
414
|
handlers.onComment(entry.ref, value, status, input);
|