clay-server 5.1.0-beta.1 → 5.1.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/LICENSES/README.md +4 -0
  2. package/LICENSES/dicebear-avatars.md +16 -0
  3. package/bin/cli.js +9 -91
  4. package/lib/builtin-mates.js +7 -7
  5. package/lib/daemon-project-access.js +7 -1
  6. package/lib/daemon-settings.js +11 -0
  7. package/lib/daemon.js +10 -37
  8. package/lib/dicebear-avatar.js +62 -0
  9. package/lib/knowledge-db-service.js +175 -0
  10. package/lib/knowledge-db-validation.js +0 -0
  11. package/lib/knowledge-document-index.js +49 -0
  12. package/lib/knowledge-draft-store.js +56 -0
  13. package/lib/knowledge-file-store.js +199 -0
  14. package/lib/knowledge-markdown.js +128 -0
  15. package/lib/linear-store.js +35 -8
  16. package/lib/mate-identity-file.js +39 -0
  17. package/lib/mate-knowledge-mcp-server.js +29 -6
  18. package/lib/mate-knowledge-service.js +23 -2
  19. package/lib/mate-knowledge-sync.js +37 -22
  20. package/lib/mate-ready-creation.js +2 -1
  21. package/lib/mate-workspace-color.js +4 -0
  22. package/lib/mates-identity.js +4 -4
  23. package/lib/mates-prompts.js +4 -3
  24. package/lib/mates.js +30 -11
  25. package/lib/os-users.js +5 -16
  26. package/lib/project-connection.js +36 -9
  27. package/lib/project-debate-proposal.js +6 -0
  28. package/lib/project-debate-workspace.js +43 -0
  29. package/lib/project-debate.js +4 -2
  30. package/lib/project-filesystem.js +21 -39
  31. package/lib/project-knowledge.js +315 -136
  32. package/lib/project-mate-creation-proposal.js +1 -0
  33. package/lib/project-mate-interaction.js +7 -6
  34. package/lib/project-server-settings.js +31 -0
  35. package/lib/project-sessions.js +92 -182
  36. package/lib/project-user-knowledge.js +60 -0
  37. package/lib/project.js +62 -21
  38. package/lib/public/app.js +79 -71
  39. package/lib/public/clay-studio-wordmark-bold.svg +20 -0
  40. package/lib/public/css/clay-workspace.css +105 -0
  41. package/lib/public/css/debates-workbench.css +47 -0
  42. package/lib/public/css/home-debate-live.css +26 -0
  43. package/lib/public/css/home-hub.css +3 -1
  44. package/lib/public/css/home-mate-model-picker.css +15 -131
  45. package/lib/public/css/home-mate-settings.css +168 -16
  46. package/lib/public/css/icon-strip.css +249 -32
  47. package/lib/public/css/input.css +3 -1
  48. package/lib/public/css/mate-conversation.css +176 -0
  49. package/lib/public/css/mate-knowledge-workbench.css +118 -0
  50. package/lib/public/css/mate-workspace-color.css +16 -0
  51. package/lib/public/css/mates.css +28 -28
  52. package/lib/public/css/menus.css +3 -0
  53. package/lib/public/css/messages.css +1 -114
  54. package/lib/public/css/mobile-nav.css +16 -16
  55. package/lib/public/css/overlays.css +15 -0
  56. package/lib/public/css/project-logs.css +7 -0
  57. package/lib/public/css/project-mate-creation.css +105 -0
  58. package/lib/public/css/project-settings-modal.css +56 -0
  59. package/lib/public/css/right-workbench.css +3 -3
  60. package/lib/public/css/server-settings-system.css +125 -0
  61. package/lib/public/css/session-folders.css +80 -21
  62. package/lib/public/css/session-github.css +25 -16
  63. package/lib/public/css/settings-ui.css +247 -22
  64. package/lib/public/css/shared-browser.css +7 -3
  65. package/lib/public/css/sidebar.css +183 -107
  66. package/lib/public/css/title-bar.css +156 -1
  67. package/lib/public/css/worker-delegation.css +47 -0
  68. package/lib/public/css/worker-proposal.css +72 -150
  69. package/lib/public/css/you.css +74 -0
  70. package/lib/public/index.html +206 -548
  71. package/lib/public/modules/account-island.js +232 -0
  72. package/lib/public/modules/admin-settings-email.js +197 -0
  73. package/lib/public/modules/admin-settings-invitations.js +183 -0
  74. package/lib/public/modules/admin-settings-projects.js +198 -0
  75. package/lib/public/modules/admin-settings-ui.js +100 -0
  76. package/lib/public/modules/admin-settings-users.js +331 -0
  77. package/lib/public/modules/admin.js +19 -949
  78. package/lib/public/modules/app-cursors.js +19 -43
  79. package/lib/public/modules/app-debate-ui.js +4 -3
  80. package/lib/public/modules/app-dm.js +0 -2
  81. package/lib/public/modules/app-header.js +106 -0
  82. package/lib/public/modules/app-message-router.js +12 -3
  83. package/lib/public/modules/app-messages.js +47 -61
  84. package/lib/public/modules/app-notifications.js +4 -7
  85. package/lib/public/modules/app-projects.js +5 -38
  86. package/lib/public/modules/app-rate-limit.js +70 -12
  87. package/lib/public/modules/app-rendering.js +12 -13
  88. package/lib/public/modules/avatar.js +30 -9
  89. package/lib/public/modules/chat-render-runtime.js +16 -4
  90. package/lib/public/modules/command-palette.js +2 -15
  91. package/lib/public/modules/context-sources.js +27 -18
  92. package/lib/public/modules/cursor-sharing-preference.js +3 -3
  93. package/lib/public/modules/debate-controls.js +299 -0
  94. package/lib/public/modules/debate.js +2 -0
  95. package/lib/public/modules/debates-workbench.js +339 -0
  96. package/lib/public/modules/default-ai.js +88 -65
  97. package/lib/public/modules/header-tui-font.js +10 -20
  98. package/lib/public/modules/home-debate-controls.js +18 -289
  99. package/lib/public/modules/home-mate-avatar-editor.js +228 -0
  100. package/lib/public/modules/home-mate-color-picker.js +66 -0
  101. package/lib/public/modules/home-mate-creation.js +1 -1
  102. package/lib/public/modules/home-mate-instructions.js +90 -0
  103. package/lib/public/modules/home-mate-model-picker.js +80 -271
  104. package/lib/public/modules/home-mate-profile-editor.js +72 -0
  105. package/lib/public/modules/home-mate-settings.js +118 -125
  106. package/lib/public/modules/home-shell.js +3 -0
  107. package/lib/public/modules/home-surface-boot.js +1 -9
  108. package/lib/public/modules/icon-strip-tooltip.js +95 -0
  109. package/lib/public/modules/knowledge-db-edit-state.js +35 -0
  110. package/lib/public/modules/knowledge-db-workbench.js +234 -0
  111. package/lib/public/modules/knowledge-history-state.js +55 -0
  112. package/lib/public/modules/knowledge-markdown-editor.js +57 -0
  113. package/lib/public/modules/knowledge-preview-links.js +70 -0
  114. package/lib/public/modules/knowledge-workbench-shell.js +21 -0
  115. package/lib/public/modules/linear-settings.js +3 -2
  116. package/lib/public/modules/markdown.js +5 -6
  117. package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
  118. package/lib/public/modules/mate-knowledge-workbench.js +500 -0
  119. package/lib/public/modules/mate-knowledge.js +11 -3
  120. package/lib/public/modules/mate-management.js +54 -10
  121. package/lib/public/modules/mate-sidebar.js +11 -1
  122. package/lib/public/modules/mate-workspace-color.js +33 -0
  123. package/lib/public/modules/mention.js +5 -13
  124. package/lib/public/modules/notification-settings.js +81 -0
  125. package/lib/public/modules/notifications.js +44 -28
  126. package/lib/public/modules/personal-settings-dialog.js +51 -0
  127. package/lib/public/modules/profile.js +66 -24
  128. package/lib/public/modules/project-chat-identity.js +79 -0
  129. package/lib/public/modules/project-debate-planning-workspace.js +250 -0
  130. package/lib/public/modules/project-debate-workspace.js +185 -0
  131. package/lib/public/modules/project-header-identity.js +127 -0
  132. package/lib/public/modules/project-logs-render.js +9 -4
  133. package/lib/public/modules/project-mate-creation-workspace.js +414 -0
  134. package/lib/public/modules/project-mate-navigation.js +238 -0
  135. package/lib/public/modules/project-session-navigation.js +29 -0
  136. package/lib/public/modules/project-settings-environment.js +106 -0
  137. package/lib/public/modules/project-settings.js +72 -628
  138. package/lib/public/modules/project-switcher.js +6 -8
  139. package/lib/public/modules/projects-hub-view.js +5 -6
  140. package/lib/public/modules/projects-hub.js +2 -6
  141. package/lib/public/modules/qrcode.js +27 -8
  142. package/lib/public/modules/search-clay-chat.js +8 -11
  143. package/lib/public/modules/server-settings-controls.js +316 -0
  144. package/lib/public/modules/server-settings-environment.js +194 -0
  145. package/lib/public/modules/server-settings-navigation.js +39 -0
  146. package/lib/public/modules/server-settings-state.js +54 -0
  147. package/lib/public/modules/server-settings.js +116 -788
  148. package/lib/public/modules/server-storage-settings.js +84 -0
  149. package/lib/public/modules/session-activity-tooltip.js +12 -0
  150. package/lib/public/modules/session-create-form.js +86 -14
  151. package/lib/public/modules/session-create.js +50 -7
  152. package/lib/public/modules/session-github.js +2 -1
  153. package/lib/public/modules/session-list-visibility.js +41 -0
  154. package/lib/public/modules/session-presence-ui.js +3 -0
  155. package/lib/public/modules/session-title-marquee.js +51 -0
  156. package/lib/public/modules/settings-env-values.js +34 -0
  157. package/lib/public/modules/settings-select.js +121 -0
  158. package/lib/public/modules/shared-browser.js +22 -12
  159. package/lib/public/modules/sidebar-mates.js +3 -50
  160. package/lib/public/modules/sidebar-mobile.js +63 -60
  161. package/lib/public/modules/sidebar-projects.js +84 -97
  162. package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
  163. package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
  164. package/lib/public/modules/sidebar-sessions.js +49 -50
  165. package/lib/public/modules/sidebar.js +11 -13
  166. package/lib/public/modules/stt-picker.js +14 -5
  167. package/lib/public/modules/terminal-prefs.js +22 -0
  168. package/lib/public/modules/theme.js +88 -52
  169. package/lib/public/modules/thinking-lifecycle.js +7 -6
  170. package/lib/public/modules/tool-palette-order.js +4 -3
  171. package/lib/public/modules/tool-palette.js +13 -3
  172. package/lib/public/modules/tools.js +22 -22
  173. package/lib/public/modules/user-settings-account.js +318 -0
  174. package/lib/public/modules/user-settings-appearance.js +55 -0
  175. package/lib/public/modules/user-settings-editors.js +24 -0
  176. package/lib/public/modules/user-settings-integrations.js +104 -0
  177. package/lib/public/modules/user-settings-layout.js +80 -0
  178. package/lib/public/modules/user-settings-preferences.js +48 -0
  179. package/lib/public/modules/user-settings-profile.js +53 -0
  180. package/lib/public/modules/user-settings-themes.js +38 -0
  181. package/lib/public/modules/user-settings-voice.js +75 -0
  182. package/lib/public/modules/user-settings.js +53 -480
  183. package/lib/public/modules/worker-proposal.js +42 -8
  184. package/lib/public/modules/worker-runtime-picker.js +115 -0
  185. package/lib/public/modules/you-activity.js +121 -0
  186. package/lib/public/modules/you.js +251 -0
  187. package/lib/public/style.css +20 -8
  188. package/lib/public/vendor/codemirror/LICENSE +21 -0
  189. package/lib/public/vendor/codemirror/codemirror.css +344 -0
  190. package/lib/public/vendor/codemirror/codemirror.js +9884 -0
  191. package/lib/public/vendor/codemirror/continuelist.js +101 -0
  192. package/lib/public/vendor/codemirror/markdown.js +886 -0
  193. package/lib/public/vendor/codemirror/show-hint.css +37 -0
  194. package/lib/public/vendor/codemirror/show-hint.js +523 -0
  195. package/lib/sdk-bridge.js +15 -3
  196. package/lib/sdk-message-processor.js +16 -4
  197. package/lib/sdk-quota-snapshot.js +37 -0
  198. package/lib/server-admin.js +11 -0
  199. package/lib/server-appearance-settings.js +71 -0
  200. package/lib/server-home-chat-events.js +1 -1
  201. package/lib/server-home-chat.js +25 -3
  202. package/lib/server-home-debate-planning.js +4 -1
  203. package/lib/server-home-debates.js +2 -0
  204. package/lib/server-home-mate-creation.js +4 -1
  205. package/lib/server-linear.js +14 -8
  206. package/lib/server-mate-instructions.js +44 -0
  207. package/lib/server-mates.js +14 -4
  208. package/lib/server-notification-settings.js +67 -0
  209. package/lib/server-palette.js +1 -1
  210. package/lib/server-settings.js +69 -1
  211. package/lib/server-storage.js +57 -0
  212. package/lib/server-user-knowledge.js +119 -0
  213. package/lib/server.js +31 -3
  214. package/lib/session-visibility.js +7 -2
  215. package/lib/sessions.js +35 -10
  216. package/lib/startup-projects.js +40 -0
  217. package/lib/storage-native-walk.js +85 -0
  218. package/lib/storage-usage.js +144 -0
  219. package/lib/user-knowledge-service.js +167 -0
  220. package/lib/users-permissions.js +7 -0
  221. package/lib/users-preferences.js +0 -74
  222. package/lib/users-project-mate-filter-preferences.js +39 -0
  223. package/lib/users.js +6 -4
  224. package/lib/workspace-query-access.js +4 -1
  225. package/lib/ws-schema.js +52 -4
  226. package/lib/yoke/acp-process-manager.js +2 -2
  227. package/lib/yoke/adapters/codex.js +12 -52
  228. package/lib/yoke/codex-app-server.js +2 -2
  229. package/lib/yoke/codex-model-catalog.js +52 -0
  230. package/lib/yoke/codex-rate-limits.js +26 -0
  231. package/package.json +12 -3
@@ -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
- article.appendChild(renderComments(entry));
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("#project-log-comment-input");
406
- var status = form.querySelector("#project-log-comment-status");
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);
@@ -0,0 +1,414 @@
1
+ // Project-chat adapter for the existing Clay-owned Mate creation workflow.
2
+
3
+ import { store } from './store.js';
4
+ import { getWs } from './ws-ref.js';
5
+ import { iconHtml, refreshIcons } from './icons.js';
6
+ import { addToMessages, scrollToBottom } from './chat-render-runtime.js';
7
+ import { openMateWorkspace } from './project-mate-navigation.js';
8
+ import { createHomeDebateQuestionCard, normalizeHomeTranscript, failHomeDebateQuestion } from './home-debate-planning.js';
9
+ import { createHomeMateProposalCard, applyHomeMateProposal, resolveHomeMateProposal } from './home-mate-creation.js';
10
+
11
+ var choiceDialog = null;
12
+ var creationRoot = null;
13
+ var requestSequence = 0;
14
+
15
+ function send(message) {
16
+ var ws = getWs();
17
+ if (!ws || ws.readyState !== 1) return false;
18
+ ws.send(JSON.stringify(message));
19
+ return true;
20
+ }
21
+
22
+ function clayMate() {
23
+ var mates = store.get('cachedMatesList') || [];
24
+ for (var i = 0; i < mates.length; i++) if (mates[i] && mates[i].builtinKey === 'clay') return mates[i];
25
+ return null;
26
+ }
27
+
28
+ function nextRequestId() {
29
+ requestSequence++;
30
+ return 'project-mate-creation-' + Date.now() + '-' + requestSequence;
31
+ }
32
+
33
+ function closeChoice(restoreFocus) {
34
+ var opener = choiceDialog ? choiceDialog._opener : null;
35
+ if (choiceDialog) choiceDialog.remove();
36
+ choiceDialog = null;
37
+ document.removeEventListener('keydown', handleChoiceKeydown, true);
38
+ if (restoreFocus && opener && opener.isConnected) opener.focus({ preventScroll: true });
39
+ }
40
+
41
+ function handleChoiceKeydown(event) {
42
+ if (!choiceDialog) return;
43
+ if (event.key === 'Escape') {
44
+ event.preventDefault();
45
+ closeChoice(true);
46
+ return;
47
+ }
48
+ if (event.key !== 'Tab') return;
49
+ var controls = choiceDialog.querySelectorAll('button:not([disabled])');
50
+ if (!controls.length) return;
51
+ if (event.shiftKey && document.activeElement === controls[0]) {
52
+ event.preventDefault();
53
+ controls[controls.length - 1].focus();
54
+ } else if (!event.shiftKey && document.activeElement === controls[controls.length - 1]) {
55
+ event.preventDefault();
56
+ controls[0].focus();
57
+ }
58
+ }
59
+
60
+ function startMateCreation() {
61
+ var clay = clayMate();
62
+ if (!clay) {
63
+ var status = choiceDialog && choiceDialog.querySelector('[role="alert"]');
64
+ if (status) status.textContent = 'Clay is unavailable. Refresh and try again.';
65
+ return;
66
+ }
67
+ closeChoice(false);
68
+ store.set({
69
+ projectMateCreationActive: true,
70
+ projectMateCreationMateId: clay.id,
71
+ projectMateCreationSessionId: null,
72
+ projectMateCreationRequestId: null,
73
+ projectMateCreationPendingStart: true,
74
+ projectMateCreationAwaitingHistory: false,
75
+ projectMateCreationAwaitingMateList: false,
76
+ projectMateCreationHistoryReady: false,
77
+ projectMateCreationLocalId: null,
78
+ projectMateCreationMessages: [],
79
+ });
80
+ openMateWorkspace(clay.id);
81
+ maybeStartPendingCreation();
82
+ }
83
+
84
+ function maybeStartPendingCreation() {
85
+ var state = store.snap();
86
+ if (!state.projectMateCreationPendingStart || !state.connected || state.activeProjectSlug !== 'mate-' + state.projectMateCreationMateId) return;
87
+ var requestId = nextRequestId();
88
+ if (!send({ type: 'home_mate_creation_plan', mateId: state.projectMateCreationMateId, requestId: requestId })) return;
89
+ store.set({ projectMateCreationPendingStart: false, projectMateCreationAwaitingHistory: true, projectMateCreationRequestId: requestId });
90
+ }
91
+
92
+ function choiceButton(icon, title, description) {
93
+ var button = document.createElement('button');
94
+ button.type = 'button';
95
+ button.className = 'project-create-choice-option';
96
+ button.innerHTML = iconHtml(icon);
97
+ var copy = document.createElement('span');
98
+ var heading = document.createElement('strong');
99
+ heading.textContent = title;
100
+ var detail = document.createElement('small');
101
+ detail.textContent = description;
102
+ copy.appendChild(heading);
103
+ copy.appendChild(detail);
104
+ button.appendChild(copy);
105
+ return button;
106
+ }
107
+
108
+ export function openProjectCreateChoice(opener, openProject) {
109
+ closeChoice(false);
110
+ var overlay = document.createElement('div');
111
+ overlay.className = 'project-create-choice-overlay';
112
+ overlay.setAttribute('role', 'presentation');
113
+ var dialog = document.createElement('section');
114
+ dialog.className = 'project-create-choice';
115
+ dialog.setAttribute('role', 'dialog');
116
+ dialog.setAttribute('aria-modal', 'true');
117
+ dialog.setAttribute('aria-labelledby', 'project-create-choice-title');
118
+ var eyebrow = document.createElement('span');
119
+ eyebrow.className = 'project-create-choice-eyebrow';
120
+ eyebrow.textContent = 'Create new';
121
+ var title = document.createElement('h2');
122
+ title.id = 'project-create-choice-title';
123
+ title.textContent = 'What would you like to add?';
124
+ var mate = choiceButton('users', 'Mate', 'Shape a new collaborator with Clay');
125
+ mate.addEventListener('click', startMateCreation);
126
+ var project = choiceButton('folder-plus', 'Project', 'Add a local workspace');
127
+ project.addEventListener('click', function () {
128
+ closeChoice(false);
129
+ openProject();
130
+ });
131
+ var cancel = document.createElement('button');
132
+ cancel.type = 'button';
133
+ cancel.className = 'project-create-choice-cancel';
134
+ cancel.textContent = 'Cancel';
135
+ cancel.addEventListener('click', function () { closeChoice(true); });
136
+ var status = document.createElement('p');
137
+ status.className = 'project-create-choice-error';
138
+ status.setAttribute('role', 'alert');
139
+ dialog.appendChild(eyebrow);
140
+ dialog.appendChild(title);
141
+ dialog.appendChild(mate);
142
+ dialog.appendChild(project);
143
+ dialog.appendChild(status);
144
+ dialog.appendChild(cancel);
145
+ overlay.appendChild(dialog);
146
+ overlay.addEventListener('click', function (event) { if (event.target === overlay) closeChoice(true); });
147
+ overlay._opener = opener || document.activeElement;
148
+ document.body.appendChild(overlay);
149
+ choiceDialog = overlay;
150
+ document.addEventListener('keydown', handleChoiceKeydown, true);
151
+ refreshIcons();
152
+ requestAnimationFrame(function () { mate.focus({ preventScroll: true }); });
153
+ }
154
+
155
+ function context() {
156
+ return {
157
+ mateId: store.get('projectMateCreationMateId'),
158
+ sessionId: store.get('projectMateCreationSessionId'),
159
+ requestId: store.get('projectMateCreationRequestId'),
160
+ };
161
+ }
162
+
163
+ function sameValue(left, right) {
164
+ return left != null && right != null && String(left) === String(right);
165
+ }
166
+
167
+ export function isExactProjectMateCreationMessage(state, msg, allowUnboundSession) {
168
+ if (!state.projectMateCreationActive || !sameValue(msg.mateId, state.projectMateCreationMateId) || !sameValue(msg.requestId, state.projectMateCreationRequestId)) return false;
169
+ if (!state.projectMateCreationSessionId) return allowUnboundSession === true;
170
+ return sameValue(msg.sessionId, state.projectMateCreationSessionId);
171
+ }
172
+
173
+ function creationMessages() {
174
+ return store.get('projectMateCreationMessages') || [];
175
+ }
176
+
177
+ function setCreationMessages(messages) {
178
+ store.set({ projectMateCreationMessages: messages });
179
+ }
180
+
181
+ function respondToQuestion(message, action, opener, answers) {
182
+ if (!message || message.status === 'submitting') return;
183
+ var payload = Object.assign({ type: 'home_mate_creation_question_response', toolId: message.toolId, answers: answers || {} }, context());
184
+ if (!send(payload)) {
185
+ setCreationMessages(creationMessages().map(function (item) { return item === message ? Object.assign({}, item, { error: 'Clay is offline. Reconnect and try again.' }) : item; }));
186
+ renderCreationMessages();
187
+ return;
188
+ }
189
+ setCreationMessages(creationMessages().map(function (item) { return item === message ? Object.assign({}, item, { status: 'submitting' }) : item; }));
190
+ renderCreationMessages();
191
+ }
192
+
193
+ function respondToProposal(message, action) {
194
+ if (!message || message.status === 'submitting') return;
195
+ var payload = Object.assign({ type: 'home_mate_creation_proposal_response', proposalId: message.proposal.proposalId, action: action === 'create' ? 'create' : 'cancel' }, context());
196
+ if (!send(payload)) {
197
+ setCreationMessages(creationMessages().map(function (item) { return item === message ? Object.assign({}, item, { error: 'Clay is offline. Reconnect and try again.' }) : item; }));
198
+ renderCreationMessages();
199
+ return;
200
+ }
201
+ setCreationMessages(creationMessages().map(function (item) { return item === message ? Object.assign({}, item, { status: 'submitting' }) : item; }));
202
+ renderCreationMessages();
203
+ }
204
+
205
+ function ensureCreationRoot() {
206
+ if (creationRoot && creationRoot.isConnected) return creationRoot;
207
+ creationRoot = document.createElement('section');
208
+ creationRoot.className = 'project-mate-creation-transcript home-mate-chat-transcript home-chat-bubble-layout';
209
+ creationRoot.setAttribute('aria-label', 'Mate creation interview');
210
+ addToMessages(creationRoot);
211
+ return creationRoot;
212
+ }
213
+
214
+ function renderCreationMessages() {
215
+ var root = ensureCreationRoot();
216
+ root.innerHTML = '';
217
+ var intro = document.createElement('header');
218
+ intro.className = 'project-mate-creation-intro';
219
+ intro.innerHTML = iconHtml('sparkles');
220
+ var copy = document.createElement('span');
221
+ copy.textContent = 'Create a Mate with Clay';
222
+ intro.appendChild(copy);
223
+ root.appendChild(intro);
224
+ var messages = creationMessages();
225
+ for (var i = 0; i < messages.length; i++) {
226
+ var message = messages[i];
227
+ if (message.role === 'question') root.appendChild(createHomeDebateQuestionCard(message, respondToQuestion));
228
+ if (message.role === 'mate_proposal') root.appendChild(createHomeMateProposalCard(message, respondToProposal, function (created) { openMateWorkspace(created.mateId); }));
229
+ }
230
+ scrollToBottom();
231
+ refreshIcons();
232
+ }
233
+
234
+ function renderCreationError(text) {
235
+ var root = ensureCreationRoot();
236
+ var prior = root.querySelector('.project-mate-creation-error');
237
+ if (prior) prior.remove();
238
+ var error = document.createElement('div');
239
+ error.className = 'project-mate-creation-error';
240
+ error.setAttribute('role', 'alert');
241
+ var copy = document.createElement('span');
242
+ copy.textContent = text || 'The Mate interview could not continue.';
243
+ var retry = document.createElement('button');
244
+ retry.type = 'button';
245
+ retry.textContent = 'Try again';
246
+ retry.addEventListener('click', function () {
247
+ error.remove();
248
+ send(Object.assign({ type: 'home_mate_creation_plan' }, context()));
249
+ });
250
+ error.appendChild(copy);
251
+ error.appendChild(retry);
252
+ root.appendChild(error);
253
+ retry.focus({ preventScroll: true });
254
+ }
255
+
256
+ function openCreationSession(msg) {
257
+ var state = store.snap();
258
+ if (!isExactProjectMateCreationMessage(state, msg, state.projectMateCreationAwaitingHistory && !state.projectMateCreationSessionId)) return false;
259
+ store.set({
260
+ projectMateCreationSessionId: msg.sessionId,
261
+ projectMateCreationLocalId: typeof msg.localId === 'number' ? msg.localId : state.projectMateCreationLocalId,
262
+ projectMateCreationAwaitingHistory: false,
263
+ });
264
+ if (typeof msg.localId === 'number' && String(store.get('activeSessionId')) !== String(msg.localId)) {
265
+ send({ type: 'switch_session', id: msg.localId });
266
+ return true;
267
+ }
268
+ setCreationMessages(normalizeHomeTranscript(msg.messages || []).filter(function (message) {
269
+ return message.role === 'question' || message.role === 'mate_proposal';
270
+ }));
271
+ renderCreationMessages();
272
+ return true;
273
+ }
274
+
275
+ function navigateCreatedMate(mateId) {
276
+ var mates = store.get('cachedMatesList') || [];
277
+ for (var i = 0; i < mates.length; i++) if (mates[i] && mates[i].id === mateId) {
278
+ openMateWorkspace(mateId);
279
+ return;
280
+ }
281
+ store.set({ projectMateCreationPendingMateId: mateId });
282
+ }
283
+
284
+ function resumeActiveCreation() {
285
+ var state = store.snap();
286
+ if (!state.projectMateCreationActive || !state.projectMateCreationMateId || !state.projectMateCreationSessionId) return;
287
+ var requestId = nextRequestId();
288
+ if (!send({ type: 'home_mate_session_open', mateId: state.projectMateCreationMateId, sessionId: state.projectMateCreationSessionId, requestId: requestId })) return;
289
+ store.set({ projectMateCreationRequestId: requestId, projectMateCreationAwaitingHistory: true });
290
+ }
291
+
292
+ function clearCreationBinding() {
293
+ creationRoot = null;
294
+ store.set({
295
+ projectMateCreationActive: false,
296
+ projectMateCreationMateId: null,
297
+ projectMateCreationSessionId: null,
298
+ projectMateCreationRequestId: null,
299
+ projectMateCreationPendingStart: false,
300
+ projectMateCreationAwaitingHistory: false,
301
+ projectMateCreationAwaitingMateList: false,
302
+ projectMateCreationHistoryReady: false,
303
+ projectMateCreationLocalId: null,
304
+ projectMateCreationMessages: [],
305
+ });
306
+ }
307
+
308
+ function activateRestoredCreation(msg, clay) {
309
+ creationRoot = null;
310
+ store.set({
311
+ projectMateCreationActive: true,
312
+ projectMateCreationMateId: clay.id,
313
+ projectMateCreationSessionId: msg.cliSessionId || 'local:' + msg.id,
314
+ projectMateCreationRequestId: nextRequestId(),
315
+ projectMateCreationAwaitingHistory: false,
316
+ projectMateCreationAwaitingMateList: false,
317
+ projectMateCreationHistoryReady: false,
318
+ projectMateCreationLocalId: msg.id,
319
+ projectMateCreationMessages: [],
320
+ });
321
+ }
322
+
323
+ function restoreAfterMateList() {
324
+ var state = store.snap();
325
+ if (!state.projectMateCreationAwaitingMateList) return;
326
+ var clay = clayMate();
327
+ if (!clay || state.currentSlug !== 'mate-' + clay.id || state.projectMateCreationLocalId == null) return;
328
+ var historyReady = state.projectMateCreationHistoryReady;
329
+ activateRestoredCreation({ id: state.projectMateCreationLocalId, cliSessionId: state.projectMateCreationSessionId && state.projectMateCreationSessionId.indexOf('local:') !== 0 ? state.projectMateCreationSessionId : null }, clay);
330
+ if (historyReady) resumeActiveCreation();
331
+ }
332
+
333
+ export function handleProjectMateCreationMessage(msg) {
334
+ if (msg.type === 'session_switched') {
335
+ var clay = clayMate();
336
+ var state = store.snap();
337
+ var startingHere = msg.mateCreation === true && state.projectMateCreationActive && state.projectMateCreationAwaitingHistory && !state.projectMateCreationSessionId && state.currentSlug === 'mate-' + state.projectMateCreationMateId;
338
+ if (startingHere) {
339
+ creationRoot = null;
340
+ store.set({ projectMateCreationSessionId: msg.cliSessionId || 'local:' + msg.id, projectMateCreationLocalId: msg.id, projectMateCreationMessages: [] });
341
+ } else if (msg.mateCreation === true && clay && state.currentSlug === 'mate-' + clay.id) activateRestoredCreation(msg, clay);
342
+ else if (msg.mateCreation === true && !clay && /^mate-/.test(state.currentSlug || '')) {
343
+ creationRoot = null;
344
+ store.set({ projectMateCreationActive: false, projectMateCreationAwaitingMateList: true, projectMateCreationHistoryReady: false, projectMateCreationLocalId: msg.id, projectMateCreationSessionId: msg.cliSessionId || 'local:' + msg.id, projectMateCreationMessages: [] });
345
+ } else if (!(state.projectMateCreationActive && (state.projectMateCreationPendingStart || state.projectMateCreationAwaitingHistory) && state.currentSlug === 'mate-' + state.projectMateCreationMateId && !state.projectMateCreationSessionId)) clearCreationBinding();
346
+ return false;
347
+ }
348
+ if (msg.type === 'history_done') {
349
+ if (store.get('projectMateCreationAwaitingMateList')) store.set({ projectMateCreationHistoryReady: true });
350
+ else if (!store.get('projectMateCreationAwaitingHistory')) resumeActiveCreation();
351
+ return false;
352
+ }
353
+ var rawCreationEvent = (msg.type === 'tool_executing' && msg.name === 'AskUserQuestion') || msg.type === 'mate_creation_proposal' || msg.type === 'mate_creation_proposal_resolved' || msg.type === 'ask_user_answered' || msg.type === 'delta';
354
+ if (rawCreationEvent && store.get('projectMateCreationAwaitingMateList')) return sameValue(store.get('activeSessionId'), store.get('projectMateCreationLocalId'));
355
+ if (!store.get('projectMateCreationActive')) return false;
356
+ if (msg.type === 'home_mate_history' && msg.mateCreation === true) {
357
+ return openCreationSession(msg);
358
+ }
359
+ if (msg.type === 'home_mate_session_identity') {
360
+ var identityState = store.snap();
361
+ if (!isExactProjectMateCreationMessage(identityState, Object.assign({}, msg, { sessionId: msg.previousSessionId }), false)) return false;
362
+ store.set({ projectMateCreationSessionId: msg.sessionId });
363
+ return true;
364
+ }
365
+ if (rawCreationEvent) return sameValue(store.get('activeSessionId'), store.get('projectMateCreationLocalId'));
366
+ if (!isExactProjectMateCreationMessage(store.snap(), msg, msg.type === 'home_mate_error' && store.get('projectMateCreationAwaitingHistory'))) return false;
367
+ if (msg.type === 'home_mate_creation_question') {
368
+ var questions = creationMessages().slice();
369
+ questions.push({ role: 'question', flow: 'mate_creation', toolId: msg.toolId, questions: msg.questions || [], status: 'pending', error: '' });
370
+ setCreationMessages(questions);
371
+ renderCreationMessages();
372
+ return true;
373
+ }
374
+ if (msg.type === 'home_mate_creation_question_resolved') {
375
+ setCreationMessages(creationMessages().map(function (item) { return item.role === 'question' && item.toolId === msg.toolId ? Object.assign({}, item, { status: msg.status === 'answered' ? 'answered' : 'expired', answers: msg.answers || null, error: msg.error || '' }) : item; }));
376
+ renderCreationMessages();
377
+ return true;
378
+ }
379
+ if (msg.type === 'home_mate_creation_proposal') {
380
+ setCreationMessages(applyHomeMateProposal(creationMessages(), msg));
381
+ renderCreationMessages();
382
+ return true;
383
+ }
384
+ if (msg.type === 'home_mate_creation_proposal_resolved') {
385
+ setCreationMessages(resolveHomeMateProposal(creationMessages(), msg));
386
+ renderCreationMessages();
387
+ if (msg.action === 'create' && msg.createdMateId) navigateCreatedMate(msg.createdMateId);
388
+ return true;
389
+ }
390
+ if (msg.type === 'home_mate_error') {
391
+ if (/^question_/.test(msg.code || '')) {
392
+ setCreationMessages(failHomeDebateQuestion(creationMessages(), msg));
393
+ renderCreationMessages();
394
+ } else renderCreationError(msg.text);
395
+ return true;
396
+ }
397
+ return false;
398
+ }
399
+
400
+ export function initProjectMateCreationWorkspace() {
401
+ store.subscribe(function (state, previous) {
402
+ if (state.projectMateCreationPendingStart !== previous.projectMateCreationPendingStart || state.connected !== previous.connected || state.activeProjectSlug !== previous.activeProjectSlug) maybeStartPendingCreation();
403
+ if (state.cachedMatesList !== previous.cachedMatesList) restoreAfterMateList();
404
+ if (state.projectMateCreationPendingMateId && state.cachedMatesList !== previous.cachedMatesList) {
405
+ var pending = state.projectMateCreationPendingMateId;
406
+ var mates = state.cachedMatesList || [];
407
+ for (var i = 0; i < mates.length; i++) if (mates[i] && mates[i].id === pending) {
408
+ store.set({ projectMateCreationPendingMateId: null });
409
+ openMateWorkspace(pending);
410
+ break;
411
+ }
412
+ }
413
+ });
414
+ }