clay-server 3.8.1 → 4.0.0-beta.1

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 (182) hide show
  1. package/lib/ask-user-mcp-server.js +5 -119
  2. package/lib/builtin-mates.js +6 -6
  3. package/lib/claude-hook-installer.js +15 -0
  4. package/lib/clay-history-mcp-server.js +62 -297
  5. package/lib/daemon.js +1 -1
  6. package/lib/debate-model-selection.js +119 -0
  7. package/lib/home-debate-tool-policy.js +164 -0
  8. package/lib/home-response-notifications.js +26 -0
  9. package/lib/mate-creation-mcp-server.js +55 -0
  10. package/lib/mate-ready-creation.js +95 -0
  11. package/lib/mates.js +2 -0
  12. package/lib/notes.js +2 -1
  13. package/lib/project-ask-user.js +64 -0
  14. package/lib/project-capsule-catalog.js +101 -0
  15. package/lib/project-debate-proposal.js +133 -17
  16. package/lib/project-debate.js +214 -110
  17. package/lib/project-delegated-follow-up.js +84 -0
  18. package/lib/project-delegated-session.js +53 -0
  19. package/lib/project-filesystem.js +7 -9
  20. package/lib/project-knowledge.js +1 -0
  21. package/lib/project-mate-creation-proposal.js +120 -0
  22. package/lib/project-memory.js +14 -7
  23. package/lib/project-models.js +157 -32
  24. package/lib/project-session-notes.js +2 -2
  25. package/lib/project-session-pair.js +8 -8
  26. package/lib/project-sessions.js +66 -51
  27. package/lib/project-worker-proposal.js +25 -25
  28. package/lib/project-workspace-query.js +144 -0
  29. package/lib/project.js +329 -102
  30. package/lib/public/app.js +85 -42
  31. package/lib/public/css/avatar-imprints.css +0 -1
  32. package/lib/public/css/base.css +4 -0
  33. package/lib/public/css/capsule-ui.css +389 -0
  34. package/lib/public/css/command-palette.css +306 -6
  35. package/lib/public/css/home-capsule-library.css +243 -0
  36. package/lib/public/css/home-capsule-source.css +192 -0
  37. package/lib/public/css/home-debate-live.css +146 -0
  38. package/lib/public/css/home-debate-planning.css +125 -0
  39. package/lib/public/css/home-debates-archive.css +281 -0
  40. package/lib/public/css/home-hub.css +896 -405
  41. package/lib/public/css/home-mate-creation.css +34 -0
  42. package/lib/public/css/home-mate-model-picker.css +131 -0
  43. package/lib/public/css/home-mate-settings.css +344 -0
  44. package/lib/public/css/home-session-actions.css +265 -0
  45. package/lib/public/css/home-sidebar.css +667 -0
  46. package/lib/public/css/icon-strip.css +1 -2
  47. package/lib/public/css/mates.css +7 -34
  48. package/lib/public/css/pane.css +1 -1
  49. package/lib/public/css/playbook.css +0 -80
  50. package/lib/public/css/sticky-notes.css +53 -117
  51. package/lib/public/css/tui-attention.css +0 -44
  52. package/lib/public/css/workspace-assignment.css +45 -0
  53. package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
  54. package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
  55. package/lib/public/index.html +93 -74
  56. package/lib/public/modules/app-connection.js +10 -1
  57. package/lib/public/modules/app-dm.js +43 -160
  58. package/lib/public/modules/app-home-hub.js +328 -585
  59. package/lib/public/modules/app-message-cards.js +242 -0
  60. package/lib/public/modules/app-message-router.js +84 -0
  61. package/lib/public/modules/app-messages.js +78 -20
  62. package/lib/public/modules/app-notifications.js +4 -2
  63. package/lib/public/modules/app-projects.js +9 -1
  64. package/lib/public/modules/app-rendering.js +21 -602
  65. package/lib/public/modules/avatar-imprint.js +11 -8
  66. package/lib/public/modules/chat-bubble-renderer.js +152 -0
  67. package/lib/public/modules/chat-render-runtime.js +198 -0
  68. package/lib/public/modules/command-palette.js +225 -436
  69. package/lib/public/modules/dm-render.js +82 -0
  70. package/lib/public/modules/home-capsule-creation-intent.js +31 -0
  71. package/lib/public/modules/home-capsule-library.js +146 -0
  72. package/lib/public/modules/home-capsule-source.js +383 -0
  73. package/lib/public/modules/home-chat-identity.js +35 -0
  74. package/lib/public/modules/home-chat-scroll.js +77 -0
  75. package/lib/public/modules/home-chat-stream-state.js +34 -0
  76. package/lib/public/modules/home-composer-focus.js +25 -0
  77. package/lib/public/modules/home-conversations-sheet.js +179 -0
  78. package/lib/public/modules/home-debate-activity.js +48 -0
  79. package/lib/public/modules/home-debate-controls.js +295 -0
  80. package/lib/public/modules/home-debate-launch.js +41 -0
  81. package/lib/public/modules/home-debate-live.js +284 -0
  82. package/lib/public/modules/home-debate-models.js +73 -0
  83. package/lib/public/modules/home-debate-planning.js +335 -0
  84. package/lib/public/modules/home-debates-archive.js +279 -0
  85. package/lib/public/modules/home-dock-resize.js +74 -0
  86. package/lib/public/modules/home-dock.js +446 -0
  87. package/lib/public/modules/home-mate-chat.js +496 -0
  88. package/lib/public/modules/home-mate-creation.js +109 -0
  89. package/lib/public/modules/home-mate-model-picker.js +281 -0
  90. package/lib/public/modules/home-mate-selection.js +38 -0
  91. package/lib/public/modules/home-mate-settings-menu.js +131 -0
  92. package/lib/public/modules/home-mate-settings.js +383 -0
  93. package/lib/public/modules/home-session-actions.js +373 -0
  94. package/lib/public/modules/home-session-model-confirmation.js +13 -0
  95. package/lib/public/modules/home-shell.js +9 -0
  96. package/lib/public/modules/home-sidebar-chat-list.js +63 -0
  97. package/lib/public/modules/home-sidebar.js +158 -0
  98. package/lib/public/modules/home-sub-surface.js +19 -0
  99. package/lib/public/modules/home-surface-boot.js +68 -0
  100. package/lib/public/modules/home-surface.js +141 -0
  101. package/lib/public/modules/home-tools.js +271 -0
  102. package/lib/public/modules/markdown.js +50 -2
  103. package/lib/public/modules/mate-management.js +86 -0
  104. package/lib/public/modules/mate-wizard.js +0 -7
  105. package/lib/public/modules/mention.js +17 -19
  106. package/lib/public/modules/profile.js +4 -5
  107. package/lib/public/modules/project-settings.js +34 -28
  108. package/lib/public/modules/project-switcher.js +11 -5
  109. package/lib/public/modules/project-workspace-assignment.js +23 -0
  110. package/lib/public/modules/search-clay-chat.js +402 -0
  111. package/lib/public/modules/server-settings.js +14 -12
  112. package/lib/public/modules/session-actions.js +1 -1
  113. package/lib/public/modules/sidebar-mates.js +56 -552
  114. package/lib/public/modules/sidebar-mobile.js +7 -64
  115. package/lib/public/modules/sidebar-presence.js +37 -0
  116. package/lib/public/modules/split-pair-ui.js +13 -13
  117. package/lib/public/modules/sticky-notes.js +7 -6
  118. package/lib/public/modules/tool-input-composition.js +48 -0
  119. package/lib/public/modules/tool-llm-status.js +167 -0
  120. package/lib/public/modules/tool-renderer-advanced.js +285 -0
  121. package/lib/public/modules/tool-renderer-chart.js +158 -0
  122. package/lib/public/modules/tool-renderer-semantics.js +35 -0
  123. package/lib/public/modules/tool-renderer.js +464 -0
  124. package/lib/public/modules/tool-runtime.js +309 -0
  125. package/lib/public/modules/tool-ui-evaluator.js +97 -0
  126. package/lib/public/modules/tool-ui-tree.js +21 -0
  127. package/lib/public/modules/user-settings.js +16 -23
  128. package/lib/public/modules/worker-proposal.js +2 -2
  129. package/lib/public/modules/workspace-assignment-card.js +149 -0
  130. package/lib/public/modules/workspace-assignment-routing.js +4 -0
  131. package/lib/public/style.css +13 -2
  132. package/lib/runtime-env.js +65 -0
  133. package/lib/sdk-bridge.js +120 -32
  134. package/lib/sdk-message-processor.js +10 -6
  135. package/lib/server-home-capsule-creation.js +36 -0
  136. package/lib/server-home-chat-events.js +287 -0
  137. package/lib/server-home-chat.js +518 -0
  138. package/lib/server-home-clay-entry.js +65 -0
  139. package/lib/server-home-clay-session-links.js +26 -0
  140. package/lib/server-home-debate-planning.js +214 -0
  141. package/lib/server-home-debates.js +137 -0
  142. package/lib/server-home-mate-creation.js +261 -0
  143. package/lib/server-home-models.js +241 -0
  144. package/lib/server-home-preferences.js +61 -0
  145. package/lib/server-mates.js +37 -0
  146. package/lib/server-tools.js +377 -0
  147. package/lib/server.js +111 -59
  148. package/lib/session-pair-mcp-server.js +6 -6
  149. package/lib/sessions.js +18 -3
  150. package/lib/tool-capsule-source.js +142 -0
  151. package/lib/tool-control-mcp-server.js +126 -0
  152. package/lib/tool-llm.js +48 -0
  153. package/lib/tool-storage.js +77 -0
  154. package/lib/tool-ui-spec-advanced.js +82 -0
  155. package/lib/tool-ui-spec.js +261 -0
  156. package/lib/tools-registry.js +276 -0
  157. package/lib/users-home-dock-preferences.js +77 -0
  158. package/lib/users-home-surface-preferences.js +99 -0
  159. package/lib/users-preferences.js +4 -7
  160. package/lib/users.js +12 -0
  161. package/lib/whats-new-content.js +3 -3
  162. package/lib/workspace-assignment-service.js +420 -0
  163. package/lib/workspace-query-mcp-server.js +154 -0
  164. package/lib/workspace-query-service.js +492 -0
  165. package/lib/ws-schema.js +86 -12
  166. package/lib/yoke/adapters/acp.js +2 -1
  167. package/lib/yoke/adapters/antigravity.js +2 -1
  168. package/lib/yoke/adapters/claude-worker.js +11 -4
  169. package/lib/yoke/adapters/claude.js +73 -43
  170. package/lib/yoke/adapters/codex.js +37 -6
  171. package/lib/yoke/adapters/kiro.js +2 -1
  172. package/lib/yoke/claude-user-input.js +38 -0
  173. package/lib/yoke/codex-user-input.js +64 -0
  174. package/lib/yoke/complete-once.js +164 -0
  175. package/lib/yoke/index.js +5 -1
  176. package/lib/yoke/interface.js +19 -0
  177. package/lib/yoke/mcp-bridge-server.js +2 -6
  178. package/lib/yoke/user-input.js +254 -0
  179. package/package.json +2 -1
  180. package/lib/public/css/home-chat.css +0 -380
  181. package/lib/public/modules/home-chat.js +0 -438
  182. package/lib/server-clay-home.js +0 -245
package/lib/project.js CHANGED
@@ -5,18 +5,22 @@ var crypto = require("crypto");
5
5
  var { createSessionManager } = require("./sessions");
6
6
  var { attachGitSessionAttribution } = require("./git-session-attribution");
7
7
  var { createSDKBridge, createMessageQueue } = require("./sdk-bridge");
8
+ var runtimeEnv = require("./runtime-env");
8
9
  var { createTerminalManager } = require("./terminal-manager");
9
10
  var { createNotesManager } = require("./notes");
10
11
  var { fetchLatestVersion, fetchVersion, isNewer } = require("./updater");
11
12
  var { execFileSync, spawn } = require("child_process");
12
13
  var usersModule = require("./users");
13
14
  var { resolveOsUserInfo, fsAsUser, grantProjectAccess } = require("./os-users");
15
+ var { buildUserEnv } = require("./build-user-env");
14
16
  var crisisSafety = require("./crisis-safety");
15
17
  var matesModule = require("./mates");
16
18
  var sessionSearch = require("./session-search");
17
19
  var userPresence = require("./user-presence");
18
20
  var { attachDebate } = require("./project-debate");
19
21
  var { attachDebateProposal } = require("./project-debate-proposal");
22
+ var { attachMateCreationProposal } = require("./project-mate-creation-proposal");
23
+ var { attachAskUser } = require("./project-ask-user");
20
24
  var { attachMemory } = require("./project-memory");
21
25
  var { attachMateInteraction } = require("./project-mate-interaction");
22
26
  var { attachUserMention } = require("./project-user-mention");
@@ -35,13 +39,68 @@ var { attachMcp } = require("./project-mcp");
35
39
  var { createLocalMcp } = require("./mcp-local");
36
40
  var { attachEmail: attachEmailModule } = require("./project-email");
37
41
  var { attachSessionSpawn } = require("./project-session-spawn");
42
+ var { attachDelegatedSession } = require("./project-delegated-session");
43
+ var { attachDelegatedFollowUp } = require("./project-delegated-follow-up");
44
+ var workspaceSessionRef = require("./workspace-query-service").sessionRef;
38
45
  var { attachSessionPair } = require("./project-session-pair");
39
46
  var { attachSessionHandoff } = require("./project-session-handoff");
40
47
  var { attachSessionNotes, composeSystemPrompts } = require("./project-session-notes");
41
48
  var { attachSessionDocument } = require("./project-session-document");
49
+ var { attachCapsuleCatalog } = require("./project-capsule-catalog");
50
+ var { attachProjectWorkspaceQuery } = require("./project-workspace-query");
42
51
  var { attachSplitGroups } = require("./session-split-groups");
52
+ var toolControlMcp = require("./tool-control-mcp-server");
53
+ var toolLlm = require("./tool-llm");
43
54
  // project-notifications is attached globally in server.js, passed via opts.notificationsModule
44
55
 
56
+ function createMateToolControlMcp(adapter, config) {
57
+ if (!adapter || typeof adapter.createToolServer !== "function") return null;
58
+ var handlers = {
59
+ list: function () {
60
+ var manifests = config.list(config.userId) || [];
61
+ var tools = [];
62
+ for (var i = 0; i < manifests.length; i++) {
63
+ tools.push({
64
+ id: manifests[i].id,
65
+ name: manifests[i].name,
66
+ description: manifests[i].description || "",
67
+ useWhen: manifests[i].useWhen || "",
68
+ runtime: manifests[i].runtime || "worker",
69
+ permissions: manifests[i].permissions || [],
70
+ skills: manifests[i].skills || "",
71
+ });
72
+ }
73
+ return tools;
74
+ },
75
+ snapshot: function (toolId) {
76
+ return config.control(config.userId, config.mateId, toolId, "snapshot", {});
77
+ },
78
+ act: function (toolId, actionId, args) {
79
+ return config.control(config.userId, config.mateId, toolId, "act", { actionId: actionId, args: args });
80
+ },
81
+ set: function (toolId, controlId, value) {
82
+ return config.control(config.userId, config.mateId, toolId, "set", { controlId: controlId, value: value });
83
+ },
84
+ source: function (toolId) {
85
+ return config.source(config.userId, toolId);
86
+ },
87
+ install: function (input) {
88
+ return config.install(config.userId, input);
89
+ },
90
+ update: function (toolId, input) {
91
+ return config.update(config.userId, toolId, input);
92
+ },
93
+ uninstall: function (toolId) {
94
+ return config.remove(config.userId, toolId);
95
+ },
96
+ };
97
+ return adapter.createToolServer({
98
+ name: "clay-tools",
99
+ version: "1.0.0",
100
+ tools: toolControlMcp.getToolDefs(handlers),
101
+ });
102
+ }
103
+
45
104
  // --- Context Sources persistence ---
46
105
  var _ctxSrcConfig = require("./config");
47
106
  var _ctxSrcDir = path.join(_ctxSrcConfig.CONFIG_DIR, "context-sources");
@@ -73,26 +132,7 @@ function saveContextSources(slug, sessionId, activeIds) {
73
132
  // Validate environment variable string (KEY=VALUE per line)
74
133
  // Returns null if valid, or an error string if invalid
75
134
  function validateEnvString(str) {
76
- if (!str || !str.trim()) return null;
77
- var lines = str.split("\n");
78
- for (var i = 0; i < lines.length; i++) {
79
- var line = lines[i].trim();
80
- if (!line || line.charAt(0) === "#") continue;
81
- // Must be KEY=VALUE format
82
- var eqIdx = line.indexOf("=");
83
- if (eqIdx < 1) return "Invalid format at line " + (i + 1) + ": expected KEY=VALUE";
84
- var key = line.substring(0, eqIdx);
85
- // Key must be valid env var name (no shell metacharacters)
86
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
87
- return "Invalid variable name at line " + (i + 1) + ": " + key;
88
- }
89
- // Value must not contain shell injection characters
90
- var value = line.substring(eqIdx + 1);
91
- if (/[`$\\;|&><(){}\n]/.test(value) && !/^["'].*["']$/.test(value)) {
92
- return "Potentially unsafe value at line " + (i + 1) + ": shell metacharacters detected";
93
- }
94
- }
95
- return null;
135
+ return runtimeEnv.validateEnvString(str);
96
136
  }
97
137
 
98
138
  // YOKE adapter (replaces direct SDK access)
@@ -153,8 +193,6 @@ function createProjectContext(opts) {
153
193
  var lanHost = opts.lanHost || null;
154
194
  var getProjectCount = opts.getProjectCount || function () { return 1; };
155
195
  var getProjectList = opts.getProjectList || function () { return []; };
156
- var getAllProjectSessions = opts.getAllProjectSessions || function () { return []; };
157
- var getAllProjectsWithSessions = opts.getAllProjectsWithSessions || function () { return []; };
158
196
  var isHostAgent = !!opts.isHostAgent;
159
197
  var getHubSchedules = opts.getHubSchedules || function () { return []; };
160
198
  var moveScheduleToProject = opts.moveScheduleToProject || function () { return { ok: false, error: "Not supported" }; };
@@ -168,6 +206,23 @@ function createProjectContext(opts) {
168
206
  var projectOwnerId = opts.projectOwnerId || null;
169
207
  var worktreeMeta = opts.worktreeMeta || null; // { parentSlug, branch, external }
170
208
  var isMate = opts.isMate || false;
209
+ var mateId = opts.mateId || (isMate ? path.basename(cwd) : null);
210
+ var listControllableTools = opts.listControllableTools || function () { return []; };
211
+ var controlToolForMate = opts.controlToolForMate || function () {
212
+ return Promise.reject(new Error("Tool control is unavailable."));
213
+ };
214
+ var installToolForMate = opts.installToolForMate || function () {
215
+ return Promise.reject(new Error("Tool installation is unavailable."));
216
+ };
217
+ var sourceToolForMate = opts.sourceToolForMate || function () {
218
+ return Promise.reject(new Error("Capsule source access is unavailable."));
219
+ };
220
+ var updateToolForMate = opts.updateToolForMate || function () {
221
+ return Promise.reject(new Error("Capsule source updates are unavailable."));
222
+ };
223
+ var removeToolForMate = opts.removeToolForMate || function () {
224
+ return Promise.reject(new Error("Tool removal is unavailable."));
225
+ };
171
226
  var onCreateWorktree = opts.onCreateWorktree || null;
172
227
  var serverPort = opts.port || 2633;
173
228
  var serverTls = opts.tls || false;
@@ -219,8 +274,7 @@ function createProjectContext(opts) {
219
274
 
220
275
  // Cache resolved OS user info to avoid repeated getent calls
221
276
  var osUserInfoCache = {};
222
- function getOsUserInfoForWs(ws) {
223
- var linuxUser = getLinuxUserForWs(ws);
277
+ function getOsUserInfoForLinuxUser(linuxUser) {
224
278
  if (!linuxUser) return null;
225
279
  if (osUserInfoCache[linuxUser]) return osUserInfoCache[linuxUser];
226
280
  try {
@@ -233,23 +287,34 @@ function createProjectContext(opts) {
233
287
  }
234
288
  }
235
289
 
290
+ function getOsUserInfoForWs(ws) {
291
+ var linuxUser = getLinuxUserForWs(ws);
292
+ return getOsUserInfoForLinuxUser(linuxUser);
293
+ }
294
+
236
295
  function getOsUserInfoForReq(req) {
237
296
  if (!osUsers) return null;
238
297
  if (!req._clayUser || !req._clayUser.linuxUser) return null;
239
298
  var linuxUser = req._clayUser.linuxUser;
240
- if (osUserInfoCache[linuxUser]) return osUserInfoCache[linuxUser];
241
- try {
242
- var info = resolveOsUserInfo(linuxUser);
243
- osUserInfoCache[linuxUser] = info;
244
- return info;
245
- } catch (e) {
246
- console.error("[project] Failed to resolve OS user info for " + linuxUser + ":", e.message);
247
- return null;
248
- }
299
+ return getOsUserInfoForLinuxUser(linuxUser);
300
+ }
301
+
302
+ function getRuntimeEnvForSession(session) {
303
+ var linuxUser = (session && session.linuxUser) || getLinuxUserForSession(session);
304
+ var osUserInfo = getOsUserInfoForLinuxUser(linuxUser);
305
+ var baseEnv = osUserInfo ? buildUserEnv(osUserInfo) : process.env;
306
+ var shared = typeof opts.onGetSharedEnv === "function" ? opts.onGetSharedEnv() : null;
307
+ var projectEnv = typeof opts.onGetProjectEnv === "function" ? opts.onGetProjectEnv(slug) : null;
308
+ return runtimeEnv.resolveRuntimeEnv({
309
+ baseEnv: baseEnv,
310
+ sharedEnvrc: shared && shared.envrc,
311
+ projectEnvrc: projectEnv && projectEnv.envrc,
312
+ });
249
313
  }
250
314
 
251
315
  // --- Per-project clients ---
252
316
  var clients = new Set();
317
+ var homeDebateClients = new Set();
253
318
 
254
319
  // --- Browser extension state (shared mutable object) ---
255
320
  var _extToken = crypto.randomUUID(); // Auth token for MCP server bridge
@@ -369,6 +434,10 @@ function createProjectContext(opts) {
369
434
  ws.send(data);
370
435
  }
371
436
  }
437
+ homeDebateClients.forEach(function (ws) {
438
+ if (ws.readyState !== 1) { homeDebateClients.delete(ws); return; }
439
+ if (!clients.has(ws) && ws._clayHomeDebateSlug === slug && ws._clayActiveSession === sessionId) ws.send(data);
440
+ });
372
441
  }
373
442
 
374
443
  function sendToSessionOthers(sender, sessionId, obj) {
@@ -537,6 +606,23 @@ function createProjectContext(opts) {
537
606
  },
538
607
  fsAsUser: fsAsUser,
539
608
  });
609
+ var _capsuleCatalog = attachCapsuleCatalog({
610
+ isMate: isMate,
611
+ listManifests: listControllableTools,
612
+ getUserId: function (session) {
613
+ return (session && session.ownerId) || projectOwnerId || "default";
614
+ },
615
+ getSdk: function () { return sdk; },
616
+ getSessions: function () { return sm.sessions; },
617
+ });
618
+ var _workspaceQuery = attachProjectWorkspaceQuery({
619
+ service: opts.workspaceQueryService || null,
620
+ sm: sm,
621
+ projectSlug: slug,
622
+ getProjectOwnerId: function () { return projectOwnerId; },
623
+ isMate: isMate,
624
+ mateId: mateId,
625
+ });
540
626
 
541
627
  // The SDK bridge is created after local MCP servers. Session spawning uses
542
628
  // a getter so tool handlers see the initialized bridge when they run.
@@ -587,15 +673,46 @@ function createProjectContext(opts) {
587
673
  var _debateProposal = attachDebateProposal({
588
674
  cwd: cwd,
589
675
  isMate: isMate,
676
+ isHostAgent: isHostAgent,
590
677
  sendTo: sendTo,
591
678
  buildMateCtx: matesModule.buildMateCtx,
592
679
  getMate: matesModule.getMate,
593
680
  getProjectOwnerId: function () { return projectOwnerId; },
681
+ getVendorModelCatalog: function (ws, vendor) { return _models.getVendorCatalog(ws, vendor); },
682
+ getVendorModelCatalogForSession: function (session, vendor) {
683
+ var user = session && session.ownerId ? usersModule.findUserById(session.ownerId) : null;
684
+ return _models.getVendorCatalog({ _clayUser: user || null }, vendor);
685
+ },
594
686
  startDebate: function (session, briefData, moderatorId, ws) {
595
687
  if (!_debate) return { error: "The debate engine is unavailable." };
596
688
  return _debate.handleMcpDebateApproval(session, briefData, moderatorId, ws);
597
689
  },
690
+ recordSessionEvent: function (session, event) { sm.sendAndRecord(session, event); },
691
+ });
692
+ var _mateCreationProposal = attachMateCreationProposal({
693
+ isMate: isMate,
694
+ isHostAgent: isHostAgent,
695
+ isMultiUser: usersModule.isMultiUser,
696
+ getProjectOwnerId: function () { return projectOwnerId; },
697
+ recordSessionEvent: function (session, event) { sm.sendAndRecord(session, event); },
698
+ getVendorModelCatalog: function (ws, vendor) { return _models.getVendorCatalog(ws, vendor); },
699
+ createReadyMate: opts.createReadyMate,
598
700
  });
701
+ var _askUser = attachAskUser({ record: function (session, event) { sm.sendAndRecord(session, event); } });
702
+
703
+ function createToolControlMcpServer() {
704
+ if (!isMate || !adapter || typeof adapter.createToolServer !== "function") return null;
705
+ return createMateToolControlMcp(adapter, {
706
+ userId: projectOwnerId || "default",
707
+ mateId: path.basename(cwd),
708
+ list: listControllableTools,
709
+ control: controlToolForMate,
710
+ source: sourceToolForMate,
711
+ install: installToolForMate,
712
+ update: updateToolForMate,
713
+ remove: removeToolForMate,
714
+ });
715
+ }
599
716
 
600
717
  // --- MCP tool servers (created via YOKE adapter) ---
601
718
  var mcpServers = (function () {
@@ -649,77 +766,39 @@ function createProjectContext(opts) {
649
766
  console.error("[project] Failed to create debate MCP server:", e.message);
650
767
  }
651
768
 
652
- // Clay-history MCP server (host agent only — Clay mate)
653
- // Gives Clay BM25 search + targeted reads across the user's full
654
- // workspace. Read-only. Other Mates and project sessions never see
655
- // these tools because the gate is the isHostAgent project flag.
656
- if (isHostAgent) {
769
+ if (isMate && isHostAgent) {
657
770
  try {
658
- var clayHistoryMcp = require("./clay-history-mcp-server");
659
- var clayHistoryToolDefs = clayHistoryMcp.getToolDefs({
660
- getAllProjectsWithSessions: getAllProjectsWithSessions,
661
- });
662
- var clayHistoryMcpConfig = adapter.createToolServer({ name: "clay-history", version: "1.0.0", tools: clayHistoryToolDefs });
663
- if (clayHistoryMcpConfig) servers[clayHistoryMcpConfig.name || "clay-history"] = clayHistoryMcpConfig;
771
+ var mateCreationMcpConfig = _mateCreationProposal.createMcpServer(adapter, null);
772
+ if (mateCreationMcpConfig) servers[mateCreationMcpConfig.name || "clay-mate-creation"] = mateCreationMcpConfig;
664
773
  } catch (e) {
665
- console.error("[project] Failed to create clay-history MCP server:", e.message);
774
+ console.error("[project] Failed to create Mate creation MCP server:", e.message);
666
775
  }
667
776
  }
668
777
 
669
- // Ask-user MCP server (mates only)
778
+ // Owner-bound workspace inspection is available only inside Mate
779
+ // projects. The server-side Mate registry decides whether the wider
780
+ // builtin Clay tools are present; project flags and tool arguments do not.
670
781
  if (isMate) {
671
782
  try {
672
- var askUserMcp = require("./ask-user-mcp-server");
673
- var askUserToolDefs = askUserMcp.getToolDefs(function onAsk(input) {
674
- // Stateless: the tool's job is to *post* the question card.
675
- // We do NOT hold a promise open waiting for the user. When the
676
- // user answers, the answer is injected as a fresh user message
677
- // on the next turn (see project-sessions.js ask_user_response).
678
- // This avoids HTTP long-poll timeouts on the MCP bridge and
679
- // matches the natural multi-turn agent loop.
680
- var session = sm.getActiveSession();
681
- if (!session) {
682
- // No active session means we have no way to show a card or
683
- // route the answer. Fail closed rather than pretend success.
684
- return Promise.resolve({
685
- content: [{ type: "text", text: "Error: no active session in " + slug + "; cannot display question card." }],
686
- isError: true,
687
- });
688
- }
689
- if (session.loop && session.loop.active && session.loop.role !== "crafting") {
690
- return Promise.resolve({
691
- content: [{ type: "text", text: "Error: Autonomous mode. Make your own decision." }],
692
- isError: true,
693
- });
694
- }
783
+ var workspaceMcpConfig = _workspaceQuery.createMcpServer(adapter, null);
784
+ if (workspaceMcpConfig) servers[workspaceMcpConfig.name || "clay-workspace"] = workspaceMcpConfig;
785
+ } catch (e) {
786
+ console.error("[project] Failed to create clay-workspace MCP server:", e.message);
787
+ }
788
+ try {
789
+ var clayHistoryMcpConfig = _workspaceQuery.createHistoryMcpServer(adapter, null);
790
+ if (clayHistoryMcpConfig) servers[clayHistoryMcpConfig.name || "clay-history"] = clayHistoryMcpConfig;
791
+ } catch (e) {
792
+ console.error("[project] Failed to create Clay history compatibility server:", e.message);
793
+ }
794
+ }
695
795
 
696
- var toolId = "ask_" + Date.now() + "_" + crypto.randomUUID().slice(0, 8);
697
- // Track for UI card lifecycle + answer routing. No resolve function.
698
- session.pendingAskUser[toolId] = {
699
- input: input,
700
- mode: "mcp",
701
- sessionId: session.localId,
702
- postedAt: Date.now(),
703
- };
704
-
705
- sm.sendAndRecord(session, {
706
- type: "tool_executing",
707
- id: toolId,
708
- name: "AskUserQuestion",
709
- input: input,
710
- });
711
-
712
- return Promise.resolve({
713
- content: [{
714
- type: "text",
715
- text: "The question card has been posted to the user. End this turn now without further commentary; the user's answer will arrive as the next user message, prefixed with \"[Answer to your AskUserQuestion]\" so you can recognize it.",
716
- }],
717
- });
718
- });
719
- var askUserMcpConfig = adapter.createToolServer({ name: "clay-ask-user", version: "1.0.0", tools: askUserToolDefs });
720
- if (askUserMcpConfig) servers[askUserMcpConfig.name || "clay-ask-user"] = askUserMcpConfig;
796
+ if (isMate) {
797
+ try {
798
+ var toolControlMcpConfig = createToolControlMcpServer();
799
+ if (toolControlMcpConfig) servers[toolControlMcpConfig.name || "clay-tools"] = toolControlMcpConfig;
721
800
  } catch (e) {
722
- console.error("[project] Failed to create ask-user MCP server:", e.message);
801
+ console.error("[project] Failed to create clay-tools MCP server:", e.message);
723
802
  }
724
803
  }
725
804
 
@@ -805,6 +884,33 @@ function createProjectContext(opts) {
805
884
  var name = keys[i];
806
885
  if (name === "clay-browser" && !extConnected) continue;
807
886
  if (name === "clay-email" && !emailAvailable) continue;
887
+ if (name === "clay-workspace" && forSession) {
888
+ try {
889
+ var boundWorkspace = _workspaceQuery.createMcpServer(adapter, forSession);
890
+ if (boundWorkspace) { filtered[name] = boundWorkspace; hasAny = true; }
891
+ } catch (e) {
892
+ console.error("[project] Failed to bind clay-workspace MCP server:", e.message);
893
+ }
894
+ continue;
895
+ }
896
+ if (name === "clay-history" && forSession) {
897
+ try {
898
+ var boundHistory = _workspaceQuery.createHistoryMcpServer(adapter, forSession);
899
+ if (boundHistory) { filtered[name] = boundHistory; hasAny = true; }
900
+ } catch (e) {
901
+ console.error("[project] Failed to bind Clay history compatibility server:", e.message);
902
+ }
903
+ continue;
904
+ }
905
+ if (name === "clay-tools" && forSession) {
906
+ try {
907
+ var boundToolControl = createToolControlMcpServer();
908
+ if (boundToolControl) { filtered[name] = boundToolControl; hasAny = true; }
909
+ } catch (e) {
910
+ console.error("[project] Failed to bind clay-tools MCP server:", e.message);
911
+ }
912
+ continue;
913
+ }
808
914
  if (name === "clay-sessions" && forSession) {
809
915
  try {
810
916
  var boundSpawn = _sessionSpawn.createMcpServer(adapter, forSession);
@@ -850,6 +956,15 @@ function createProjectContext(opts) {
850
956
  }
851
957
  continue;
852
958
  }
959
+ if (name === "clay-mate-creation" && forSession) {
960
+ try {
961
+ var boundMateCreation = _mateCreationProposal.createMcpServer(adapter, forSession);
962
+ if (boundMateCreation) { filtered[name] = boundMateCreation; hasAny = true; }
963
+ } catch (e) {
964
+ console.error("[project] Failed to bind Mate creation MCP server:", e.message);
965
+ }
966
+ continue;
967
+ }
853
968
  filtered[name] = mcpServers[name];
854
969
  hasAny = true;
855
970
  }
@@ -866,6 +981,7 @@ function createProjectContext(opts) {
866
981
  adapter: adapter,
867
982
  adapters: adapters,
868
983
  getNotificationsModule: function () { return _notifications; },
984
+ shouldSuppressResponseNotification: opts.shouldSuppressResponseNotification,
869
985
  mateDisplayName: opts.mateDisplayName || "",
870
986
  isMate: isMate,
871
987
  osUsers: osUsers,
@@ -879,6 +995,7 @@ function createProjectContext(opts) {
879
995
  onTurnDone: function (session, preview) {
880
996
  if (isMate) digestDmTurn(session, preview);
881
997
  else _sessionPair.handleTurnDone(session);
998
+ if (session && typeof session.onTurnDone === "function") session.onTurnDone(session, preview);
882
999
  },
883
1000
  scheduleMessage: function (session, text, resetsAt) {
884
1001
  scheduleMessage(session, text, resetsAt);
@@ -902,13 +1019,22 @@ function createProjectContext(opts) {
902
1019
  _sessionNotes.getSystemPrompt(session),
903
1020
  _sessionHandoff.getSystemPrompt(session),
904
1021
  _sessionDocument.getSystemPrompt(session),
1022
+ _capsuleCatalog.getSystemPrompt(session),
905
1023
  ]);
906
1024
  },
1025
+ getRuntimeEnv: getRuntimeEnvForSession,
1026
+ onUserInputRequest: function (session, request, respond) {
1027
+ return _askUser.createHandler(session)(request, respond);
1028
+ },
907
1029
  getSessionToolDefs: function (session) {
908
1030
  return _sessionPair.getToolDefs(session)
909
1031
  .concat(_sessionNotes.getToolDefs(session))
910
1032
  .concat(_sessionHandoff.getToolDefs(session))
911
- .concat(_sessionDocument.getToolDefs(session));
1033
+ .concat(_sessionDocument.getToolDefs(session))
1034
+ .concat(_debateProposal.getToolDefs(session))
1035
+ .concat(_mateCreationProposal.getToolDefs(session))
1036
+ .concat(_workspaceQuery.getDynamicToolDefs(session))
1037
+ .concat(_workspaceQuery.getHistoryDynamicToolDefs(session));
912
1038
  },
913
1039
  });
914
1040
 
@@ -1042,6 +1168,11 @@ function createProjectContext(opts) {
1042
1168
  }
1043
1169
 
1044
1170
  function handleMessage(ws, msg) {
1171
+ if (ws._clayHomeDebateSlug && ws._clayHomeDebateSlug !== slug && /^debate_(hand_raise|comment|stop|conclude_response|user_floor_response)$/.test(msg.type || "") && opts.getProject) {
1172
+ var homeDebateCtx = opts.getProject(ws._clayHomeDebateSlug);
1173
+ if (homeDebateCtx) homeDebateCtx.handleMessage(ws, msg);
1174
+ return;
1175
+ }
1045
1176
  // --- Cross-project routing (e.g. permission_response from notification banner) ---
1046
1177
  if (msg.targetSlug && msg.targetSlug !== slug && opts.getProject) {
1047
1178
  var targetCtx = opts.getProject(msg.targetSlug);
@@ -1052,9 +1183,17 @@ function createProjectContext(opts) {
1052
1183
  }
1053
1184
 
1054
1185
  // --- DM messages (delegated to server-level handler) ---
1055
- if (msg.type === "dm_open" || msg.type === "dm_send" || msg.type === "dm_list" || msg.type === "dm_typing" || msg.type === "dm_add_favorite" || msg.type === "dm_remove_favorite" || msg.type === "mate_create" || msg.type === "mate_list" || msg.type === "mate_delete" || msg.type === "mate_update" || msg.type === "mate_readd_builtin" || msg.type === "mate_list_available_builtins" || msg.type === "email_accounts_list" || msg.type === "email_account_add" || msg.type === "email_account_remove" || msg.type === "email_account_test" || msg.type === "home_clay_open" || msg.type === "home_clay_send" || msg.type === "home_clay_new_session" || msg.type === "home_clay_close") {
1186
+ if (msg.type === "home_debate_question_response" || msg.type === "home_debate_control" || msg.type === "home_mate_creation_question_response") {
1187
+ if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg);
1188
+ return;
1189
+ }
1190
+ if (msg.type === "home_clay_ask" || msg.type === "home_clay_session_resolve") {
1191
+ if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg, slug);
1192
+ return;
1193
+ }
1194
+ if (msg.type === "project_assignment_response" || msg.type === "dm_open" || msg.type === "dm_send" || msg.type === "dm_list" || msg.type === "dm_typing" || msg.type === "dm_add_favorite" || msg.type === "dm_remove_favorite" || msg.type === "mate_create" || msg.type === "mate_list" || msg.type === "mate_delete" || msg.type === "mate_update" || msg.type === "mate_readd_builtin" || msg.type === "mate_list_available_builtins" || msg.type === "email_accounts_list" || msg.type === "email_account_add" || msg.type === "email_account_remove" || msg.type === "email_account_test" || msg.type === "home_debates_list" || msg.type === "home_mate_present" || msg.type === "home_mate_open" || msg.type === "home_mate_sessions_list" || msg.type === "home_mate_session_open" || msg.type === "home_mate_send" || msg.type === "home_mate_new_session" || msg.type === "home_mate_debate_plan" || msg.type === "home_debate_proposal_response" || msg.type === "home_mate_creation_plan" || msg.type === "home_mate_creation_proposal_response" || msg.type === "home_mate_close" || msg.type === "home_mate_memory_list" || msg.type === "home_mate_knowledge_list" || msg.type === "home_mate_models_get" || msg.type === "home_mate_model_set" || msg.type === "home_dock_get" || msg.type === "home_dock_set" || msg.type === "home_surface_get" || msg.type === "home_surface_set" || msg.type === "tools_list" || msg.type === "tool_get" || msg.type === "tool_install" || msg.type === "tool_remove" || msg.type === "tool_storage_op" || msg.type === "tool_llm_op" || msg.type === "tool_llm_config_get" || msg.type === "tool_control_response" || msg.type === "tool_source_get" || msg.type === "tool_mate_access_set") {
1056
1195
  if (typeof opts.onDmMessage === "function") {
1057
- opts.onDmMessage(ws, msg);
1196
+ opts.onDmMessage(ws, msg, slug);
1058
1197
  }
1059
1198
  return;
1060
1199
  }
@@ -1165,7 +1304,12 @@ function createProjectContext(opts) {
1165
1304
  sendTo: sendTo,
1166
1305
  matesModule: matesModule,
1167
1306
  sessionSearch: sessionSearch,
1168
- getAllProjectSessions: getAllProjectSessions,
1307
+ getWorkspaceMemorySessions: function () { return _workspaceQuery.getMemorySessions(true); },
1308
+ getOwnedCurrentSessions: function () {
1309
+ return _workspaceQuery.getMemorySessions(false).filter(function (session) {
1310
+ return session._projectSlug === slug;
1311
+ });
1312
+ },
1169
1313
  projectOwnerId: projectOwnerId,
1170
1314
  handleMessage: handleMessage,
1171
1315
  });
@@ -1246,6 +1390,8 @@ function createProjectContext(opts) {
1246
1390
  getSessionForWs: getSessionForWs,
1247
1391
  updateMemorySummary: updateMemorySummary,
1248
1392
  initMemorySummary: initMemorySummary,
1393
+ registerHomeDebateClient: function (ws) { if (ws) homeDebateClients.add(ws); },
1394
+ unregisterHomeDebateClient: function (ws) { homeDebateClients.delete(ws); },
1249
1395
  });
1250
1396
  var handleDebateStart = _debate.handleDebateStart;
1251
1397
  var handleDebateHandRaise = _debate.handleDebateHandRaise;
@@ -1294,6 +1440,11 @@ function createProjectContext(opts) {
1294
1440
  browserState._extensionId = null;
1295
1441
  if (_mcp) _mcp.handleExtensionDisconnect();
1296
1442
  }
1443
+ homeDebateClients.delete(ws);
1444
+ if (ws._clayHomeDebateSlug && ws._clayHomeDebateSlug !== slug && opts.getProject) {
1445
+ var debateProject = opts.getProject(ws._clayHomeDebateSlug);
1446
+ if (debateProject && typeof debateProject.unregisterHomeDebateClient === "function") debateProject.unregisterHomeDebateClient(ws);
1447
+ }
1297
1448
  _connection.handleDisconnection(ws);
1298
1449
  }
1299
1450
 
@@ -1317,6 +1468,7 @@ function createProjectContext(opts) {
1317
1468
  sendToSessionOthers: sendToSessionOthers,
1318
1469
  opts: opts,
1319
1470
  usersModule: usersModule,
1471
+ getProjectAccess: opts.getProjectAccess || function () { return { visibility: "public", ownerId: projectOwnerId || null }; },
1320
1472
  userPresence: userPresence,
1321
1473
  matesModule: matesModule,
1322
1474
  pushModule: pushModule,
@@ -1365,6 +1517,28 @@ function createProjectContext(opts) {
1365
1517
  serverTls: serverTls,
1366
1518
  serverAuthToken: serverAuthToken,
1367
1519
  });
1520
+ var _delegatedSession = attachDelegatedSession({
1521
+ sm: sm,
1522
+ getSdk: function () { return sdk; },
1523
+ getLinuxUserForSession: getLinuxUserForSession,
1524
+ resolveModel: function (principal) {
1525
+ var user = principal && principal.userId ? usersModule.findUserById(principal.userId) : null;
1526
+ return _models.resolveConfiguredModel({ _clayUser: user || null }, "standard");
1527
+ },
1528
+ });
1529
+ var _delegatedFollowUp = attachDelegatedFollowUp({
1530
+ sm: sm,
1531
+ getSdk: function () { return sdk; },
1532
+ getLinuxUserForSession: getLinuxUserForSession,
1533
+ onProcessingChanged: onProcessingChanged,
1534
+ isMultiUser: function () { return usersModule.isMultiUser(); },
1535
+ sessionRef: function (session) { return workspaceSessionRef(slug, session); },
1536
+ isPairedSession: function (session) { return !!_splitGroups.store.groupForMember(session.localId); },
1537
+ canResumeVendor: function (vendor) {
1538
+ var capabilities = sm.capabilitiesByVendor && sm.capabilitiesByVendor[vendor];
1539
+ return !!(capabilities && capabilities.sessionResume === true);
1540
+ },
1541
+ });
1368
1542
 
1369
1543
  // --- User message handler (delegated to project-user-message.js) ---
1370
1544
  var _userMessage = attachUserMessage({
@@ -1436,6 +1610,7 @@ function createProjectContext(opts) {
1436
1610
  usersModule: usersModule,
1437
1611
  fsAsUser: fsAsUser,
1438
1612
  validateEnvString: validateEnvString,
1613
+ onEnvironmentChanged: function () { return sdk.refreshEnvironmentRuntime(); },
1439
1614
  opts: opts,
1440
1615
  IGNORED_DIRS: IGNORED_DIRS,
1441
1616
  BINARY_EXTS: BINARY_EXTS,
@@ -1531,6 +1706,14 @@ function createProjectContext(opts) {
1531
1706
  inputSchema: normalizeToolSchema(documentTools[dti].inputSchema),
1532
1707
  });
1533
1708
  }
1709
+ var debateTools = _debateProposal.getBridgeTools(boundSession, normalizeToolSchema);
1710
+ for (var dbti = 0; dbti < debateTools.length; dbti++) tools.push(debateTools[dbti]);
1711
+ var mateCreationTools = _mateCreationProposal.getBridgeTools(boundSession, normalizeToolSchema);
1712
+ for (var mcti = 0; mcti < mateCreationTools.length; mcti++) tools.push(mateCreationTools[mcti]);
1713
+ var workspaceTools = _workspaceQuery.getBridgeTools(boundSession, normalizeToolSchema);
1714
+ for (var wqti = 0; wqti < workspaceTools.length; wqti++) tools.push(workspaceTools[wqti]);
1715
+ var historyTools = _workspaceQuery.getHistoryBridgeTools(boundSession, normalizeToolSchema);
1716
+ for (var cht = 0; cht < historyTools.length; cht++) tools.push(historyTools[cht]);
1534
1717
  }
1535
1718
 
1536
1719
  if (sessionOnly) return Promise.resolve(tools);
@@ -1543,6 +1726,10 @@ function createProjectContext(opts) {
1543
1726
  var inAppNames = Object.keys(localMcp);
1544
1727
  for (var i = 0; i < inAppNames.length; i++) {
1545
1728
  if (inAppNames[i] === "clay-sessions" || inAppNames[i] === "clay-notes" || inAppNames[i] === "clay-handoff" || inAppNames[i] === "clay-documents") continue;
1729
+ // Debate tools were added above only when this request had an
1730
+ // exact session. Never duplicate them or advertise the static,
1731
+ // intentionally unbound proposal server.
1732
+ if (inAppNames[i] === "clay-debate" || inAppNames[i] === "clay-mate-creation" || inAppNames[i] === "clay-workspace" || inAppNames[i] === "clay-history") continue;
1546
1733
  extractServerTools(inAppNames[i], localMcp[inAppNames[i]]);
1547
1734
  }
1548
1735
  }
@@ -1593,7 +1780,19 @@ function createProjectContext(opts) {
1593
1780
  }
1594
1781
  }
1595
1782
  }
1596
- if (serverName === "clay-sessions" || serverName === "clay-notes" || serverName === "clay-handoff" || serverName === "clay-documents") {
1783
+ if (boundSession && serverName === "clay-debate") {
1784
+ return _debateProposal.callBridgeTool(boundSession, toolName, args);
1785
+ }
1786
+ if (boundSession && serverName === "clay-mate-creation") {
1787
+ return _mateCreationProposal.callBridgeTool(boundSession, toolName, args);
1788
+ }
1789
+ if (boundSession && serverName === "clay-workspace") {
1790
+ return _workspaceQuery.callBridgeTool(boundSession, toolName, args);
1791
+ }
1792
+ if (boundSession && serverName === "clay-history") {
1793
+ return _workspaceQuery.callHistoryBridgeTool(boundSession, toolName, args);
1794
+ }
1795
+ if (serverName === "clay-sessions" || serverName === "clay-notes" || serverName === "clay-handoff" || serverName === "clay-documents" || serverName === "clay-debate" || serverName === "clay-mate-creation" || serverName === "clay-workspace" || serverName === "clay-history") {
1597
1796
  return Promise.reject(new Error("Session-bound tool requires a valid Clay session: " + serverName + "/" + toolName));
1598
1797
  }
1599
1798
  if (sessionOnly) return Promise.reject(new Error("Session tool not found: " + serverName + "/" + toolName));
@@ -1807,7 +2006,7 @@ function createProjectContext(opts) {
1807
2006
  };
1808
2007
  if (isMate) {
1809
2008
  status.isMate = true;
1810
- status.mateId = path.basename(cwd);
2009
+ status.mateId = mateId;
1811
2010
  }
1812
2011
  if (worktreeMeta) {
1813
2012
  status.isWorktree = true;
@@ -1908,6 +2107,19 @@ function createProjectContext(opts) {
1908
2107
  getMcpBridgeHandler: getMcpBridgeHandler,
1909
2108
  getStatus: getStatus,
1910
2109
  getSessionManager: function () { return sm; },
2110
+ createDelegatedSession: _delegatedSession.createDelegatedSession,
2111
+ inspectDelegatedFollowUp: _delegatedFollowUp.inspectDelegatedFollowUp,
2112
+ dispatchDelegatedFollowUp: _delegatedFollowUp.dispatchDelegatedFollowUp,
2113
+ unregisterHomeDebateClient: function (ws) { homeDebateClients.delete(ws); },
2114
+ handleHomeDebateProposalResponse: function (ws, msg, session) { return _debateProposal.handleHomeMessage(ws, msg, session); },
2115
+ handleHomeMateCreationProposalResponse: function (ws, msg, session) { return _mateCreationProposal.handleHomeMessage(ws, msg, session); },
2116
+ handleHomeAskUserResponse: function (msg, session) { return _sessions.respondToAskUser(session, msg); },
2117
+ handleHomeDebateControl: function (ws, msg, session) { return _debate.handleHomeControl(ws, msg, session); },
2118
+ getVendorModelCatalog: _models.getVendorCatalog,
2119
+ getVendorModelAvailability: _models.getVendorAvailability,
2120
+ getMemoryState: _memory.readMemoryState,
2121
+ listKnowledgeFiles: _knowledge.listKnowledgeFiles,
2122
+ refreshCapsuleCatalog: _capsuleCatalog.refreshSessions,
1911
2123
  getNotificationsModule: function () { return _notifications; },
1912
2124
  getSchedules: _loop.getSchedules,
1913
2125
  importSchedule: _loop.importSchedule,
@@ -1916,6 +2128,21 @@ function createProjectContext(opts) {
1916
2128
  setIcon: setIcon,
1917
2129
  setProjectOwner: function (ownerId) { projectOwnerId = ownerId; },
1918
2130
  getProjectOwner: function () { return projectOwnerId; },
2131
+ getToolLlmConfig: function (ws, alias) {
2132
+ return _models.resolveConfiguredModel(ws, alias);
2133
+ },
2134
+ completeToolLlm: async function (ws, args) {
2135
+ var owner = projectOwnerId ? usersModule.findUserById(projectOwnerId) : null;
2136
+ var selection = await _models.resolveConfiguredModel(ws, args.model);
2137
+ return toolLlm.complete({
2138
+ adapters: adapters,
2139
+ cwd: cwd,
2140
+ linuxUser: owner && owner.linuxUser ? owner.linuxUser : null,
2141
+ args: args,
2142
+ selection: selection,
2143
+ timeoutMs: 60000,
2144
+ });
2145
+ },
1919
2146
  refreshUserProfile: function (userId) {
1920
2147
  var user = usersModule.findUserById(userId);
1921
2148
  if (!user) return;
@@ -1934,4 +2161,4 @@ function createProjectContext(opts) {
1934
2161
  };
1935
2162
  }
1936
2163
 
1937
- module.exports = { createProjectContext: createProjectContext, safePath: safePath, validateEnvString: validateEnvString };
2164
+ module.exports = { createProjectContext: createProjectContext, createMateToolControlMcp: createMateToolControlMcp, safePath: safePath, validateEnvString: validateEnvString };