clay-server 3.8.1 → 4.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ask-user-mcp-server.js +5 -119
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +1 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/mate-creation-mcp-server.js +55 -0
- package/lib/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +4 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +1 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-memory.js +14 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +397 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +349 -102
- package/lib/public/app.js +85 -42
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +93 -74
- package/lib/public/modules/app-connection.js +10 -1
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +102 -37
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +158 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +7 -64
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +7 -6
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +13 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +10 -6
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +111 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +18 -3
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +93 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +73 -43
- package/lib/yoke/adapters/codex.js +40 -10
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +3 -2
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// Concrete Mate model resolution and Home model-selection protocol.
|
|
2
|
+
|
|
3
|
+
var modelEntryMatches = require("./project-models").modelEntryMatches;
|
|
4
|
+
var modelEntryValue = require("./project-models").modelEntryValue;
|
|
5
|
+
|
|
6
|
+
function attachHomeModels(deps) {
|
|
7
|
+
var users = deps.users;
|
|
8
|
+
var mates = deps.mates;
|
|
9
|
+
var projects = deps.projects;
|
|
10
|
+
var sendMessage = deps.sendMessage;
|
|
11
|
+
|
|
12
|
+
function modelError(text) {
|
|
13
|
+
var error = new Error(text);
|
|
14
|
+
error.code = "model_unavailable";
|
|
15
|
+
return error;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function broadcastMateUpdated(userId, mate) {
|
|
19
|
+
projects.forEach(function (project) {
|
|
20
|
+
project.forEachClient(function (client) {
|
|
21
|
+
if (client.readyState !== 1) return;
|
|
22
|
+
if (users.isMultiUser()) {
|
|
23
|
+
var clientUserId = client._clayUser ? client._clayUser.id : null;
|
|
24
|
+
if (!userId || clientUserId !== userId) return;
|
|
25
|
+
}
|
|
26
|
+
sendMessage(client, { type: "mate_updated", mate: mate });
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function catalogModel(models, candidate) {
|
|
32
|
+
if (!candidate) return "";
|
|
33
|
+
for (var i = 0; i < models.length; i++) {
|
|
34
|
+
if (modelEntryMatches(models[i], candidate)) return modelEntryValue(models[i]);
|
|
35
|
+
}
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function vendorChoices(found) {
|
|
40
|
+
var currentVendor = found.mate.vendor || "claude";
|
|
41
|
+
if (typeof found.ctx.getVendorModelAvailability !== "function") {
|
|
42
|
+
return [{ id: currentVendor, displayName: currentVendor, installed: false }];
|
|
43
|
+
}
|
|
44
|
+
return found.ctx.getVendorModelAvailability();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function vendorIsAvailable(choices, vendor) {
|
|
48
|
+
for (var i = 0; i < choices.length; i++) {
|
|
49
|
+
if (choices[i] && choices[i].id === vendor) return true;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function sessionReference(session) {
|
|
55
|
+
if (!session) return null;
|
|
56
|
+
return session.cliSessionId || (session.localId != null ? "local:" + session.localId : null);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function ownsSession(session, userId) {
|
|
60
|
+
if (!session) return false;
|
|
61
|
+
if (!users.isMultiUser()) return true;
|
|
62
|
+
return !!userId && session.ownerId === userId;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resolveRequestedSession(found, userId, reference) {
|
|
66
|
+
if (!reference || !found.ctx || typeof found.ctx.getSessionManager !== "function") return null;
|
|
67
|
+
var manager = found.ctx.getSessionManager();
|
|
68
|
+
if (!manager || !manager.sessions) return null;
|
|
69
|
+
var localMatch = /^local:(\d+)$/.exec(reference);
|
|
70
|
+
if (localMatch) {
|
|
71
|
+
var localSession = manager.sessions.get(parseInt(localMatch[1], 10));
|
|
72
|
+
return ownsSession(localSession, userId) ? localSession : null;
|
|
73
|
+
}
|
|
74
|
+
var foundSession = null;
|
|
75
|
+
manager.sessions.forEach(function (session) {
|
|
76
|
+
if (!foundSession && session && session.cliSessionId === reference && ownsSession(session, userId)) foundSession = session;
|
|
77
|
+
});
|
|
78
|
+
return foundSession;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isPristineSession(session) {
|
|
82
|
+
if (!session || session.isProcessing || session._queryStarting || session.queryInstance || session.worker) return false;
|
|
83
|
+
if (session.pendingPush && session.pendingPush.length) return false;
|
|
84
|
+
return Array.isArray(session.history) && session.history.length === 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function applyModelToPristineSession(found, userId, reference, vendor, model) {
|
|
88
|
+
if (!reference) return {};
|
|
89
|
+
var result = { requestedSessionId: reference, sessionId: null, sessionApplied: false };
|
|
90
|
+
var session = resolveRequestedSession(found, userId, reference);
|
|
91
|
+
if (!session) {
|
|
92
|
+
result.sessionReason = "The selected conversation is no longer available.";
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
result.sessionId = sessionReference(session);
|
|
96
|
+
if (!isPristineSession(session)) {
|
|
97
|
+
result.sessionReason = "This conversation already has activity and keeps its committed model.";
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
var manager = found.ctx.getSessionManager();
|
|
101
|
+
if (!manager || typeof manager.saveSessionFile !== "function") {
|
|
102
|
+
result.sessionReason = "The conversation model could not be persisted.";
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
var previousVendor = session.vendor;
|
|
106
|
+
var previousModel = session.model;
|
|
107
|
+
session.vendor = vendor;
|
|
108
|
+
session.model = model;
|
|
109
|
+
try {
|
|
110
|
+
manager.saveSessionFile(session);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
session.vendor = previousVendor;
|
|
113
|
+
session.model = previousModel;
|
|
114
|
+
result.sessionReason = "The conversation model could not be persisted.";
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
result.sessionApplied = true;
|
|
118
|
+
result.sessionVendor = vendor;
|
|
119
|
+
result.sessionModel = model;
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function loadCatalog(ws, found, vendor) {
|
|
124
|
+
if (typeof found.ctx.getVendorModelCatalog !== "function") {
|
|
125
|
+
throw modelError("Model catalog is unavailable. Reconnect and choose a model before starting a conversation.");
|
|
126
|
+
}
|
|
127
|
+
var catalog = await found.ctx.getVendorModelCatalog(ws, vendor);
|
|
128
|
+
var models = catalog.models || [];
|
|
129
|
+
if (!models.length) {
|
|
130
|
+
throw modelError(catalog.error || "No models are available for this Mate. Check the vendor connection and try again.");
|
|
131
|
+
}
|
|
132
|
+
return catalog;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function resolveMateModel(ws, found, userId) {
|
|
136
|
+
var mateCtx = mates.buildMateCtx(userId);
|
|
137
|
+
var latestMate = mates.getMate(mateCtx, found.mate.id);
|
|
138
|
+
if (!latestMate) throw modelError("Mate not available.");
|
|
139
|
+
var vendor = latestMate.vendor || "claude";
|
|
140
|
+
var catalog = await loadCatalog(ws, found, vendor);
|
|
141
|
+
var models = catalog.models || [];
|
|
142
|
+
var selected = catalogModel(models, latestMate.model);
|
|
143
|
+
if (!selected) selected = catalogModel(models, catalog.defaultModel);
|
|
144
|
+
for (var i = 0; i < models.length && !selected; i++) selected = modelEntryValue(models[i]);
|
|
145
|
+
if (!selected) throw modelError("The Mate model catalog did not return a usable model. Choose a model and try again.");
|
|
146
|
+
if (latestMate.model !== selected) {
|
|
147
|
+
latestMate = mates.updateMate(mateCtx, latestMate.id, { model: selected });
|
|
148
|
+
if (!latestMate) throw modelError("Could not save the resolved Mate model.");
|
|
149
|
+
broadcastMateUpdated(userId, latestMate);
|
|
150
|
+
}
|
|
151
|
+
found.mate = latestMate;
|
|
152
|
+
return { vendor: vendor, model: selected, catalog: catalog };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function sendMateModels(ws, found, requestId, requestedVendor) {
|
|
156
|
+
var choices = vendorChoices(found);
|
|
157
|
+
var vendor = requestedVendor || found.mate.vendor || "claude";
|
|
158
|
+
if (!vendorIsAvailable(choices, vendor)) {
|
|
159
|
+
sendMessage(ws, { type: "home_mate_models_state", mateId: found.mate.id, requestId: requestId, vendor: vendor, mateVendor: found.mate.vendor || "claude", mateModel: found.mate.model || "", model: "", models: [], vendors: choices, status: "error", error: "That vendor is not configured for this Clay project." });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
var catalog = await found.ctx.getVendorModelCatalog(ws, vendor);
|
|
164
|
+
sendMessage(ws, {
|
|
165
|
+
type: "home_mate_models_state",
|
|
166
|
+
mateId: found.mate.id,
|
|
167
|
+
requestId: requestId,
|
|
168
|
+
vendor: vendor,
|
|
169
|
+
mateVendor: found.mate.vendor || "claude",
|
|
170
|
+
mateModel: found.mate.model || "",
|
|
171
|
+
model: (found.mate.vendor || "claude") === vendor ? (found.mate.model || "") : "",
|
|
172
|
+
models: catalog.models || [],
|
|
173
|
+
vendors: choices,
|
|
174
|
+
status: catalog.status || ((catalog.models || []).length ? "ready" : "empty"),
|
|
175
|
+
error: catalog.error || "",
|
|
176
|
+
});
|
|
177
|
+
} catch (error) {
|
|
178
|
+
sendMessage(ws, { type: "home_mate_models_state", mateId: found.mate.id, requestId: requestId, vendor: vendor, mateVendor: found.mate.vendor || "claude", mateModel: found.mate.model || "", model: "", models: [], vendors: choices, status: "error", error: error.message || String(error) });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function setMateModel(ws, found, userId, msg) {
|
|
183
|
+
var requestId = msg.requestId || null;
|
|
184
|
+
var vendor = msg.vendor || "";
|
|
185
|
+
var choices = vendorChoices(found);
|
|
186
|
+
if (!vendor || !vendorIsAvailable(choices, vendor)) {
|
|
187
|
+
sendMessage(ws, { type: "home_mate_model_result", mateId: found.mate.id, requestId: requestId, ok: false, error: "That vendor is not configured for this Clay project." });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (!msg.model) {
|
|
191
|
+
sendMessage(ws, { type: "home_mate_model_result", mateId: found.mate.id, requestId: requestId, ok: false, error: "That model is not available for this Mate." });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
var catalog;
|
|
195
|
+
try {
|
|
196
|
+
catalog = await loadCatalog(ws, found, vendor);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
sendMessage(ws, { type: "home_mate_model_result", mateId: found.mate.id, requestId: requestId, ok: false, error: error.message || String(error) });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
var mateCtx = mates.buildMateCtx(userId);
|
|
202
|
+
var latestMate = mates.getMate(mateCtx, found.mate.id);
|
|
203
|
+
if (!latestMate) {
|
|
204
|
+
sendMessage(ws, { type: "home_mate_model_result", mateId: found.mate.id, requestId: requestId, ok: false, error: "Mate not available." });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
var selected = catalogModel(catalog.models || [], msg.model);
|
|
208
|
+
if (!selected) {
|
|
209
|
+
sendMessage(ws, { type: "home_mate_model_result", mateId: found.mate.id, requestId: requestId, ok: false, error: "That model is not available for the Mate vendor." });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
var updated = mates.updateMate(mateCtx, found.mate.id, { vendor: vendor, model: selected });
|
|
213
|
+
if (!updated) {
|
|
214
|
+
sendMessage(ws, { type: "home_mate_model_result", mateId: found.mate.id, requestId: requestId, ok: false, error: "Mate not available." });
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
found.mate = updated;
|
|
218
|
+
broadcastMateUpdated(userId, updated);
|
|
219
|
+
var sessionResult = applyModelToPristineSession(found, userId, msg.sessionId || null, vendor, selected);
|
|
220
|
+
var result = Object.assign({ type: "home_mate_model_result", mateId: updated.id, requestId: requestId, ok: true, vendor: vendor, model: selected }, sessionResult);
|
|
221
|
+
sendMessage(ws, result);
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function sendAccessError(ws, msg, text) {
|
|
226
|
+
if (msg.type === "home_mate_models_get") {
|
|
227
|
+
sendMessage(ws, { type: "home_mate_models_state", mateId: msg.mateId || null, requestId: msg.requestId || null, vendor: msg.vendor || "", mateVendor: "", mateModel: "", model: "", models: [], vendors: [], status: "error", error: text });
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
sendMessage(ws, { type: "home_mate_model_result", mateId: msg.mateId || null, requestId: msg.requestId || null, ok: false, error: text });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
resolveMateModel: resolveMateModel,
|
|
235
|
+
sendMateModels: sendMateModels,
|
|
236
|
+
setMateModel: setMateModel,
|
|
237
|
+
sendAccessError: sendAccessError,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
module.exports = { attachHomeModels: attachHomeModels };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// WebSocket bridge for user-scoped home surface preferences.
|
|
2
|
+
|
|
3
|
+
function attachHomePreferences(deps) {
|
|
4
|
+
var users = deps.users;
|
|
5
|
+
var projects = deps.projects;
|
|
6
|
+
|
|
7
|
+
function socketUserId(ws) {
|
|
8
|
+
if (!users.isMultiUser()) return "default";
|
|
9
|
+
return ws._clayUser ? ws._clayUser.id : null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function send(ws, payload) {
|
|
13
|
+
if (ws.readyState !== undefined && ws.readyState !== 1) return;
|
|
14
|
+
ws.send(JSON.stringify(payload));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function broadcast(userId, preference) {
|
|
18
|
+
var sent = new Set();
|
|
19
|
+
projects.forEach(function (projectContext) {
|
|
20
|
+
projectContext.forEachClient(function (otherWs) {
|
|
21
|
+
if (sent.has(otherWs) || socketUserId(otherWs) !== userId) return;
|
|
22
|
+
sent.add(otherWs);
|
|
23
|
+
send(otherWs, { type: "home_dock_state", preference: preference });
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function handleMessage(ws, msg) {
|
|
29
|
+
if (msg.type !== "home_dock_get" && msg.type !== "home_dock_set" && msg.type !== "home_surface_get" && msg.type !== "home_surface_set") return false;
|
|
30
|
+
var userId = socketUserId(ws);
|
|
31
|
+
if (!userId) return true;
|
|
32
|
+
if (msg.type === "home_surface_get") {
|
|
33
|
+
send(ws, { type: "home_surface_state", preference: users.getHomeSurfacePreference(userId) });
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
if (msg.type === "home_surface_set") {
|
|
37
|
+
var surfaceResult = users.setHomeSurfacePreference(userId, msg.preference || {});
|
|
38
|
+
send(ws, {
|
|
39
|
+
type: "home_surface_state",
|
|
40
|
+
preference: surfaceResult.preference || users.getHomeSurfacePreference(userId),
|
|
41
|
+
error: surfaceResult.error || null,
|
|
42
|
+
});
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (msg.type === "home_dock_get") {
|
|
46
|
+
send(ws, { type: "home_dock_state", preference: users.getHomeDockPreference(userId) });
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
var result = users.setHomeDockPreference(userId, msg.preference || {});
|
|
50
|
+
if (result.error) {
|
|
51
|
+
send(ws, { type: "home_dock_state", error: result.error });
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
broadcast(userId, result.preference);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { handleMessage: handleMessage };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = { attachHomePreferences: attachHomePreferences };
|
package/lib/server-mates.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var fs = require("fs");
|
|
2
2
|
var path = require("path");
|
|
3
|
+
var readyCreation = require("./mate-ready-creation");
|
|
3
4
|
|
|
4
5
|
function attachMates(ctx) {
|
|
5
6
|
var users = ctx.users;
|
|
@@ -62,6 +63,37 @@ function attachMates(ctx) {
|
|
|
62
63
|
}, 2000);
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
function createReadyMateFromInterview(ws, userId, definition) {
|
|
67
|
+
var effectiveUserId = users.isMultiUser() ? userId : "default";
|
|
68
|
+
var mateCtx = mates.buildMateCtx(effectiveUserId);
|
|
69
|
+
var mate = readyCreation.createReadyMate(mates, mateCtx, definition);
|
|
70
|
+
var mateDir = mates.getMateDir(mateCtx, mate.id);
|
|
71
|
+
var mateSlug = "mate-" + mate.id;
|
|
72
|
+
var mateName = (mate.profile && mate.profile.displayName) || mate.name || "Mate";
|
|
73
|
+
var registered = false;
|
|
74
|
+
var favorites;
|
|
75
|
+
try {
|
|
76
|
+
registered = addProject(mateDir, mateSlug, mateName, null, mate.createdBy || effectiveUserId, null, { isMate: true, mateDisplayName: mateName }) !== false;
|
|
77
|
+
if (!registered) throw new Error("The Mate project could not be registered.");
|
|
78
|
+
favorites = users.addDmFavorite(effectiveUserId, mate.id);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
if (registered) try { removeProject(mateSlug); } catch (removeError) {}
|
|
81
|
+
try { mates.deleteMate(mateCtx, mate.id); } catch (deleteError) {}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
var message = { type: "mate_created", mate: mate, projectSlug: mateSlug, dmFavorites: favorites, interviewComplete: true };
|
|
85
|
+
if (ws && ws.readyState === 1) try { ws.send(JSON.stringify(message)); } catch (sendError) {}
|
|
86
|
+
projects.forEach(function (project) {
|
|
87
|
+
project.forEachClient(function (otherWs) {
|
|
88
|
+
if (!otherWs || otherWs === ws || otherWs.readyState !== 1) return;
|
|
89
|
+
if (users.isMultiUser() && (!otherWs._clayUser || otherWs._clayUser.id !== effectiveUserId)) return;
|
|
90
|
+
try { otherWs.send(JSON.stringify(message)); } catch (sendError) {}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
refreshTeamSections(mateCtx);
|
|
94
|
+
return mate;
|
|
95
|
+
}
|
|
96
|
+
|
|
65
97
|
// --- Mate message handlers ---
|
|
66
98
|
|
|
67
99
|
function handleMessage(ws, msg) {
|
|
@@ -261,6 +293,10 @@ function attachMates(ctx) {
|
|
|
261
293
|
|
|
262
294
|
if (msg.type === "mate_update") {
|
|
263
295
|
if (!msg.mateId || !msg.updates) return true;
|
|
296
|
+
if (Object.prototype.hasOwnProperty.call(msg.updates, "model")) {
|
|
297
|
+
ws.send(JSON.stringify({ type: "mate_error", error: "Use the Mate model selector to change this setting." }));
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
264
300
|
var mateCtx7 = mates.buildMateCtx(userId);
|
|
265
301
|
var updated = mates.updateMate(mateCtx7, msg.mateId, msg.updates);
|
|
266
302
|
if (updated) {
|
|
@@ -287,6 +323,7 @@ function attachMates(ctx) {
|
|
|
287
323
|
return {
|
|
288
324
|
handleMessage: handleMessage,
|
|
289
325
|
scheduleRegistryRefresh: scheduleRegistryRefresh,
|
|
326
|
+
createReadyMateFromInterview: createReadyMateFromInterview,
|
|
290
327
|
};
|
|
291
328
|
}
|
|
292
329
|
|