clay-server 5.1.0-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-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- 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/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/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/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
package/lib/project-knowledge.js
CHANGED
|
@@ -1,184 +1,363 @@
|
|
|
1
|
-
var fs = require("fs");
|
|
2
1
|
var path = require("path");
|
|
2
|
+
var crypto = require("crypto");
|
|
3
3
|
var mateSync = require("./mate-knowledge-sync");
|
|
4
|
+
var knowledgeFiles = require("./knowledge-file-store");
|
|
5
|
+
var markdown = require("./knowledge-markdown");
|
|
6
|
+
var draftStore = require("./knowledge-draft-store");
|
|
7
|
+
var documentIndexModule = require("./knowledge-document-index");
|
|
8
|
+
var knowledgeDbModule = require("./knowledge-db-service");
|
|
9
|
+
var knowledgeImport = require("./knowledge-import");
|
|
4
10
|
|
|
5
|
-
/**
|
|
6
|
-
* Attach knowledge file management to a project context.
|
|
7
|
-
*
|
|
8
|
-
* ctx fields:
|
|
9
|
-
* cwd, isMate, sendTo, matesModule, projectOwnerId
|
|
10
|
-
*/
|
|
11
11
|
function attachKnowledge(ctx) {
|
|
12
12
|
var cwd = ctx.cwd;
|
|
13
13
|
var isMate = ctx.isMate;
|
|
14
14
|
var sendTo = ctx.sendTo;
|
|
15
15
|
var matesModule = ctx.matesModule;
|
|
16
16
|
var getProjectOwnerId = ctx.getProjectOwnerId;
|
|
17
|
+
var metadataKey = crypto.createHash("sha256").update(path.resolve(cwd)).digest("hex").slice(0, 24);
|
|
18
|
+
var metadataRoot = path.join(ctx.knowledgeBaseDir || path.join(cwd, ".clay"), "knowledge-documents", metadataKey);
|
|
19
|
+
var files = knowledgeFiles.createKnowledgeFileStore(cwd, { metaDir: metadataRoot });
|
|
20
|
+
var drafts = draftStore.createKnowledgeDraftStore(ctx.knowledgeBaseDir || path.join(cwd, ".clay"), path.resolve(cwd));
|
|
21
|
+
var indexer = documentIndexModule.createKnowledgeDocumentIndex({ list: listKnowledgeFiles, read: readEntry, maxDocumentBytes: knowledgeFiles.MAX_CONTENT_BYTES });
|
|
22
|
+
var dbScope = isMate ? mateSync.scopeForMateDir(cwd) : null;
|
|
23
|
+
var dbImporter = dbScope ? knowledgeImport.createKnowledgeImporter({ scopeId: dbScope.scopeId, baseDir: ctx.knowledgeBaseDir }) : null;
|
|
24
|
+
var databases = isMate ? knowledgeDbModule.createKnowledgeDbService({
|
|
25
|
+
projectDir: cwd,
|
|
26
|
+
authorizeTextReference: function (id) { return files.list().some(function (file) { return file.id === id && file.itemType === "text"; }); },
|
|
27
|
+
projectSummary: dbImporter ? function (summary) {
|
|
28
|
+
return dbImporter.importRecord({ importKey: "knowledge-database:" + summary.databaseId, sourceHash: String(summary.revision) + ":" + String(summary.archived),
|
|
29
|
+
kind: "knowledge-database-summary", name: summary.name, content: summary.content,
|
|
30
|
+
source: { namespace: "knowledge-database", databaseId: summary.databaseId, relPath: "knowledge/.clay-db/databases.db" }, actor: summary.actor });
|
|
31
|
+
} : null,
|
|
32
|
+
}) : null;
|
|
33
|
+
var databaseReady = databases && databases.hasStore() ? databases.initialize() : null;
|
|
34
|
+
if (databaseReady) databaseReady.catch(function (error) { console.error("[knowledge-db] Failed to initialize:", error.message); });
|
|
35
|
+
|
|
36
|
+
function canWrite(ws) {
|
|
37
|
+
if (typeof ctx.canManageKnowledge === "function") return ctx.canManageKnowledge(ws) === true;
|
|
38
|
+
var ownerId = getProjectOwnerId();
|
|
39
|
+
return !ownerId || !!(ws && ws._clayUser && ws._clayUser.id === ownerId);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function actor(ws) {
|
|
43
|
+
var user = (ws && ws._clayUser) || null;
|
|
44
|
+
return { type: user ? "user" : "system", userId: user ? user.id : null, displayName: user ? (user.displayName || user.username) : null };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function mirror(ws, name) {
|
|
48
|
+
if (!isMate) return { ok: true, names: [] };
|
|
49
|
+
var summary = mateSync.syncMateSource({ mateDir: cwd, fileName: name, baseDir: ctx.knowledgeBaseDir, actor: actor(ws) });
|
|
50
|
+
return { ok: !!summary && summary.failed === 0, names: [name], error: summary && summary.errors[0] ? summary.errors[0].message : "Knowledge index synchronization failed." };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function mirrorMany(ws, names) {
|
|
54
|
+
var failures = [];
|
|
55
|
+
for (var i = 0; i < names.length; i++) {
|
|
56
|
+
var mirrored = mirror(ws, names[i]);
|
|
57
|
+
if (!mirrored.ok) failures.push(mirrored.error);
|
|
58
|
+
}
|
|
59
|
+
return { ok: failures.length === 0, names: names.slice(), error: failures[0] || null };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function addSyncState(payload, sync) {
|
|
63
|
+
if (sync.ok) return payload;
|
|
64
|
+
return Object.assign(payload, { indexSyncPending: true, syncNames: sync.names, syncError: sync.error });
|
|
65
|
+
}
|
|
17
66
|
|
|
18
67
|
function listKnowledgeFiles() {
|
|
19
|
-
var
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
68
|
+
var listed = files.list();
|
|
69
|
+
for (var i = 0; i < listed.length; i++) listed[i].common = false;
|
|
70
|
+
if (!isMate) return listed;
|
|
71
|
+
var mateCtx = matesModule.buildMateCtx(getProjectOwnerId());
|
|
72
|
+
var thisMateId = path.basename(cwd);
|
|
73
|
+
for (var p = 0; p < listed.length; p++) listed[p].promoted = matesModule.isPromoted(mateCtx, thisMateId, listed[p].name);
|
|
74
|
+
var common = matesModule.getCommonKnowledgeForMate(mateCtx, thisMateId);
|
|
75
|
+
for (var c = 0; c < common.length; c++) {
|
|
76
|
+
if (common[c].ownMateId !== thisMateId) listed.push(Object.assign({}, common[c], { id: "shared:" + common[c].ownMateId + ":" + common[c].name,
|
|
77
|
+
itemType: /\.jsonl$/i.test(common[c].name) ? "db" : "text", writable: false, revision: null }));
|
|
78
|
+
}
|
|
79
|
+
return listed;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function listKnowledgeItems(ws) {
|
|
83
|
+
var textItems = listKnowledgeFiles();
|
|
84
|
+
if (!databases || !databases.hasStore()) return textItems;
|
|
85
|
+
function combine(result) { return textItems.concat(result.databases.map(function (item) { return Object.assign({}, item, { writable: canWrite(ws), common: false }); })); }
|
|
86
|
+
if (databases.isReady()) return combine(databases.listCached({}));
|
|
87
|
+
return databaseReady.then(function () { return combine(databases.listCached({})); });
|
|
88
|
+
}
|
|
34
89
|
|
|
35
|
-
|
|
90
|
+
function response(ws, msg, payload) {
|
|
91
|
+
sendTo(ws, Object.assign({ requestId: msg.requestId || null }, payload));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function failure(ws, msg, error, extra) {
|
|
95
|
+
response(ws, msg, Object.assign({ type: "knowledge_error", operation: msg.type, name: msg.name || msg.from || null,
|
|
96
|
+
code: error.code || "FAILED", error: error.message || "Knowledge operation failed.", currentRevision: error.currentRevision || null }, extra || {}));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function requireWrite(ws, msg) {
|
|
100
|
+
if (canWrite(ws)) return true;
|
|
101
|
+
failure(ws, msg, Object.assign(new Error("Only the Mate owner can change Knowledge documents."), { code: "FORBIDDEN" }));
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function readEntry(file) {
|
|
106
|
+
if (file.common && file.ownMateId && isMate) {
|
|
36
107
|
var mateCtx = matesModule.buildMateCtx(getProjectOwnerId());
|
|
37
|
-
|
|
38
|
-
for (var pi = 0; pi < files.length; pi++) {
|
|
39
|
-
files[pi].promoted = matesModule.isPromoted(mateCtx, thisMateId, files[pi].name);
|
|
40
|
-
}
|
|
41
|
-
var commonFiles = matesModule.getCommonKnowledgeForMate(mateCtx, thisMateId);
|
|
42
|
-
for (var ci = 0; ci < commonFiles.length; ci++) {
|
|
43
|
-
if (commonFiles[ci].ownMateId !== thisMateId) {
|
|
44
|
-
files.push(commonFiles[ci]);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
108
|
+
return matesModule.readCommonKnowledgeFile(mateCtx, file.ownMateId, file.name);
|
|
47
109
|
}
|
|
48
|
-
return files;
|
|
110
|
+
return files.read(file.name).content;
|
|
49
111
|
}
|
|
50
112
|
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
113
|
+
function documentIndex() {
|
|
114
|
+
return indexer.reconcile();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function findDocument(index, name, id) {
|
|
118
|
+
var matches;
|
|
119
|
+
if (id) { matches = index.filter(function (item) { return item.id === id; }); return matches.length === 1 ? matches[0] : null; }
|
|
120
|
+
matches = index.filter(function (item) { return item.name === name; });
|
|
121
|
+
return matches.length === 1 ? matches[0] : null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function linksFor(index, target) {
|
|
125
|
+
var outgoing = []; var backlinks = [];
|
|
126
|
+
for (var i = 0; i < target.parsed.links.length; i++) {
|
|
127
|
+
var link = target.parsed.links[i]; var resolved = markdown.resolveLink(target.name, link, index, target.id);
|
|
128
|
+
var headingValid = !link.heading || !!(resolved && resolved.parsed.headings.some(function (heading) { return heading.slug === markdown.slug(link.heading); }));
|
|
129
|
+
outgoing.push({ kind: link.kind, raw: link.raw, label: link.alias || link.target || link.heading, target: link.target, heading: link.heading,
|
|
130
|
+
headingValid: headingValid, documentId: resolved && resolved.id || null, documentKey: resolved && resolved.key || null,
|
|
131
|
+
name: resolved && resolved.name || null, external: link.external === true, self: !link.target && !!link.heading, unresolved: !resolved && !link.external });
|
|
132
|
+
}
|
|
133
|
+
for (var d = 0; d < index.length; d++) {
|
|
134
|
+
if (index[d] === target) continue;
|
|
135
|
+
for (var l = 0; l < index[d].parsed.links.length; l++) {
|
|
136
|
+
var resolvedTarget = markdown.resolveLink(index[d].name, index[d].parsed.links[l], index, index[d].id);
|
|
137
|
+
if (resolvedTarget && resolvedTarget.id === target.id) {
|
|
138
|
+
backlinks.push({ documentId: index[d].id, documentKey: index[d].key, name: index[d].name, heading: index[d].parsed.links[l].heading,
|
|
139
|
+
snippet: markdown.snippet(index[d].content, index[d].parsed.links[l].start) }); break;
|
|
60
140
|
}
|
|
61
141
|
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
142
|
+
}
|
|
143
|
+
return { outgoing: outgoing, backlinks: backlinks };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function relativeLink(from, to, withExtension) {
|
|
147
|
+
var value = path.posix.relative(path.posix.dirname(from), to) || path.posix.basename(to);
|
|
148
|
+
if (withExtension === false) value = value.replace(/\.md$/i, "");
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function rewriteMoveLinks(index, target, nextName) {
|
|
153
|
+
var changes = [];
|
|
154
|
+
for (var i = 0; i < index.length; i++) {
|
|
155
|
+
var source = index[i];
|
|
156
|
+
if (source.common || source.itemType === "db" || !source.writable) continue;
|
|
157
|
+
var replacements = [];
|
|
158
|
+
for (var l = 0; l < source.parsed.links.length; l++) {
|
|
159
|
+
var link = source.parsed.links[l]; var resolved = markdown.resolveLink(source.name, link, index, source.id);
|
|
160
|
+
if (!resolved || source.id !== target.id && resolved.id !== target.id) continue;
|
|
161
|
+
var sourceAfter = source.id === target.id ? nextName : source.name;
|
|
162
|
+
var targetAfter = resolved.id === target.id ? nextName : resolved.name;
|
|
163
|
+
var nextTarget = relativeLink(sourceAfter, targetAfter, link.kind === "markdown" || link.kind === "image");
|
|
164
|
+
var suffix = link.heading ? "#" + link.heading : ""; var replacement;
|
|
165
|
+
if (link.kind === "wiki" || link.kind === "embed") replacement = (link.kind === "embed" ? "!" : "") + "[[" + nextTarget + suffix + (link.alias ? "|" + link.alias : "") + "]]";
|
|
166
|
+
else replacement = (link.kind === "image" ? "!" : "") + "[" + link.alias + "](" + nextTarget + suffix + ")";
|
|
167
|
+
replacements.push({ start: link.start, end: link.end, value: replacement });
|
|
74
168
|
}
|
|
169
|
+
if (!replacements.length) continue;
|
|
170
|
+
var content = source.content;
|
|
171
|
+
for (var r = replacements.length - 1; r >= 0; r--) content = content.slice(0, replacements[r].start) + replacements[r].value + content.slice(replacements[r].end);
|
|
172
|
+
changes.push({ id: source.id, name: source.name, revision: source.revision, content: content, count: replacements.length });
|
|
75
173
|
}
|
|
76
|
-
return
|
|
174
|
+
return changes;
|
|
77
175
|
}
|
|
78
176
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
displayName: user ? (user.displayName || user.username) : null,
|
|
92
|
-
},
|
|
93
|
-
});
|
|
177
|
+
function searchFiles(query, offset, limit) {
|
|
178
|
+
var start = Math.max(0, Number(offset) || 0); var count = Math.max(1, Math.min(100, Number(limit) || 50)); var direct = indexer.search(query, start, count); var needle = String(query || "").trim().toLowerCase();
|
|
179
|
+
if (!databases || !databases.hasStore()) return direct;
|
|
180
|
+
function combineSearch(result) {
|
|
181
|
+
var databaseMatches = result.databases.filter(function (item) { return needle && (item.name.toLowerCase().indexOf(needle) !== -1 || item.schema.some(function (field) { return field.name.toLowerCase().indexOf(needle) !== -1 || field.type.indexOf(needle) !== -1; })); }).map(function (item) { return Object.assign({}, item, { itemType: "db", writable: true, common: false, snippet: "Database · " + item.recordCount + " records" }); });
|
|
182
|
+
if (!databaseMatches.length) return direct;
|
|
183
|
+
var files = direct.files.slice(); var textTotal = direct.total; var databaseOffset = Math.max(0, start - textTotal); var room = count - files.length;
|
|
184
|
+
if (room > 0) files = files.concat(databaseMatches.slice(databaseOffset, databaseOffset + room));
|
|
185
|
+
return { files: files, total: textTotal + databaseMatches.length, offset: start, limit: count, complete: direct.complete, errors: direct.errors };
|
|
186
|
+
}
|
|
187
|
+
if (databases.isReady()) return combineSearch(databases.listCached({}));
|
|
188
|
+
return databaseReady.then(function () { return combineSearch(databases.listCached({})); });
|
|
94
189
|
}
|
|
95
190
|
|
|
96
191
|
function handleKnowledgeMessage(ws, msg) {
|
|
97
192
|
if (msg.type === "knowledge_list") {
|
|
98
|
-
|
|
193
|
+
try { var listed = listKnowledgeItems(ws); if (listed && typeof listed.then === "function") listed.then(function (items) { response(ws, msg, { type: "knowledge_list", files: items, drafts: drafts.list(ws && ws._clayUser && ws._clayUser.id || "system") }); }).catch(function (error) { failure(ws, msg, error); }); else response(ws, msg, { type: "knowledge_list", files: listed, drafts: drafts.list(ws && ws._clayUser && ws._clayUser.id || "system") }); } catch (error) { failure(ws, msg, error); }
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
if (msg.type === "knowledge_search") {
|
|
197
|
+
try { var searched = searchFiles(msg.query, msg.offset, msg.limit); if (searched && typeof searched.then === "function") searched.then(function (result) { response(ws, msg, Object.assign({ type: "knowledge_search_results", query: String(msg.query || "") }, result)); }).catch(function (error) { failure(ws, msg, error); }); else response(ws, msg, Object.assign({ type: "knowledge_search_results", query: String(msg.query || "") }, searched)); } catch (error) { failure(ws, msg, error); }
|
|
99
198
|
return true;
|
|
100
199
|
}
|
|
101
|
-
|
|
102
200
|
if (msg.type === "knowledge_read") {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
var
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
var
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
201
|
+
try {
|
|
202
|
+
if (msg.common && msg.ownMateId && isMate) {
|
|
203
|
+
if (!knowledgeFiles.validName(msg.name)) throw new Error("Invalid knowledge file name.");
|
|
204
|
+
var mateCtx = matesModule.buildMateCtx(getProjectOwnerId());
|
|
205
|
+
var sharedContent = matesModule.readCommonKnowledgeFile(mateCtx, msg.ownMateId, msg.name);
|
|
206
|
+
var sharedParsed = markdown.parse(sharedContent); var sharedIndexState = documentIndex();
|
|
207
|
+
var sharedIndexed = findDocument(sharedIndexState.documents, msg.name, msg.documentId); var sharedRelations = sharedIndexed ? linksFor(sharedIndexState.documents, sharedIndexed) : { outgoing: [], backlinks: [] };
|
|
208
|
+
response(ws, msg, { type: "knowledge_content", name: msg.name, content: sharedContent, common: true, ownMateId: msg.ownMateId, writable: false, revision: null,
|
|
209
|
+
outline: sharedParsed.headings, outgoing: sharedRelations.outgoing, backlinks: sharedRelations.backlinks,
|
|
210
|
+
properties: sharedParsed.properties, tags: sharedParsed.tags, propertyErrors: sharedParsed.propertyErrors,
|
|
211
|
+
indexComplete: sharedIndexState.complete, indexErrors: sharedIndexState.errors });
|
|
212
|
+
} else {
|
|
213
|
+
var item = files.read(msg.name);
|
|
214
|
+
var indexState = documentIndex(); var indexed = findDocument(indexState.documents, item.name, msg.documentId || item.id); var relations = indexed ? linksFor(indexState.documents, indexed) : { outgoing: [], backlinks: [] };
|
|
215
|
+
var parsed = indexed ? indexed.parsed : markdown.parse(item.content);
|
|
216
|
+
var userId = ws && ws._clayUser && ws._clayUser.id || "system"; var recovered = drafts.read(userId, item.id);
|
|
217
|
+
response(ws, msg, { type: "knowledge_content", id: item.id, name: item.name, content: item.content, revision: item.revision, itemType: item.itemType,
|
|
218
|
+
writable: item.itemType === "text" && canWrite(ws), outline: parsed.headings, outgoing: relations.outgoing, backlinks: relations.backlinks,
|
|
219
|
+
properties: parsed.properties, tags: parsed.tags, propertyErrors: parsed.propertyErrors, recoveredDraft: recovered,
|
|
220
|
+
indexComplete: indexState.complete, indexErrors: indexState.errors });
|
|
120
221
|
}
|
|
121
|
-
}
|
|
222
|
+
} catch (error) { failure(ws, msg, error); }
|
|
122
223
|
return true;
|
|
123
224
|
}
|
|
124
|
-
|
|
125
225
|
if (msg.type === "knowledge_save") {
|
|
126
|
-
if (!
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
226
|
+
if (!requireWrite(ws, msg)) return true;
|
|
227
|
+
try {
|
|
228
|
+
var saved = files.save(msg.name, msg.content, msg.expectedRevision || null);
|
|
229
|
+
var savedSync = mirror(ws, saved.name);
|
|
230
|
+
if (msg.documentId) drafts.remove(ws._clayUser && ws._clayUser.id || "system", msg.documentId, msg.draftVersion);
|
|
231
|
+
response(ws, msg, addSyncState({ type: "knowledge_saved", id: saved.id, name: saved.name, revision: saved.revision }, savedSync));
|
|
232
|
+
sendTo(ws, { type: "knowledge_list", files: listKnowledgeFiles() });
|
|
233
|
+
} catch (error) { failure(ws, msg, error); }
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
if (msg.type === "knowledge_rename") {
|
|
237
|
+
if (!requireWrite(ws, msg)) return true;
|
|
238
|
+
try {
|
|
239
|
+
var beforeMoveState = documentIndex(); var beforeMove = beforeMoveState.documents; var moveTarget = findDocument(beforeMove, msg.from, msg.documentId); var linkChanges = moveTarget ? rewriteMoveLinks(beforeMove, moveTarget, msg.name) : [];
|
|
240
|
+
var renamed = files.rename(msg.from, msg.name, msg.expectedRevision || null); var linkUpdateFailures = []; var updatedLinks = 0;
|
|
241
|
+
var updatedDocuments = []; var mirrorNames = [msg.from, renamed.name];
|
|
242
|
+
for (var u = 0; u < linkChanges.length; u++) {
|
|
243
|
+
var change = linkChanges[u]; var writeName = change.id === renamed.id ? renamed.name : change.name; var expected = change.id === renamed.id ? renamed.revision : change.revision;
|
|
244
|
+
try { var rewritten = files.save(writeName, change.content, expected); updatedLinks += change.count; updatedDocuments.push(rewritten); mirrorNames.push(rewritten.name); }
|
|
245
|
+
catch (linkError) { linkUpdateFailures.push({ name: writeName, error: linkError.message }); }
|
|
246
|
+
}
|
|
247
|
+
renamed = files.read(renamed.name);
|
|
248
|
+
var uniqueMirrorNames = mirrorNames.filter(function (name, at) { return mirrorNames.indexOf(name) === at; }); var renameSync = mirrorMany(ws, uniqueMirrorNames);
|
|
249
|
+
response(ws, msg, addSyncState({ type: "knowledge_renamed", id: renamed.id, from: msg.from, name: renamed.name, revision: renamed.revision,
|
|
250
|
+
content: renamed.content, updatedLinks: updatedLinks, linkUpdateFailures: linkUpdateFailures,
|
|
251
|
+
updatedDocuments: updatedDocuments.map(function (item) { return { id: item.id, name: item.name, content: item.content, revision: item.revision }; }) }, renameSync));
|
|
252
|
+
sendTo(ws, { type: "knowledge_list", files: listKnowledgeFiles() });
|
|
253
|
+
} catch (error) { failure(ws, msg, error); }
|
|
135
254
|
return true;
|
|
136
255
|
}
|
|
137
|
-
|
|
138
256
|
if (msg.type === "knowledge_delete") {
|
|
139
|
-
if (!msg
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
sendTo(ws, { type: "knowledge_deleted", name: safeName });
|
|
147
|
-
sendTo(ws, { type: "knowledge_list", files: listKnowledgeFilesBasic() });
|
|
257
|
+
if (!requireWrite(ws, msg)) return true;
|
|
258
|
+
try {
|
|
259
|
+
var removed = files.remove(msg.name, msg.expectedRevision || null);
|
|
260
|
+
var deleteSync = mirror(ws, removed.name);
|
|
261
|
+
response(ws, msg, addSyncState({ type: "knowledge_deleted", name: removed.name }, deleteSync));
|
|
262
|
+
sendTo(ws, { type: "knowledge_list", files: listKnowledgeFiles() });
|
|
263
|
+
} catch (error) { failure(ws, msg, error); }
|
|
148
264
|
return true;
|
|
149
265
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
sendTo(ws, { type: "knowledge_list", files: listKnowledgeFiles() });
|
|
266
|
+
if (msg.type === "knowledge_sync") {
|
|
267
|
+
if (!requireWrite(ws, msg)) return true;
|
|
268
|
+
try {
|
|
269
|
+
var syncNames = Array.isArray(msg.names) ? msg.names.slice(0, 4) : [msg.name];
|
|
270
|
+
if (!syncNames.length) throw new Error("A Knowledge source is required.");
|
|
271
|
+
for (var n = 0; n < syncNames.length; n++) if (!knowledgeFiles.validName(syncNames[n])) throw new Error("Invalid knowledge file name.");
|
|
272
|
+
var retrySync = mirrorMany(ws, syncNames);
|
|
273
|
+
if (!retrySync.ok) throw Object.assign(new Error(retrySync.error), { code: "SYNC_FAILED" });
|
|
274
|
+
response(ws, msg, { type: "knowledge_synced", names: syncNames });
|
|
275
|
+
} catch (error) { failure(ws, msg, error, { diskCommitted: true, names: msg.names || [msg.name] }); }
|
|
161
276
|
return true;
|
|
162
277
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
278
|
+
if (msg.type === "knowledge_draft_save") {
|
|
279
|
+
if (!requireWrite(ws, msg)) return true;
|
|
280
|
+
try {
|
|
281
|
+
var savedDraft = drafts.save(ws._clayUser && ws._clayUser.id || "system", msg.documentId, { name: msg.name, content: msg.content, baseRevision: msg.baseRevision,
|
|
282
|
+
cursor: msg.cursor, clientVersion: msg.clientVersion, newDocument: msg.newDocument });
|
|
283
|
+
response(ws, msg, { type: "knowledge_draft_saved", documentId: msg.documentId, savedAt: savedDraft.savedAt, clientVersion: savedDraft.clientVersion });
|
|
284
|
+
} catch (error) { failure(ws, msg, error); }
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
if (msg.type === "knowledge_draft_delete") {
|
|
288
|
+
if (!requireWrite(ws, msg)) return true;
|
|
289
|
+
try { var removedDraft = drafts.remove(ws._clayUser && ws._clayUser.id || "system", msg.documentId, msg.throughVersion); response(ws, msg, { type: "knowledge_draft_deleted", documentId: msg.documentId, removed: removedDraft }); }
|
|
290
|
+
catch (error) { failure(ws, msg, error); }
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
if (msg.type === "knowledge_discard_draft") {
|
|
294
|
+
if (!requireWrite(ws, msg)) return true;
|
|
295
|
+
try {
|
|
296
|
+
var disk = files.read(msg.name); if (msg.expectedRevision && disk.revision !== msg.expectedRevision) throw Object.assign(new Error("The disk version changed again."), { code: "STALE", currentRevision: disk.revision });
|
|
297
|
+
var removed = drafts.remove(ws._clayUser && ws._clayUser.id || "system", msg.documentId, msg.throughVersion);
|
|
298
|
+
response(ws, msg, { type: "knowledge_draft_discarded", documentId: msg.documentId, removed: removed, id: disk.id, name: disk.name, content: disk.content, revision: disk.revision });
|
|
299
|
+
} catch (error) { failure(ws, msg, error); }
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
if (msg.type === "knowledge_history") {
|
|
303
|
+
try { response(ws, msg, { type: "knowledge_history", documentId: msg.documentId, versions: files.history(msg.documentId) }); }
|
|
304
|
+
catch (error) { failure(ws, msg, error); }
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
if (msg.type === "knowledge_history_read") {
|
|
308
|
+
try { response(ws, msg, Object.assign({ type: "knowledge_history_version", documentId: msg.documentId }, files.readHistory(msg.documentId, msg.version))); }
|
|
309
|
+
catch (error) { failure(ws, msg, error); }
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
if (msg.type === "knowledge_deleted_list") {
|
|
313
|
+
if (!databases || !databases.hasStore()) { try { response(ws, msg, { type: "knowledge_deleted_list", files: files.deleted() }); } catch (error) { failure(ws, msg, error); } return true; }
|
|
314
|
+
databases.list({ archived: true }).then(function (result) { var archivedDatabases = result.databases.map(function (item) { return Object.assign({}, item, { itemType: "db", writable: canWrite(ws) }); }); response(ws, msg, { type: "knowledge_deleted_list", files: files.deleted().concat(archivedDatabases) }); }).catch(function (error) { failure(ws, msg, error); });
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
if (msg.type === "knowledge_restore") {
|
|
318
|
+
if (!requireWrite(ws, msg)) return true;
|
|
319
|
+
try {
|
|
320
|
+
var restored = files.restore(msg.documentId, msg.version, msg.name, msg.expectedRevision || null); var restoreSync = mirror(ws, restored.name);
|
|
321
|
+
response(ws, msg, addSyncState({ type: "knowledge_restored", id: restored.id, name: restored.name, revision: restored.revision }, restoreSync));
|
|
322
|
+
sendTo(ws, { type: "knowledge_list", files: listKnowledgeFiles() });
|
|
323
|
+
} catch (error) { failure(ws, msg, error); }
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
if (msg.type === "knowledge_promote" || msg.type === "knowledge_depromote") {
|
|
327
|
+
if (!isMate || !requireWrite(ws, msg)) return true;
|
|
328
|
+
try {
|
|
329
|
+
if (!knowledgeFiles.validName(msg.name)) throw new Error("Invalid knowledge file name.");
|
|
330
|
+
var promoteCtx = matesModule.buildMateCtx(getProjectOwnerId());
|
|
331
|
+
var mateId = path.basename(cwd);
|
|
332
|
+
if (msg.type === "knowledge_promote") {
|
|
333
|
+
var mate = matesModule.getMate(promoteCtx, mateId);
|
|
334
|
+
matesModule.promoteKnowledge(promoteCtx, mateId, mate && mate.name, msg.name);
|
|
335
|
+
} else matesModule.depromoteKnowledge(promoteCtx, mateId, msg.name);
|
|
336
|
+
response(ws, msg, { type: msg.type === "knowledge_promote" ? "knowledge_promoted" : "knowledge_depromoted", name: msg.name });
|
|
337
|
+
sendTo(ws, { type: "knowledge_list", files: listKnowledgeFiles() });
|
|
338
|
+
} catch (error) { failure(ws, msg, error); }
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
var dbOperations = {
|
|
342
|
+
knowledge_db_create: { method: "create", reply: "knowledge_db_created" }, knowledge_db_read: { method: "read", reply: "knowledge_db_content", read: true },
|
|
343
|
+
knowledge_db_rename: { method: "rename", reply: "knowledge_db_renamed" }, knowledge_db_archive: { method: "archive", reply: "knowledge_db_archived" },
|
|
344
|
+
knowledge_db_recover: { method: "recover", reply: "knowledge_db_recovered" }, knowledge_db_schema_save: { method: "updateSchema", reply: "knowledge_db_schema_saved" },
|
|
345
|
+
knowledge_db_view_save: { method: "saveView", reply: "knowledge_db_view_saved" }, knowledge_db_record_create: { method: "createRecord", reply: "knowledge_db_record_created" },
|
|
346
|
+
knowledge_db_record_read: { method: "readRecord", reply: "knowledge_db_record_content", read: true }, knowledge_db_record_update: { method: "updateRecord", reply: "knowledge_db_record_updated" },
|
|
347
|
+
knowledge_db_record_archive: { method: "archiveRecord", reply: "knowledge_db_record_archived" }, knowledge_db_record_recover: { method: "recoverRecord", reply: "knowledge_db_record_recovered" },
|
|
348
|
+
knowledge_db_query: { method: "query", reply: "knowledge_db_query_results", read: true }, knowledge_db_sync: { method: "retryProjection", reply: "knowledge_db_synced" },
|
|
349
|
+
};
|
|
350
|
+
if (dbOperations[msg.type]) {
|
|
351
|
+
if (!isMate) { failure(ws, msg, new Error("Knowledge databases are available only inside a Mate project.")); return true; }
|
|
352
|
+
var operation = dbOperations[msg.type]; if (!operation.read && !requireWrite(ws, msg)) return true;
|
|
353
|
+
var args = Object.assign({}, msg, { actor: actor(ws) }); delete args.type; delete args.requestId;
|
|
354
|
+
Promise.resolve(databases[operation.method](args)).then(function (result) { response(ws, msg, Object.assign({ type: operation.reply }, result)); }).catch(function (error) { failure(ws, msg, error, { databaseId: msg.databaseId || null, recordId: msg.recordId || null }); });
|
|
172
355
|
return true;
|
|
173
356
|
}
|
|
174
|
-
|
|
175
357
|
return false;
|
|
176
358
|
}
|
|
177
359
|
|
|
178
|
-
return {
|
|
179
|
-
handleKnowledgeMessage: handleKnowledgeMessage,
|
|
180
|
-
listKnowledgeFiles: listKnowledgeFiles,
|
|
181
|
-
};
|
|
360
|
+
return { handleKnowledgeMessage: handleKnowledgeMessage, listKnowledgeFiles: listKnowledgeFiles, databases: databases };
|
|
182
361
|
}
|
|
183
362
|
|
|
184
363
|
module.exports = { attachKnowledge: attachKnowledge };
|
|
@@ -98,6 +98,7 @@ function attachMateCreationProposal(ctx) {
|
|
|
98
98
|
return ctx.createReadyMate(ws, session.ownerId || null, Object.assign({}, entry.definition, { vendor: vendor, model: selected.value }));
|
|
99
99
|
}).then(function (mate) {
|
|
100
100
|
session.homeMateCreationPhase = "created";
|
|
101
|
+
if (typeof ctx.persistSession === "function") ctx.persistSession(session);
|
|
101
102
|
record(session, { type: "mate_creation_proposal_resolved", proposalId: msg.proposalId, action: "create", mateId: mate.id, mateName: (mate.profile && mate.profile.displayName) || mate.name || "Mate" });
|
|
102
103
|
entry.resolve({ action: "create", mateId: mate.id });
|
|
103
104
|
}).catch(function (error) {
|
package/lib/project-sessions.js
CHANGED
|
@@ -87,6 +87,7 @@ function formatAskUserAnswerAsMessage(input, answers) {
|
|
|
87
87
|
* getLatestVersion, setLatestVersion
|
|
88
88
|
*/
|
|
89
89
|
function attachSessions(ctx) {
|
|
90
|
+
var mateDefaultsToken = {};
|
|
90
91
|
var contextUsage = contextUsageModule.attachContextUsage(ctx);
|
|
91
92
|
var cwd = ctx.cwd;
|
|
92
93
|
var slug = ctx.slug;
|
|
@@ -635,6 +636,32 @@ function attachSessions(ctx) {
|
|
|
635
636
|
ws._scheduledInterviewSessionRequests[scheduledRequestId] = pendingScheduled;
|
|
636
637
|
return true;
|
|
637
638
|
}
|
|
639
|
+
if (msg.mateDefaults === true && msg._mateDefaultsToken !== mateDefaultsToken) {
|
|
640
|
+
var mateRequestId = typeof msg.requestId === "string" ? msg.requestId.substring(0, 200) : "";
|
|
641
|
+
if (!isMate || !mateRequestId || typeof ctx.resolveMateSessionDefaults !== "function") {
|
|
642
|
+
scheduledRequestError(ws, msg, "Mate defaults are unavailable.");
|
|
643
|
+
return true;
|
|
644
|
+
}
|
|
645
|
+
if (!ws._pendingMateSessionRequests) ws._pendingMateSessionRequests = {};
|
|
646
|
+
if (ws._pendingMateSessionRequests[mateRequestId]) return true;
|
|
647
|
+
var pendingMateSession = Promise.resolve(ctx.resolveMateSessionDefaults(ws)).then(function (resolved) {
|
|
648
|
+
if (!resolved || !resolved.vendor || !resolved.model) throw new Error("The Mate vendor and model are not configured.");
|
|
649
|
+
var resolvedMessage = Object.assign({}, msg, {
|
|
650
|
+
_mateDefaultsToken: mateDefaultsToken,
|
|
651
|
+
vendor: resolved.vendor,
|
|
652
|
+
model: resolved.model,
|
|
653
|
+
effort: resolved.effort || "",
|
|
654
|
+
mode: "gui",
|
|
655
|
+
});
|
|
656
|
+
handleSessionsMessage(ws, resolvedMessage);
|
|
657
|
+
}).catch(function (error) {
|
|
658
|
+
scheduledRequestError(ws, msg, error.message || String(error));
|
|
659
|
+
}).finally(function () {
|
|
660
|
+
if (ws._pendingMateSessionRequests[mateRequestId] === pendingMateSession) delete ws._pendingMateSessionRequests[mateRequestId];
|
|
661
|
+
});
|
|
662
|
+
ws._pendingMateSessionRequests[mateRequestId] = pendingMateSession;
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
638
665
|
var creationRequestId = typeof msg.requestId === "string" ? msg.requestId.substring(0, 200) : "";
|
|
639
666
|
var creationFailed = function (text) {
|
|
640
667
|
if (creationRequestId) sendTo(ws, { type: "new_session_result", requestId: creationRequestId, ok: false, error: text });
|
|
@@ -672,6 +699,7 @@ function attachSessions(ctx) {
|
|
|
672
699
|
}
|
|
673
700
|
sessionOpts.sessionVisibility = visibilityChoice.visibility;
|
|
674
701
|
if (msg.vendor) sessionOpts.vendor = msg.vendor;
|
|
702
|
+
if (isMate && msg._mateDefaultsToken === mateDefaultsToken) sessionOpts.model = msg.model;
|
|
675
703
|
// Mode resolution: vendors without a TUI session mode are always GUI.
|
|
676
704
|
// TUI-capable sessions honor the explicit msg.mode if provided, otherwise
|
|
677
705
|
// fall back to the user's claudeOpenMode preference. This is what
|
|
@@ -741,7 +769,10 @@ function attachSessions(ctx) {
|
|
|
741
769
|
sm.switchSession(newSess.localId, ws);
|
|
742
770
|
} else {
|
|
743
771
|
var newSessionVendor = sessionOpts.vendor || sm.defaultVendor || "claude";
|
|
744
|
-
|
|
772
|
+
var newSessionEffort = isMate && msg._mateDefaultsToken === mateDefaultsToken
|
|
773
|
+
? (msg.effort || "")
|
|
774
|
+
: ((sm.currentEffortByVendor && sm.currentEffortByVendor[newSessionVendor]) || sm.currentEffort || "medium");
|
|
775
|
+
sessionOpts.effort = yoke.clampEffort(newSessionVendor, newSessionEffort) || null;
|
|
745
776
|
// Reuse an existing blank GUI session instead of stacking another
|
|
746
777
|
// one. A vendor-less blank is acceptable: nothing has happened in it,
|
|
747
778
|
// so stamping the requested vendor is equivalent to a fresh create.
|
|
@@ -773,7 +804,7 @@ function attachSessions(ctx) {
|
|
|
773
804
|
// new_session without a vendor (mate sidebar, notification banner,
|
|
774
805
|
// debate) falls through to the default adapter and must not clobber
|
|
775
806
|
// the user's remembered pick.
|
|
776
|
-
if (msg.vendor && sm.lastVendor !== msg.vendor) {
|
|
807
|
+
if (msg.vendor && msg._mateDefaultsToken !== mateDefaultsToken && sm.lastVendor !== msg.vendor) {
|
|
777
808
|
sm.lastVendor = msg.vendor;
|
|
778
809
|
if (typeof opts.onSetProjectLastVendor === "function") {
|
|
779
810
|
opts.onSetProjectLastVendor(slug, msg.vendor);
|
|
@@ -810,6 +841,10 @@ function attachSessions(ctx) {
|
|
|
810
841
|
}
|
|
811
842
|
|
|
812
843
|
if (msg.type === "transfer_project_owner") {
|
|
844
|
+
if (isMate) {
|
|
845
|
+
sendTo(ws, { type: "error", text: "Clay and Mate ownership cannot be transferred." });
|
|
846
|
+
return true;
|
|
847
|
+
}
|
|
813
848
|
// Home directory projects: ownership is permanently locked
|
|
814
849
|
if (osUsers && osUsers.length > 0 && /^\/home\/[^/]+\//.test(cwd)) {
|
|
815
850
|
sendTo(ws, { type: "error", text: "Cannot transfer ownership of home directory projects." });
|
|
@@ -1603,6 +1638,7 @@ function attachSessions(ctx) {
|
|
|
1603
1638
|
var forked = sm.createSession({
|
|
1604
1639
|
vendor: session.vendor,
|
|
1605
1640
|
ownerId: session.ownerId || null,
|
|
1641
|
+
userKnowledgeOwnerId: session.userKnowledgeOwnerId || null,
|
|
1606
1642
|
sessionVisibility: sessionVisibility.normalize(session.sessionVisibility),
|
|
1607
1643
|
}, ws);
|
|
1608
1644
|
forked.cliSessionId = result.sessionId;
|
|
@@ -1627,6 +1663,7 @@ function attachSessions(ctx) {
|
|
|
1627
1663
|
title: forkTitle,
|
|
1628
1664
|
vendor: session.vendor,
|
|
1629
1665
|
ownerId: session.ownerId || null,
|
|
1666
|
+
userKnowledgeOwnerId: session.userKnowledgeOwnerId || null,
|
|
1630
1667
|
sessionVisibility: sessionVisibility.normalize(session.sessionVisibility),
|
|
1631
1668
|
sessionVisibilityExplicit: session.sessionVisibilityExplicit === true,
|
|
1632
1669
|
}, ws);
|