clay-server 3.8.1 → 4.0.0-beta.10

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 (222) hide show
  1. package/lib/ask-user-mcp-server.js +5 -119
  2. package/lib/background-task-timing.js +105 -0
  3. package/lib/builtin-mates.js +6 -6
  4. package/lib/claude-hook-installer.js +15 -0
  5. package/lib/clay-history-mcp-server.js +62 -297
  6. package/lib/daemon.js +23 -1
  7. package/lib/debate-model-selection.js +119 -0
  8. package/lib/home-debate-tool-policy.js +164 -0
  9. package/lib/home-response-notifications.js +26 -0
  10. package/lib/knowledge-import.js +436 -0
  11. package/lib/knowledge-record-store.js +188 -0
  12. package/lib/knowledge-search.js +224 -0
  13. package/lib/mate-creation-mcp-server.js +55 -0
  14. package/lib/mate-knowledge-mcp-server.js +151 -0
  15. package/lib/mate-knowledge-migration.js +283 -0
  16. package/lib/mate-knowledge-service.js +488 -0
  17. package/lib/mate-knowledge-sync.js +482 -0
  18. package/lib/mate-ready-creation.js +95 -0
  19. package/lib/mates.js +2 -0
  20. package/lib/notes.js +2 -1
  21. package/lib/project-ask-user.js +64 -0
  22. package/lib/project-capsule-catalog.js +101 -0
  23. package/lib/project-connection.js +17 -0
  24. package/lib/project-debate-proposal.js +133 -17
  25. package/lib/project-debate.js +214 -110
  26. package/lib/project-delegated-follow-up.js +84 -0
  27. package/lib/project-delegated-session.js +53 -0
  28. package/lib/project-filesystem.js +7 -9
  29. package/lib/project-knowledge.js +23 -0
  30. package/lib/project-logs-comments.js +137 -0
  31. package/lib/project-logs-mcp-server.js +290 -0
  32. package/lib/project-logs-query.js +167 -0
  33. package/lib/project-logs-root.js +67 -0
  34. package/lib/project-logs-schema.js +259 -0
  35. package/lib/project-logs-service.js +357 -0
  36. package/lib/project-logs-snapshot.js +202 -0
  37. package/lib/project-logs-store.js +498 -0
  38. package/lib/project-logs-versioning.js +128 -0
  39. package/lib/project-logs.js +347 -0
  40. package/lib/project-mate-creation-proposal.js +120 -0
  41. package/lib/project-mate-interaction.js +14 -0
  42. package/lib/project-mate-knowledge.js +110 -0
  43. package/lib/project-memory.js +36 -7
  44. package/lib/project-models.js +157 -32
  45. package/lib/project-session-notes.js +2 -2
  46. package/lib/project-session-pair.js +8 -8
  47. package/lib/project-sessions.js +66 -51
  48. package/lib/project-vendor-login.js +414 -0
  49. package/lib/project-worker-proposal.js +25 -25
  50. package/lib/project-workspace-query.js +144 -0
  51. package/lib/project.js +433 -102
  52. package/lib/public/app.js +109 -48
  53. package/lib/public/css/avatar-imprints.css +0 -1
  54. package/lib/public/css/base.css +4 -0
  55. package/lib/public/css/capsule-ui.css +389 -0
  56. package/lib/public/css/command-palette.css +306 -6
  57. package/lib/public/css/home-capsule-library.css +243 -0
  58. package/lib/public/css/home-capsule-source.css +192 -0
  59. package/lib/public/css/home-debate-live.css +146 -0
  60. package/lib/public/css/home-debate-planning.css +125 -0
  61. package/lib/public/css/home-debates-archive.css +281 -0
  62. package/lib/public/css/home-hub.css +896 -405
  63. package/lib/public/css/home-mate-creation.css +34 -0
  64. package/lib/public/css/home-mate-model-picker.css +131 -0
  65. package/lib/public/css/home-mate-settings.css +344 -0
  66. package/lib/public/css/home-session-actions.css +265 -0
  67. package/lib/public/css/home-sidebar.css +667 -0
  68. package/lib/public/css/icon-strip.css +1 -2
  69. package/lib/public/css/input.css +79 -25
  70. package/lib/public/css/mates.css +7 -34
  71. package/lib/public/css/pane.css +1 -1
  72. package/lib/public/css/playbook.css +0 -80
  73. package/lib/public/css/project-logs.css +234 -0
  74. package/lib/public/css/scheduler.css +1 -1
  75. package/lib/public/css/sticky-notes.css +53 -117
  76. package/lib/public/css/tui-attention.css +0 -44
  77. package/lib/public/css/workspace-assignment.css +45 -0
  78. package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
  79. package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
  80. package/lib/public/index.html +96 -74
  81. package/lib/public/modules/app-connection.js +100 -5
  82. package/lib/public/modules/app-dm.js +43 -160
  83. package/lib/public/modules/app-home-hub.js +328 -585
  84. package/lib/public/modules/app-message-cards.js +242 -0
  85. package/lib/public/modules/app-message-router.js +84 -0
  86. package/lib/public/modules/app-messages.js +124 -38
  87. package/lib/public/modules/app-notifications.js +8 -119
  88. package/lib/public/modules/app-panels.js +43 -2
  89. package/lib/public/modules/app-projects.js +9 -1
  90. package/lib/public/modules/app-rendering.js +21 -602
  91. package/lib/public/modules/avatar-imprint.js +11 -8
  92. package/lib/public/modules/background-tasks-ui.js +139 -16
  93. package/lib/public/modules/chat-bubble-renderer.js +152 -0
  94. package/lib/public/modules/chat-render-runtime.js +198 -0
  95. package/lib/public/modules/command-palette.js +225 -436
  96. package/lib/public/modules/dm-render.js +82 -0
  97. package/lib/public/modules/home-capsule-creation-intent.js +31 -0
  98. package/lib/public/modules/home-capsule-library.js +146 -0
  99. package/lib/public/modules/home-capsule-source.js +383 -0
  100. package/lib/public/modules/home-chat-identity.js +35 -0
  101. package/lib/public/modules/home-chat-scroll.js +77 -0
  102. package/lib/public/modules/home-chat-stream-state.js +34 -0
  103. package/lib/public/modules/home-composer-focus.js +25 -0
  104. package/lib/public/modules/home-conversations-sheet.js +179 -0
  105. package/lib/public/modules/home-debate-activity.js +48 -0
  106. package/lib/public/modules/home-debate-controls.js +295 -0
  107. package/lib/public/modules/home-debate-launch.js +41 -0
  108. package/lib/public/modules/home-debate-live.js +284 -0
  109. package/lib/public/modules/home-debate-models.js +73 -0
  110. package/lib/public/modules/home-debate-planning.js +335 -0
  111. package/lib/public/modules/home-debates-archive.js +279 -0
  112. package/lib/public/modules/home-dock-resize.js +74 -0
  113. package/lib/public/modules/home-dock.js +446 -0
  114. package/lib/public/modules/home-mate-chat.js +496 -0
  115. package/lib/public/modules/home-mate-creation.js +109 -0
  116. package/lib/public/modules/home-mate-model-picker.js +281 -0
  117. package/lib/public/modules/home-mate-selection.js +38 -0
  118. package/lib/public/modules/home-mate-settings-menu.js +131 -0
  119. package/lib/public/modules/home-mate-settings.js +383 -0
  120. package/lib/public/modules/home-session-actions.js +373 -0
  121. package/lib/public/modules/home-session-model-confirmation.js +13 -0
  122. package/lib/public/modules/home-shell.js +9 -0
  123. package/lib/public/modules/home-sidebar-chat-list.js +63 -0
  124. package/lib/public/modules/home-sidebar.js +165 -0
  125. package/lib/public/modules/home-sub-surface.js +19 -0
  126. package/lib/public/modules/home-surface-boot.js +68 -0
  127. package/lib/public/modules/home-surface.js +141 -0
  128. package/lib/public/modules/home-tools.js +271 -0
  129. package/lib/public/modules/markdown.js +50 -2
  130. package/lib/public/modules/mate-management.js +86 -0
  131. package/lib/public/modules/mate-sidebar.js +0 -8
  132. package/lib/public/modules/mate-wizard.js +0 -7
  133. package/lib/public/modules/mention.js +17 -19
  134. package/lib/public/modules/pane-bridge.js +9 -0
  135. package/lib/public/modules/profile.js +4 -5
  136. package/lib/public/modules/project-logs-ambient.js +238 -0
  137. package/lib/public/modules/project-logs-render.js +359 -0
  138. package/lib/public/modules/project-logs.js +328 -0
  139. package/lib/public/modules/project-settings.js +34 -28
  140. package/lib/public/modules/project-switcher.js +11 -5
  141. package/lib/public/modules/project-workspace-assignment.js +23 -0
  142. package/lib/public/modules/scheduler.js +17 -3
  143. package/lib/public/modules/search-clay-chat.js +402 -0
  144. package/lib/public/modules/server-settings.js +14 -12
  145. package/lib/public/modules/session-actions.js +1 -1
  146. package/lib/public/modules/sidebar-mates.js +56 -552
  147. package/lib/public/modules/sidebar-mobile.js +12 -73
  148. package/lib/public/modules/sidebar-presence.js +37 -0
  149. package/lib/public/modules/sidebar-sessions.js +25 -1
  150. package/lib/public/modules/split-pair-ui.js +13 -13
  151. package/lib/public/modules/split-view.js +7 -0
  152. package/lib/public/modules/sticky-notes.js +106 -53
  153. package/lib/public/modules/tool-input-composition.js +48 -0
  154. package/lib/public/modules/tool-llm-status.js +167 -0
  155. package/lib/public/modules/tool-palette.js +76 -4
  156. package/lib/public/modules/tool-renderer-advanced.js +285 -0
  157. package/lib/public/modules/tool-renderer-chart.js +158 -0
  158. package/lib/public/modules/tool-renderer-semantics.js +35 -0
  159. package/lib/public/modules/tool-renderer.js +464 -0
  160. package/lib/public/modules/tool-runtime.js +309 -0
  161. package/lib/public/modules/tool-ui-evaluator.js +97 -0
  162. package/lib/public/modules/tool-ui-tree.js +21 -0
  163. package/lib/public/modules/tui-attention.js +10 -0
  164. package/lib/public/modules/user-settings.js +16 -23
  165. package/lib/public/modules/vendor-login.js +287 -0
  166. package/lib/public/modules/worker-proposal.js +2 -2
  167. package/lib/public/modules/workspace-assignment-card.js +149 -0
  168. package/lib/public/modules/workspace-assignment-routing.js +4 -0
  169. package/lib/public/style.css +14 -2
  170. package/lib/runtime-env.js +65 -0
  171. package/lib/sdk-bridge.js +120 -32
  172. package/lib/sdk-message-processor.js +34 -13
  173. package/lib/server-home-capsule-creation.js +36 -0
  174. package/lib/server-home-chat-events.js +287 -0
  175. package/lib/server-home-chat.js +518 -0
  176. package/lib/server-home-clay-entry.js +65 -0
  177. package/lib/server-home-clay-session-links.js +26 -0
  178. package/lib/server-home-debate-planning.js +214 -0
  179. package/lib/server-home-debates.js +137 -0
  180. package/lib/server-home-mate-creation.js +261 -0
  181. package/lib/server-home-models.js +241 -0
  182. package/lib/server-home-preferences.js +61 -0
  183. package/lib/server-mates.js +37 -0
  184. package/lib/server-tools.js +377 -0
  185. package/lib/server.js +166 -59
  186. package/lib/session-pair-mcp-server.js +6 -6
  187. package/lib/sessions.js +22 -4
  188. package/lib/tool-capsule-source.js +142 -0
  189. package/lib/tool-control-mcp-server.js +126 -0
  190. package/lib/tool-llm.js +48 -0
  191. package/lib/tool-storage.js +77 -0
  192. package/lib/tool-ui-spec-advanced.js +82 -0
  193. package/lib/tool-ui-spec.js +261 -0
  194. package/lib/tools-registry.js +286 -0
  195. package/lib/users-home-dock-preferences.js +77 -0
  196. package/lib/users-home-surface-preferences.js +99 -0
  197. package/lib/users-preferences.js +4 -7
  198. package/lib/users.js +12 -0
  199. package/lib/whats-new-content.js +3 -3
  200. package/lib/workspace-assignment-service.js +420 -0
  201. package/lib/workspace-query-mcp-server.js +154 -0
  202. package/lib/workspace-query-service.js +492 -0
  203. package/lib/ws-schema.js +107 -12
  204. package/lib/yoke/adapters/acp.js +2 -1
  205. package/lib/yoke/adapters/antigravity.js +2 -1
  206. package/lib/yoke/adapters/claude-worker.js +11 -4
  207. package/lib/yoke/adapters/claude.js +141 -46
  208. package/lib/yoke/adapters/codex.js +79 -11
  209. package/lib/yoke/adapters/kiro.js +2 -1
  210. package/lib/yoke/claude-user-input.js +38 -0
  211. package/lib/yoke/codex-app-server.js +20 -2
  212. package/lib/yoke/codex-background-tasks.js +8 -2
  213. package/lib/yoke/codex-user-input.js +64 -0
  214. package/lib/yoke/complete-once.js +164 -0
  215. package/lib/yoke/index.js +5 -1
  216. package/lib/yoke/interface.js +19 -0
  217. package/lib/yoke/mcp-bridge-server.js +2 -6
  218. package/lib/yoke/user-input.js +254 -0
  219. package/package.json +4 -3
  220. package/lib/public/css/home-chat.css +0 -380
  221. package/lib/public/modules/home-chat.js +0 -438
  222. 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");
@@ -30,18 +34,76 @@ var { attachSessions } = require("./project-sessions");
30
34
  var { attachModels } = require("./project-models");
31
35
  var { attachUserMessage } = require("./project-user-message");
32
36
  var { attachShellCommand } = require("./project-shell-command");
37
+ var { attachVendorLogin } = require("./project-vendor-login");
33
38
  var { attachConnection } = require("./project-connection");
34
39
  var { attachMcp } = require("./project-mcp");
35
40
  var { createLocalMcp } = require("./mcp-local");
36
41
  var { attachEmail: attachEmailModule } = require("./project-email");
37
42
  var { attachSessionSpawn } = require("./project-session-spawn");
43
+ var { attachDelegatedSession } = require("./project-delegated-session");
44
+ var { attachDelegatedFollowUp } = require("./project-delegated-follow-up");
45
+ var workspaceSessionRef = require("./workspace-query-service").sessionRef;
38
46
  var { attachSessionPair } = require("./project-session-pair");
39
47
  var { attachSessionHandoff } = require("./project-session-handoff");
40
48
  var { attachSessionNotes, composeSystemPrompts } = require("./project-session-notes");
41
49
  var { attachSessionDocument } = require("./project-session-document");
50
+ var { attachCapsuleCatalog } = require("./project-capsule-catalog");
51
+ var { attachProjectWorkspaceQuery } = require("./project-workspace-query");
52
+ var { attachProjectLogs } = require("./project-logs");
53
+ var { attachProjectMateKnowledge } = require("./project-mate-knowledge");
42
54
  var { attachSplitGroups } = require("./session-split-groups");
55
+ var toolControlMcp = require("./tool-control-mcp-server");
56
+ var toolLlm = require("./tool-llm");
43
57
  // project-notifications is attached globally in server.js, passed via opts.notificationsModule
44
58
 
59
+ function createMateToolControlMcp(adapter, config) {
60
+ if (!adapter || typeof adapter.createToolServer !== "function") return null;
61
+ var handlers = {
62
+ list: function () {
63
+ var manifests = config.list(config.userId) || [];
64
+ var tools = [];
65
+ for (var i = 0; i < manifests.length; i++) {
66
+ tools.push({
67
+ id: manifests[i].id,
68
+ name: manifests[i].name,
69
+ description: manifests[i].description || "",
70
+ useWhen: manifests[i].useWhen || "",
71
+ runtime: manifests[i].runtime || "worker",
72
+ permissions: manifests[i].permissions || [],
73
+ skills: manifests[i].skills || "",
74
+ });
75
+ }
76
+ return tools;
77
+ },
78
+ snapshot: function (toolId) {
79
+ return config.control(config.userId, config.mateId, toolId, "snapshot", {});
80
+ },
81
+ act: function (toolId, actionId, args) {
82
+ return config.control(config.userId, config.mateId, toolId, "act", { actionId: actionId, args: args });
83
+ },
84
+ set: function (toolId, controlId, value) {
85
+ return config.control(config.userId, config.mateId, toolId, "set", { controlId: controlId, value: value });
86
+ },
87
+ source: function (toolId) {
88
+ return config.source(config.userId, toolId);
89
+ },
90
+ install: function (input) {
91
+ return config.install(config.userId, input);
92
+ },
93
+ update: function (toolId, input) {
94
+ return config.update(config.userId, toolId, input);
95
+ },
96
+ uninstall: function (toolId) {
97
+ return config.remove(config.userId, toolId);
98
+ },
99
+ };
100
+ return adapter.createToolServer({
101
+ name: "clay-tools",
102
+ version: "1.0.0",
103
+ tools: toolControlMcp.getToolDefs(handlers),
104
+ });
105
+ }
106
+
45
107
  // --- Context Sources persistence ---
46
108
  var _ctxSrcConfig = require("./config");
47
109
  var _ctxSrcDir = path.join(_ctxSrcConfig.CONFIG_DIR, "context-sources");
@@ -73,26 +135,7 @@ function saveContextSources(slug, sessionId, activeIds) {
73
135
  // Validate environment variable string (KEY=VALUE per line)
74
136
  // Returns null if valid, or an error string if invalid
75
137
  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;
138
+ return runtimeEnv.validateEnvString(str);
96
139
  }
97
140
 
98
141
  // YOKE adapter (replaces direct SDK access)
@@ -153,8 +196,6 @@ function createProjectContext(opts) {
153
196
  var lanHost = opts.lanHost || null;
154
197
  var getProjectCount = opts.getProjectCount || function () { return 1; };
155
198
  var getProjectList = opts.getProjectList || function () { return []; };
156
- var getAllProjectSessions = opts.getAllProjectSessions || function () { return []; };
157
- var getAllProjectsWithSessions = opts.getAllProjectsWithSessions || function () { return []; };
158
199
  var isHostAgent = !!opts.isHostAgent;
159
200
  var getHubSchedules = opts.getHubSchedules || function () { return []; };
160
201
  var moveScheduleToProject = opts.moveScheduleToProject || function () { return { ok: false, error: "Not supported" }; };
@@ -168,6 +209,23 @@ function createProjectContext(opts) {
168
209
  var projectOwnerId = opts.projectOwnerId || null;
169
210
  var worktreeMeta = opts.worktreeMeta || null; // { parentSlug, branch, external }
170
211
  var isMate = opts.isMate || false;
212
+ var mateId = opts.mateId || (isMate ? path.basename(cwd) : null);
213
+ var listControllableTools = opts.listControllableTools || function () { return []; };
214
+ var controlToolForMate = opts.controlToolForMate || function () {
215
+ return Promise.reject(new Error("Tool control is unavailable."));
216
+ };
217
+ var installToolForMate = opts.installToolForMate || function () {
218
+ return Promise.reject(new Error("Tool installation is unavailable."));
219
+ };
220
+ var sourceToolForMate = opts.sourceToolForMate || function () {
221
+ return Promise.reject(new Error("Capsule source access is unavailable."));
222
+ };
223
+ var updateToolForMate = opts.updateToolForMate || function () {
224
+ return Promise.reject(new Error("Capsule source updates are unavailable."));
225
+ };
226
+ var removeToolForMate = opts.removeToolForMate || function () {
227
+ return Promise.reject(new Error("Tool removal is unavailable."));
228
+ };
171
229
  var onCreateWorktree = opts.onCreateWorktree || null;
172
230
  var serverPort = opts.port || 2633;
173
231
  var serverTls = opts.tls || false;
@@ -219,8 +277,7 @@ function createProjectContext(opts) {
219
277
 
220
278
  // Cache resolved OS user info to avoid repeated getent calls
221
279
  var osUserInfoCache = {};
222
- function getOsUserInfoForWs(ws) {
223
- var linuxUser = getLinuxUserForWs(ws);
280
+ function getOsUserInfoForLinuxUser(linuxUser) {
224
281
  if (!linuxUser) return null;
225
282
  if (osUserInfoCache[linuxUser]) return osUserInfoCache[linuxUser];
226
283
  try {
@@ -233,23 +290,34 @@ function createProjectContext(opts) {
233
290
  }
234
291
  }
235
292
 
293
+ function getOsUserInfoForWs(ws) {
294
+ var linuxUser = getLinuxUserForWs(ws);
295
+ return getOsUserInfoForLinuxUser(linuxUser);
296
+ }
297
+
236
298
  function getOsUserInfoForReq(req) {
237
299
  if (!osUsers) return null;
238
300
  if (!req._clayUser || !req._clayUser.linuxUser) return null;
239
301
  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
- }
302
+ return getOsUserInfoForLinuxUser(linuxUser);
303
+ }
304
+
305
+ function getRuntimeEnvForSession(session) {
306
+ var linuxUser = (session && session.linuxUser) || getLinuxUserForSession(session);
307
+ var osUserInfo = getOsUserInfoForLinuxUser(linuxUser);
308
+ var baseEnv = osUserInfo ? buildUserEnv(osUserInfo) : process.env;
309
+ var shared = typeof opts.onGetSharedEnv === "function" ? opts.onGetSharedEnv() : null;
310
+ var projectEnv = typeof opts.onGetProjectEnv === "function" ? opts.onGetProjectEnv(slug) : null;
311
+ return runtimeEnv.resolveRuntimeEnv({
312
+ baseEnv: baseEnv,
313
+ sharedEnvrc: shared && shared.envrc,
314
+ projectEnvrc: projectEnv && projectEnv.envrc,
315
+ });
249
316
  }
250
317
 
251
318
  // --- Per-project clients ---
252
319
  var clients = new Set();
320
+ var homeDebateClients = new Set();
253
321
 
254
322
  // --- Browser extension state (shared mutable object) ---
255
323
  var _extToken = crypto.randomUUID(); // Auth token for MCP server bridge
@@ -369,6 +437,10 @@ function createProjectContext(opts) {
369
437
  ws.send(data);
370
438
  }
371
439
  }
440
+ homeDebateClients.forEach(function (ws) {
441
+ if (ws.readyState !== 1) { homeDebateClients.delete(ws); return; }
442
+ if (!clients.has(ws) && ws._clayHomeDebateSlug === slug && ws._clayActiveSession === sessionId) ws.send(data);
443
+ });
372
444
  }
373
445
 
374
446
  function sendToSessionOthers(sender, sessionId, obj) {
@@ -537,6 +609,41 @@ function createProjectContext(opts) {
537
609
  },
538
610
  fsAsUser: fsAsUser,
539
611
  });
612
+ var _capsuleCatalog = attachCapsuleCatalog({
613
+ isMate: isMate,
614
+ listManifests: listControllableTools,
615
+ getUserId: function (session) {
616
+ return (session && session.ownerId) || projectOwnerId || "default";
617
+ },
618
+ getSdk: function () { return sdk; },
619
+ getSessions: function () { return sm.sessions; },
620
+ });
621
+ var _workspaceQuery = attachProjectWorkspaceQuery({
622
+ service: opts.workspaceQueryService || null,
623
+ sm: sm,
624
+ projectSlug: slug,
625
+ getProjectOwnerId: function () { return projectOwnerId; },
626
+ isMate: isMate,
627
+ mateId: mateId,
628
+ });
629
+ var _projectLogs = attachProjectLogs({
630
+ service: opts.projectLogsService || null,
631
+ sm: sm,
632
+ projectSlug: slug,
633
+ getProjectOwnerId: function () { return projectOwnerId; },
634
+ isMate: isMate,
635
+ mateId: mateId,
636
+ sendTo: sendTo,
637
+ getClients: function () { return clients; },
638
+ });
639
+ var _mateKnowledge = attachProjectMateKnowledge({
640
+ service: opts.mateKnowledgeService || null,
641
+ sm: sm,
642
+ projectSlug: slug,
643
+ getProjectOwnerId: function () { return projectOwnerId; },
644
+ isMate: isMate,
645
+ mateId: mateId,
646
+ });
540
647
 
541
648
  // The SDK bridge is created after local MCP servers. Session spawning uses
542
649
  // a getter so tool handlers see the initialized bridge when they run.
@@ -587,15 +694,46 @@ function createProjectContext(opts) {
587
694
  var _debateProposal = attachDebateProposal({
588
695
  cwd: cwd,
589
696
  isMate: isMate,
697
+ isHostAgent: isHostAgent,
590
698
  sendTo: sendTo,
591
699
  buildMateCtx: matesModule.buildMateCtx,
592
700
  getMate: matesModule.getMate,
593
701
  getProjectOwnerId: function () { return projectOwnerId; },
702
+ getVendorModelCatalog: function (ws, vendor) { return _models.getVendorCatalog(ws, vendor); },
703
+ getVendorModelCatalogForSession: function (session, vendor) {
704
+ var user = session && session.ownerId ? usersModule.findUserById(session.ownerId) : null;
705
+ return _models.getVendorCatalog({ _clayUser: user || null }, vendor);
706
+ },
594
707
  startDebate: function (session, briefData, moderatorId, ws) {
595
708
  if (!_debate) return { error: "The debate engine is unavailable." };
596
709
  return _debate.handleMcpDebateApproval(session, briefData, moderatorId, ws);
597
710
  },
711
+ recordSessionEvent: function (session, event) { sm.sendAndRecord(session, event); },
598
712
  });
713
+ var _mateCreationProposal = attachMateCreationProposal({
714
+ isMate: isMate,
715
+ isHostAgent: isHostAgent,
716
+ isMultiUser: usersModule.isMultiUser,
717
+ getProjectOwnerId: function () { return projectOwnerId; },
718
+ recordSessionEvent: function (session, event) { sm.sendAndRecord(session, event); },
719
+ getVendorModelCatalog: function (ws, vendor) { return _models.getVendorCatalog(ws, vendor); },
720
+ createReadyMate: opts.createReadyMate,
721
+ });
722
+ var _askUser = attachAskUser({ record: function (session, event) { sm.sendAndRecord(session, event); } });
723
+
724
+ function createToolControlMcpServer() {
725
+ if (!isMate || !adapter || typeof adapter.createToolServer !== "function") return null;
726
+ return createMateToolControlMcp(adapter, {
727
+ userId: projectOwnerId || "default",
728
+ mateId: path.basename(cwd),
729
+ list: listControllableTools,
730
+ control: controlToolForMate,
731
+ source: sourceToolForMate,
732
+ install: installToolForMate,
733
+ update: updateToolForMate,
734
+ remove: removeToolForMate,
735
+ });
736
+ }
599
737
 
600
738
  // --- MCP tool servers (created via YOKE adapter) ---
601
739
  var mcpServers = (function () {
@@ -621,6 +759,27 @@ function createProjectContext(opts) {
621
759
  }
622
760
  }
623
761
 
762
+ // Project Logs. Project sessions get the project-scoped set; Mate projects
763
+ // get the read-only cross-project set only when the Mate registry confirms
764
+ // authoritative builtin Clay.
765
+ try {
766
+ var projectLogsMcpConfig = _projectLogs.createMcpServer(adapter, null);
767
+ if (projectLogsMcpConfig) servers[projectLogsMcpConfig.name || "clay-logs"] = projectLogsMcpConfig;
768
+ } catch (e) {
769
+ console.error("[project] Failed to create clay-logs MCP server:", e.message);
770
+ }
771
+
772
+ // Mate Knowledge. Mate projects only; the registry decides whether this is
773
+ // one Mate's own scope or authoritative Clay's cross-Mate read view.
774
+ if (isMate) {
775
+ try {
776
+ var mateKnowledgeMcpConfig = _mateKnowledge.createMcpServer(adapter, null);
777
+ if (mateKnowledgeMcpConfig) servers[mateKnowledgeMcpConfig.name || "clay-knowledge"] = mateKnowledgeMcpConfig;
778
+ } catch (e) {
779
+ console.error("[project] Failed to create clay-knowledge MCP server:", e.message);
780
+ }
781
+ }
782
+
624
783
  // Session-bound access to the source of a handoff (main projects only).
625
784
  if (!isMate) {
626
785
  try {
@@ -649,77 +808,39 @@ function createProjectContext(opts) {
649
808
  console.error("[project] Failed to create debate MCP server:", e.message);
650
809
  }
651
810
 
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) {
811
+ if (isMate && isHostAgent) {
657
812
  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;
813
+ var mateCreationMcpConfig = _mateCreationProposal.createMcpServer(adapter, null);
814
+ if (mateCreationMcpConfig) servers[mateCreationMcpConfig.name || "clay-mate-creation"] = mateCreationMcpConfig;
664
815
  } catch (e) {
665
- console.error("[project] Failed to create clay-history MCP server:", e.message);
816
+ console.error("[project] Failed to create Mate creation MCP server:", e.message);
666
817
  }
667
818
  }
668
819
 
669
- // Ask-user MCP server (mates only)
820
+ // Owner-bound workspace inspection is available only inside Mate
821
+ // projects. The server-side Mate registry decides whether the wider
822
+ // builtin Clay tools are present; project flags and tool arguments do not.
670
823
  if (isMate) {
671
824
  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
- }
825
+ var workspaceMcpConfig = _workspaceQuery.createMcpServer(adapter, null);
826
+ if (workspaceMcpConfig) servers[workspaceMcpConfig.name || "clay-workspace"] = workspaceMcpConfig;
827
+ } catch (e) {
828
+ console.error("[project] Failed to create clay-workspace MCP server:", e.message);
829
+ }
830
+ try {
831
+ var clayHistoryMcpConfig = _workspaceQuery.createHistoryMcpServer(adapter, null);
832
+ if (clayHistoryMcpConfig) servers[clayHistoryMcpConfig.name || "clay-history"] = clayHistoryMcpConfig;
833
+ } catch (e) {
834
+ console.error("[project] Failed to create Clay history compatibility server:", e.message);
835
+ }
836
+ }
695
837
 
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;
838
+ if (isMate) {
839
+ try {
840
+ var toolControlMcpConfig = createToolControlMcpServer();
841
+ if (toolControlMcpConfig) servers[toolControlMcpConfig.name || "clay-tools"] = toolControlMcpConfig;
721
842
  } catch (e) {
722
- console.error("[project] Failed to create ask-user MCP server:", e.message);
843
+ console.error("[project] Failed to create clay-tools MCP server:", e.message);
723
844
  }
724
845
  }
725
846
 
@@ -805,6 +926,51 @@ function createProjectContext(opts) {
805
926
  var name = keys[i];
806
927
  if (name === "clay-browser" && !extConnected) continue;
807
928
  if (name === "clay-email" && !emailAvailable) continue;
929
+ if (name === "clay-workspace" && forSession) {
930
+ try {
931
+ var boundWorkspace = _workspaceQuery.createMcpServer(adapter, forSession);
932
+ if (boundWorkspace) { filtered[name] = boundWorkspace; hasAny = true; }
933
+ } catch (e) {
934
+ console.error("[project] Failed to bind clay-workspace MCP server:", e.message);
935
+ }
936
+ continue;
937
+ }
938
+ if (name === "clay-history" && forSession) {
939
+ try {
940
+ var boundHistory = _workspaceQuery.createHistoryMcpServer(adapter, forSession);
941
+ if (boundHistory) { filtered[name] = boundHistory; hasAny = true; }
942
+ } catch (e) {
943
+ console.error("[project] Failed to bind Clay history compatibility server:", e.message);
944
+ }
945
+ continue;
946
+ }
947
+ if (name === "clay-logs" && forSession) {
948
+ try {
949
+ var boundLogs = _projectLogs.createMcpServer(adapter, forSession);
950
+ if (boundLogs) { filtered[name] = boundLogs; hasAny = true; }
951
+ } catch (e) {
952
+ console.error("[project] Failed to bind clay-logs MCP server:", e.message);
953
+ }
954
+ continue;
955
+ }
956
+ if (name === "clay-knowledge" && forSession) {
957
+ try {
958
+ var boundKnowledge = _mateKnowledge.createMcpServer(adapter, forSession);
959
+ if (boundKnowledge) { filtered[name] = boundKnowledge; hasAny = true; }
960
+ } catch (e) {
961
+ console.error("[project] Failed to bind clay-knowledge MCP server:", e.message);
962
+ }
963
+ continue;
964
+ }
965
+ if (name === "clay-tools" && forSession) {
966
+ try {
967
+ var boundToolControl = createToolControlMcpServer();
968
+ if (boundToolControl) { filtered[name] = boundToolControl; hasAny = true; }
969
+ } catch (e) {
970
+ console.error("[project] Failed to bind clay-tools MCP server:", e.message);
971
+ }
972
+ continue;
973
+ }
808
974
  if (name === "clay-sessions" && forSession) {
809
975
  try {
810
976
  var boundSpawn = _sessionSpawn.createMcpServer(adapter, forSession);
@@ -850,6 +1016,15 @@ function createProjectContext(opts) {
850
1016
  }
851
1017
  continue;
852
1018
  }
1019
+ if (name === "clay-mate-creation" && forSession) {
1020
+ try {
1021
+ var boundMateCreation = _mateCreationProposal.createMcpServer(adapter, forSession);
1022
+ if (boundMateCreation) { filtered[name] = boundMateCreation; hasAny = true; }
1023
+ } catch (e) {
1024
+ console.error("[project] Failed to bind Mate creation MCP server:", e.message);
1025
+ }
1026
+ continue;
1027
+ }
853
1028
  filtered[name] = mcpServers[name];
854
1029
  hasAny = true;
855
1030
  }
@@ -866,6 +1041,7 @@ function createProjectContext(opts) {
866
1041
  adapter: adapter,
867
1042
  adapters: adapters,
868
1043
  getNotificationsModule: function () { return _notifications; },
1044
+ shouldSuppressResponseNotification: opts.shouldSuppressResponseNotification,
869
1045
  mateDisplayName: opts.mateDisplayName || "",
870
1046
  isMate: isMate,
871
1047
  osUsers: osUsers,
@@ -879,6 +1055,7 @@ function createProjectContext(opts) {
879
1055
  onTurnDone: function (session, preview) {
880
1056
  if (isMate) digestDmTurn(session, preview);
881
1057
  else _sessionPair.handleTurnDone(session);
1058
+ if (session && typeof session.onTurnDone === "function") session.onTurnDone(session, preview);
882
1059
  },
883
1060
  scheduleMessage: function (session, text, resetsAt) {
884
1061
  scheduleMessage(session, text, resetsAt);
@@ -902,13 +1079,26 @@ function createProjectContext(opts) {
902
1079
  _sessionNotes.getSystemPrompt(session),
903
1080
  _sessionHandoff.getSystemPrompt(session),
904
1081
  _sessionDocument.getSystemPrompt(session),
1082
+ _capsuleCatalog.getSystemPrompt(session),
1083
+ _projectLogs.getSystemPrompt(session),
1084
+ _mateKnowledge.getSystemPrompt(session),
905
1085
  ]);
906
1086
  },
1087
+ getRuntimeEnv: getRuntimeEnvForSession,
1088
+ onUserInputRequest: function (session, request, respond) {
1089
+ return _askUser.createHandler(session)(request, respond);
1090
+ },
907
1091
  getSessionToolDefs: function (session) {
908
1092
  return _sessionPair.getToolDefs(session)
909
1093
  .concat(_sessionNotes.getToolDefs(session))
910
1094
  .concat(_sessionHandoff.getToolDefs(session))
911
- .concat(_sessionDocument.getToolDefs(session));
1095
+ .concat(_sessionDocument.getToolDefs(session))
1096
+ .concat(_debateProposal.getToolDefs(session))
1097
+ .concat(_mateCreationProposal.getToolDefs(session))
1098
+ .concat(_workspaceQuery.getDynamicToolDefs(session))
1099
+ .concat(_workspaceQuery.getHistoryDynamicToolDefs(session))
1100
+ .concat(_projectLogs.getDynamicToolDefs(session))
1101
+ .concat(_mateKnowledge.getDynamicToolDefs(session));
912
1102
  },
913
1103
  });
914
1104
 
@@ -1042,6 +1232,17 @@ function createProjectContext(opts) {
1042
1232
  }
1043
1233
 
1044
1234
  function handleMessage(ws, msg) {
1235
+ // --- Keep-alive (delegated to project-connection.js) ---
1236
+ // Answered before any routing so a ping can never be forwarded elsewhere.
1237
+ // _connection is assigned later in this factory than the other modules, so
1238
+ // the reference is guarded rather than assumed.
1239
+ if (_connection && _connection.handleKeepaliveMessage(ws, msg)) return;
1240
+
1241
+ if (ws._clayHomeDebateSlug && ws._clayHomeDebateSlug !== slug && /^debate_(hand_raise|comment|stop|conclude_response|user_floor_response)$/.test(msg.type || "") && opts.getProject) {
1242
+ var homeDebateCtx = opts.getProject(ws._clayHomeDebateSlug);
1243
+ if (homeDebateCtx) homeDebateCtx.handleMessage(ws, msg);
1244
+ return;
1245
+ }
1045
1246
  // --- Cross-project routing (e.g. permission_response from notification banner) ---
1046
1247
  if (msg.targetSlug && msg.targetSlug !== slug && opts.getProject) {
1047
1248
  var targetCtx = opts.getProject(msg.targetSlug);
@@ -1052,9 +1253,17 @@ function createProjectContext(opts) {
1052
1253
  }
1053
1254
 
1054
1255
  // --- 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") {
1256
+ if (msg.type === "home_debate_question_response" || msg.type === "home_debate_control" || msg.type === "home_mate_creation_question_response") {
1257
+ if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg);
1258
+ return;
1259
+ }
1260
+ if (msg.type === "home_clay_ask" || msg.type === "home_clay_session_resolve") {
1261
+ if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg, slug);
1262
+ return;
1263
+ }
1264
+ 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
1265
  if (typeof opts.onDmMessage === "function") {
1057
- opts.onDmMessage(ws, msg);
1266
+ opts.onDmMessage(ws, msg, slug);
1058
1267
  }
1059
1268
  return;
1060
1269
  }
@@ -1126,6 +1335,9 @@ function createProjectContext(opts) {
1126
1335
  // --- Knowledge file management (delegated to project-knowledge.js) ---
1127
1336
  if (_knowledge.handleKnowledgeMessage(ws, msg)) return;
1128
1337
 
1338
+ // --- Project Logs (delegated to project-logs.js) ---
1339
+ if (_projectLogs.handleLogsMessage(ws, msg)) return;
1340
+
1129
1341
  // --- Notifications (delegated to project-notifications.js) ---
1130
1342
  if (_notifications.handleNotificationMessage(ws, msg)) return;
1131
1343
 
@@ -1147,6 +1359,9 @@ function createProjectContext(opts) {
1147
1359
  // --- Shell command context ---
1148
1360
  if (_shellCommand.handleShellCommand(ws, msg)) return;
1149
1361
 
1362
+ // --- Vendor login flow (delegated to project-vendor-login.js) ---
1363
+ if (_vendorLogin.handleVendorLoginMessage(ws, msg)) return;
1364
+
1150
1365
  // --- Notes, terminals, context, user message (delegated to project-user-message.js) ---
1151
1366
  if (_userMessage.handleUserMessage(ws, msg)) return;
1152
1367
  }
@@ -1165,7 +1380,12 @@ function createProjectContext(opts) {
1165
1380
  sendTo: sendTo,
1166
1381
  matesModule: matesModule,
1167
1382
  sessionSearch: sessionSearch,
1168
- getAllProjectSessions: getAllProjectSessions,
1383
+ getWorkspaceMemorySessions: function () { return _workspaceQuery.getMemorySessions(true); },
1384
+ getOwnedCurrentSessions: function () {
1385
+ return _workspaceQuery.getMemorySessions(false).filter(function (session) {
1386
+ return session._projectSlug === slug;
1387
+ });
1388
+ },
1169
1389
  projectOwnerId: projectOwnerId,
1170
1390
  handleMessage: handleMessage,
1171
1391
  });
@@ -1246,6 +1466,8 @@ function createProjectContext(opts) {
1246
1466
  getSessionForWs: getSessionForWs,
1247
1467
  updateMemorySummary: updateMemorySummary,
1248
1468
  initMemorySummary: initMemorySummary,
1469
+ registerHomeDebateClient: function (ws) { if (ws) homeDebateClients.add(ws); },
1470
+ unregisterHomeDebateClient: function (ws) { homeDebateClients.delete(ws); },
1249
1471
  });
1250
1472
  var handleDebateStart = _debate.handleDebateStart;
1251
1473
  var handleDebateHandRaise = _debate.handleDebateHandRaise;
@@ -1294,6 +1516,11 @@ function createProjectContext(opts) {
1294
1516
  browserState._extensionId = null;
1295
1517
  if (_mcp) _mcp.handleExtensionDisconnect();
1296
1518
  }
1519
+ homeDebateClients.delete(ws);
1520
+ if (ws._clayHomeDebateSlug && ws._clayHomeDebateSlug !== slug && opts.getProject) {
1521
+ var debateProject = opts.getProject(ws._clayHomeDebateSlug);
1522
+ if (debateProject && typeof debateProject.unregisterHomeDebateClient === "function") debateProject.unregisterHomeDebateClient(ws);
1523
+ }
1297
1524
  _connection.handleDisconnection(ws);
1298
1525
  }
1299
1526
 
@@ -1317,6 +1544,7 @@ function createProjectContext(opts) {
1317
1544
  sendToSessionOthers: sendToSessionOthers,
1318
1545
  opts: opts,
1319
1546
  usersModule: usersModule,
1547
+ getProjectAccess: opts.getProjectAccess || function () { return { visibility: "public", ownerId: projectOwnerId || null }; },
1320
1548
  userPresence: userPresence,
1321
1549
  matesModule: matesModule,
1322
1550
  pushModule: pushModule,
@@ -1365,6 +1593,28 @@ function createProjectContext(opts) {
1365
1593
  serverTls: serverTls,
1366
1594
  serverAuthToken: serverAuthToken,
1367
1595
  });
1596
+ var _delegatedSession = attachDelegatedSession({
1597
+ sm: sm,
1598
+ getSdk: function () { return sdk; },
1599
+ getLinuxUserForSession: getLinuxUserForSession,
1600
+ resolveModel: function (principal) {
1601
+ var user = principal && principal.userId ? usersModule.findUserById(principal.userId) : null;
1602
+ return _models.resolveConfiguredModel({ _clayUser: user || null }, "standard");
1603
+ },
1604
+ });
1605
+ var _delegatedFollowUp = attachDelegatedFollowUp({
1606
+ sm: sm,
1607
+ getSdk: function () { return sdk; },
1608
+ getLinuxUserForSession: getLinuxUserForSession,
1609
+ onProcessingChanged: onProcessingChanged,
1610
+ isMultiUser: function () { return usersModule.isMultiUser(); },
1611
+ sessionRef: function (session) { return workspaceSessionRef(slug, session); },
1612
+ isPairedSession: function (session) { return !!_splitGroups.store.groupForMember(session.localId); },
1613
+ canResumeVendor: function (vendor) {
1614
+ var capabilities = sm.capabilitiesByVendor && sm.capabilitiesByVendor[vendor];
1615
+ return !!(capabilities && capabilities.sessionResume === true);
1616
+ },
1617
+ });
1368
1618
 
1369
1619
  // --- User message handler (delegated to project-user-message.js) ---
1370
1620
  var _userMessage = attachUserMessage({
@@ -1419,6 +1669,22 @@ function createProjectContext(opts) {
1419
1669
  getOsUserInfoForWs: getOsUserInfoForWs,
1420
1670
  });
1421
1671
 
1672
+ // --- Vendor login flow (delegated to project-vendor-login.js) ---
1673
+ var _vendorLogin = attachVendorLogin({
1674
+ slug: slug,
1675
+ osUsers: osUsers,
1676
+ sm: sm,
1677
+ tm: tm,
1678
+ adapters: adapters,
1679
+ send: send,
1680
+ sendTo: sendTo,
1681
+ usersModule: usersModule,
1682
+ getOsUserInfoForWs: getOsUserInfoForWs,
1683
+ getOsUserInfoForLinuxUser: getOsUserInfoForLinuxUser,
1684
+ getLinuxUserForSession: getLinuxUserForSession,
1685
+ refreshVendorAuthEverywhere: opts.refreshVendorAuthEverywhere,
1686
+ });
1687
+
1422
1688
  // --- Filesystem handler (delegated to project-filesystem.js) ---
1423
1689
  var _filesystem = attachFilesystem({
1424
1690
  cwd: cwd,
@@ -1436,6 +1702,7 @@ function createProjectContext(opts) {
1436
1702
  usersModule: usersModule,
1437
1703
  fsAsUser: fsAsUser,
1438
1704
  validateEnvString: validateEnvString,
1705
+ onEnvironmentChanged: function () { return sdk.refreshEnvironmentRuntime(); },
1439
1706
  opts: opts,
1440
1707
  IGNORED_DIRS: IGNORED_DIRS,
1441
1708
  BINARY_EXTS: BINARY_EXTS,
@@ -1531,6 +1798,18 @@ function createProjectContext(opts) {
1531
1798
  inputSchema: normalizeToolSchema(documentTools[dti].inputSchema),
1532
1799
  });
1533
1800
  }
1801
+ var debateTools = _debateProposal.getBridgeTools(boundSession, normalizeToolSchema);
1802
+ for (var dbti = 0; dbti < debateTools.length; dbti++) tools.push(debateTools[dbti]);
1803
+ var mateCreationTools = _mateCreationProposal.getBridgeTools(boundSession, normalizeToolSchema);
1804
+ for (var mcti = 0; mcti < mateCreationTools.length; mcti++) tools.push(mateCreationTools[mcti]);
1805
+ var workspaceTools = _workspaceQuery.getBridgeTools(boundSession, normalizeToolSchema);
1806
+ for (var wqti = 0; wqti < workspaceTools.length; wqti++) tools.push(workspaceTools[wqti]);
1807
+ var historyTools = _workspaceQuery.getHistoryBridgeTools(boundSession, normalizeToolSchema);
1808
+ for (var cht = 0; cht < historyTools.length; cht++) tools.push(historyTools[cht]);
1809
+ var logsTools = _projectLogs.getBridgeTools(boundSession, normalizeToolSchema);
1810
+ for (var plti = 0; plti < logsTools.length; plti++) tools.push(logsTools[plti]);
1811
+ var knowledgeTools = _mateKnowledge.getBridgeTools(boundSession, normalizeToolSchema);
1812
+ for (var mkti = 0; mkti < knowledgeTools.length; mkti++) tools.push(knowledgeTools[mkti]);
1534
1813
  }
1535
1814
 
1536
1815
  if (sessionOnly) return Promise.resolve(tools);
@@ -1543,6 +1822,10 @@ function createProjectContext(opts) {
1543
1822
  var inAppNames = Object.keys(localMcp);
1544
1823
  for (var i = 0; i < inAppNames.length; i++) {
1545
1824
  if (inAppNames[i] === "clay-sessions" || inAppNames[i] === "clay-notes" || inAppNames[i] === "clay-handoff" || inAppNames[i] === "clay-documents") continue;
1825
+ // Debate tools were added above only when this request had an
1826
+ // exact session. Never duplicate them or advertise the static,
1827
+ // intentionally unbound proposal server.
1828
+ if (inAppNames[i] === "clay-debate" || inAppNames[i] === "clay-mate-creation" || inAppNames[i] === "clay-workspace" || inAppNames[i] === "clay-history" || inAppNames[i] === "clay-logs" || inAppNames[i] === "clay-knowledge") continue;
1546
1829
  extractServerTools(inAppNames[i], localMcp[inAppNames[i]]);
1547
1830
  }
1548
1831
  }
@@ -1593,7 +1876,25 @@ function createProjectContext(opts) {
1593
1876
  }
1594
1877
  }
1595
1878
  }
1596
- if (serverName === "clay-sessions" || serverName === "clay-notes" || serverName === "clay-handoff" || serverName === "clay-documents") {
1879
+ if (boundSession && serverName === "clay-debate") {
1880
+ return _debateProposal.callBridgeTool(boundSession, toolName, args);
1881
+ }
1882
+ if (boundSession && serverName === "clay-mate-creation") {
1883
+ return _mateCreationProposal.callBridgeTool(boundSession, toolName, args);
1884
+ }
1885
+ if (boundSession && serverName === "clay-workspace") {
1886
+ return _workspaceQuery.callBridgeTool(boundSession, toolName, args);
1887
+ }
1888
+ if (boundSession && serverName === "clay-history") {
1889
+ return _workspaceQuery.callHistoryBridgeTool(boundSession, toolName, args);
1890
+ }
1891
+ if (boundSession && serverName === "clay-logs") {
1892
+ return _projectLogs.callBridgeTool(boundSession, toolName, args);
1893
+ }
1894
+ if (boundSession && serverName === "clay-knowledge") {
1895
+ return _mateKnowledge.callBridgeTool(boundSession, toolName, args);
1896
+ }
1897
+ 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" || serverName === "clay-logs" || serverName === "clay-knowledge") {
1597
1898
  return Promise.reject(new Error("Session-bound tool requires a valid Clay session: " + serverName + "/" + toolName));
1598
1899
  }
1599
1900
  if (sessionOnly) return Promise.reject(new Error("Session tool not found: " + serverName + "/" + toolName));
@@ -1667,6 +1968,7 @@ function createProjectContext(opts) {
1667
1968
  _mcp: _mcp,
1668
1969
  _notifications: _notifications,
1669
1970
  _splitGroups: _splitGroups,
1971
+ _vendorLogin: _vendorLogin,
1670
1972
  resolveSessionForView: _sessions.resolveSessionForView,
1671
1973
  hydrateImageRefs: hydrateImageRefs,
1672
1974
  broadcastClientCount: broadcastClientCount,
@@ -1807,7 +2109,7 @@ function createProjectContext(opts) {
1807
2109
  };
1808
2110
  if (isMate) {
1809
2111
  status.isMate = true;
1810
- status.mateId = path.basename(cwd);
2112
+ status.mateId = mateId;
1811
2113
  }
1812
2114
  if (worktreeMeta) {
1813
2115
  status.isWorktree = true;
@@ -1908,7 +2210,21 @@ function createProjectContext(opts) {
1908
2210
  getMcpBridgeHandler: getMcpBridgeHandler,
1909
2211
  getStatus: getStatus,
1910
2212
  getSessionManager: function () { return sm; },
2213
+ createDelegatedSession: _delegatedSession.createDelegatedSession,
2214
+ inspectDelegatedFollowUp: _delegatedFollowUp.inspectDelegatedFollowUp,
2215
+ dispatchDelegatedFollowUp: _delegatedFollowUp.dispatchDelegatedFollowUp,
2216
+ unregisterHomeDebateClient: function (ws) { homeDebateClients.delete(ws); },
2217
+ handleHomeDebateProposalResponse: function (ws, msg, session) { return _debateProposal.handleHomeMessage(ws, msg, session); },
2218
+ handleHomeMateCreationProposalResponse: function (ws, msg, session) { return _mateCreationProposal.handleHomeMessage(ws, msg, session); },
2219
+ handleHomeAskUserResponse: function (msg, session) { return _sessions.respondToAskUser(session, msg); },
2220
+ handleHomeDebateControl: function (ws, msg, session) { return _debate.handleHomeControl(ws, msg, session); },
2221
+ getVendorModelCatalog: _models.getVendorCatalog,
2222
+ getVendorModelAvailability: _models.getVendorAvailability,
2223
+ getMemoryState: _memory.readMemoryState,
2224
+ listKnowledgeFiles: _knowledge.listKnowledgeFiles,
2225
+ refreshCapsuleCatalog: _capsuleCatalog.refreshSessions,
1911
2226
  getNotificationsModule: function () { return _notifications; },
2227
+ refreshVendorAuth: _vendorLogin.refreshVendorAuth,
1912
2228
  getSchedules: _loop.getSchedules,
1913
2229
  importSchedule: _loop.importSchedule,
1914
2230
  removeSchedule: _loop.removeSchedule,
@@ -1916,6 +2232,21 @@ function createProjectContext(opts) {
1916
2232
  setIcon: setIcon,
1917
2233
  setProjectOwner: function (ownerId) { projectOwnerId = ownerId; },
1918
2234
  getProjectOwner: function () { return projectOwnerId; },
2235
+ getToolLlmConfig: function (ws, alias) {
2236
+ return _models.resolveConfiguredModel(ws, alias);
2237
+ },
2238
+ completeToolLlm: async function (ws, args) {
2239
+ var owner = projectOwnerId ? usersModule.findUserById(projectOwnerId) : null;
2240
+ var selection = await _models.resolveConfiguredModel(ws, args.model);
2241
+ return toolLlm.complete({
2242
+ adapters: adapters,
2243
+ cwd: cwd,
2244
+ linuxUser: owner && owner.linuxUser ? owner.linuxUser : null,
2245
+ args: args,
2246
+ selection: selection,
2247
+ timeoutMs: 60000,
2248
+ });
2249
+ },
1919
2250
  refreshUserProfile: function (userId) {
1920
2251
  var user = usersModule.findUserById(userId);
1921
2252
  if (!user) return;
@@ -1934,4 +2265,4 @@ function createProjectContext(opts) {
1934
2265
  };
1935
2266
  }
1936
2267
 
1937
- module.exports = { createProjectContext: createProjectContext, safePath: safePath, validateEnvString: validateEnvString };
2268
+ module.exports = { createProjectContext: createProjectContext, createMateToolControlMcp: createMateToolControlMcp, safePath: safePath, validateEnvString: validateEnvString };