clay-server 5.2.0-beta.1 → 5.2.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 (552) hide show
  1. package/lib/account-auth-socket.js +1 -0
  2. package/lib/builtin-mates.js +19 -16
  3. package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
  4. package/lib/canonical-clay-record-authority.js +15 -0
  5. package/lib/canonical-clay-scheduling-authority.js +19 -0
  6. package/lib/claude-hook-installer.js +1 -239
  7. package/lib/claude-jsonl-watcher.js +1 -204
  8. package/lib/clay-control-presentation-binding.js +96 -0
  9. package/lib/clay-control-presentation.js +128 -0
  10. package/lib/clay-control-target-projection.js +26 -0
  11. package/lib/clay-mate-chat-receipts.js +26 -0
  12. package/lib/clay-mate-chat.js +88 -0
  13. package/lib/clay-mate-knowledge-input.js +26 -0
  14. package/lib/clay-mate-knowledge.js +95 -0
  15. package/lib/clay-mate-lifecycle.js +95 -0
  16. package/lib/clay-product-control-input.js +33 -0
  17. package/lib/clay-product-control-tools.js +51 -0
  18. package/lib/clay-product-control.js +247 -0
  19. package/lib/clay-project-lifecycle.js +154 -0
  20. package/lib/clay-project-record-input.js +44 -0
  21. package/lib/clay-project-records.js +84 -0
  22. package/lib/clay-scheduling-input.js +21 -0
  23. package/lib/clay-scheduling-receipts.js +26 -0
  24. package/lib/clay-scheduling.js +119 -0
  25. package/lib/clay-screen-controls.js +104 -0
  26. package/lib/clay-skill-install.js +1 -33
  27. package/lib/clay-workspace-controls.js +84 -0
  28. package/lib/clay-workspace-input.js +17 -0
  29. package/lib/clay-workspace-receipts.js +26 -0
  30. package/lib/cli-sessions.js +1 -300
  31. package/lib/codex-defaults.js +1 -28
  32. package/lib/context-usage.js +3 -2
  33. package/lib/contextual-screen-snapshot.js +38 -0
  34. package/lib/daemon-project-access.js +11 -0
  35. package/lib/daemon-project-lifecycle-callbacks.js +15 -0
  36. package/lib/daemon-project-lifecycle.js +262 -0
  37. package/lib/daemon-projects.js +1 -1
  38. package/lib/daemon.js +78 -276
  39. package/lib/default-ai-runtime.js +4 -8
  40. package/lib/dm-digest-cursor.js +120 -0
  41. package/lib/email-mcp-server.js +1 -1
  42. package/lib/issues-service.js +29 -15
  43. package/lib/kiro-defaults.js +1 -22
  44. package/lib/knowledge-db-import-validation.js +46 -0
  45. package/lib/knowledge-db-import.js +99 -0
  46. package/lib/knowledge-db-service.js +24 -33
  47. package/lib/knowledge-db-storage-nedb-maintenance.js +99 -0
  48. package/lib/knowledge-db-storage-nedb.js +66 -0
  49. package/lib/knowledge-db-storage.js +72 -0
  50. package/lib/knowledge-db-validation.js +0 -0
  51. package/lib/knowledge-document-index.js +2 -1
  52. package/lib/knowledge-file-store.js +7 -1
  53. package/lib/knowledge-product-operations.js +46 -0
  54. package/lib/mate-avatar-catalog.js +12 -0
  55. package/lib/mate-avatar-migration.js +41 -0
  56. package/lib/mate-context-service.js +138 -0
  57. package/lib/mate-context-tools.js +21 -0
  58. package/lib/mate-creation-mcp-server.js +2 -0
  59. package/lib/mate-knowledge-canonical-access.js +10 -0
  60. package/lib/mate-knowledge-mate-bound.js +53 -0
  61. package/lib/mate-knowledge-mcp-server.js +55 -8
  62. package/lib/mate-knowledge-service.js +16 -34
  63. package/lib/mate-knowledge-text-tools.js +106 -0
  64. package/lib/mate-lifecycle-service.js +94 -0
  65. package/lib/mate-message-delivery.js +43 -0
  66. package/lib/mate-ready-creation.js +9 -1
  67. package/lib/mate-schedule-input.js +29 -0
  68. package/lib/mate-schedule-lifecycle.js +151 -0
  69. package/lib/mate-scheduling.js +103 -0
  70. package/lib/mates.js +18 -6
  71. package/lib/mcp-agent-tools.js +117 -0
  72. package/lib/mcp-connection-store.js +119 -15
  73. package/lib/mcp-import-credentials.js +31 -0
  74. package/lib/mcp-local-transport.js +13 -0
  75. package/lib/mcp-oauth.js +8 -6
  76. package/lib/mcp-proxy.js +2 -32
  77. package/lib/mcp-query-bridge.js +30 -0
  78. package/lib/mcp-remote-connections.js +74 -20
  79. package/lib/mcp-source-adapters.js +1 -0
  80. package/lib/mcp-source-context.js +1 -0
  81. package/lib/mcp-source-discovery.js +1 -0
  82. package/lib/mcp-source-plugins.js +1 -0
  83. package/lib/mcp-source-restrictions.js +1 -0
  84. package/lib/mcp-tool-policy.js +9 -0
  85. package/lib/notes-checklist.js +50 -0
  86. package/lib/notes.js +49 -3
  87. package/lib/os-user-diagnostics.js +2 -4
  88. package/lib/os-users.js +24 -70
  89. package/lib/pane-pending-interactions.js +20 -0
  90. package/lib/pane-session-activation.js +114 -0
  91. package/lib/pane-session-transport.js +26 -0
  92. package/lib/project-admin-overview.js +51 -0
  93. package/lib/project-ask-user.js +8 -4
  94. package/lib/project-connection.js +14 -10
  95. package/lib/project-control-git-view.js +12 -0
  96. package/lib/project-debate.js +1 -0
  97. package/lib/project-delegated-follow-up.js +2 -1
  98. package/lib/project-directory-claim.js +65 -0
  99. package/lib/project-file-operations.js +61 -0
  100. package/lib/project-filesystem.js +15 -85
  101. package/lib/project-full-access.js +23 -2
  102. package/lib/project-http.js +7 -4
  103. package/lib/project-knowledge.js +32 -18
  104. package/lib/project-lifecycle-operations.js +98 -0
  105. package/lib/project-lifecycle-process-witness.js +32 -0
  106. package/lib/project-lifecycle-runtime.js +50 -0
  107. package/lib/project-linux-access.js +22 -0
  108. package/lib/project-logs-canonical-clay.js +27 -0
  109. package/lib/project-logs-clay-query.js +16 -0
  110. package/lib/project-logs-schema.js +4 -2
  111. package/lib/project-logs-service.js +8 -7
  112. package/lib/project-logs.js +1 -0
  113. package/lib/project-loop.js +1 -0
  114. package/lib/project-mate-chat-control.js +55 -0
  115. package/lib/project-mate-creation-proposal.js +18 -3
  116. package/lib/project-mate-interaction.js +40 -62
  117. package/lib/project-mcp.js +54 -16
  118. package/lib/project-models.js +14 -31
  119. package/lib/project-notifications.js +76 -17
  120. package/lib/project-ownership.js +77 -0
  121. package/lib/project-pair-result-delivery.js +14 -3
  122. package/lib/project-pair-usage.js +12 -13
  123. package/lib/project-pending-message-queue.js +4 -1
  124. package/lib/project-product-control.js +89 -0
  125. package/lib/project-product-session-queue.js +46 -0
  126. package/lib/project-push-access.js +28 -0
  127. package/lib/project-scheduled-message-queue.js +30 -0
  128. package/lib/project-scheduled-messages.js +67 -68
  129. package/lib/project-scheduled-task-control.js +83 -0
  130. package/lib/project-scheduled-tasks.js +13 -2
  131. package/lib/project-scheduling-access.js +10 -0
  132. package/lib/project-session-actions.js +65 -0
  133. package/lib/project-session-delete.js +8 -1
  134. package/lib/project-session-document.js +27 -7
  135. package/lib/project-session-github.js +63 -19
  136. package/lib/project-session-history-actions.js +167 -0
  137. package/lib/project-session-linear.js +14 -6
  138. package/lib/project-session-notes.js +7 -3
  139. package/lib/project-session-pair.js +1 -1
  140. package/lib/project-session-runtime-actions.js +64 -0
  141. package/lib/project-session-spawn.js +2 -3
  142. package/lib/project-session-vendor.js +55 -0
  143. package/lib/project-sessions.js +103 -272
  144. package/lib/project-shared-browser.js +78 -17
  145. package/lib/project-studio-presentation.js +58 -0
  146. package/lib/project-user-message.js +67 -1
  147. package/lib/project-vendor-login.js +6 -36
  148. package/lib/project-workspace-operations.js +126 -0
  149. package/lib/project-workspace-query.js +19 -2
  150. package/lib/project.js +178 -45
  151. package/lib/public/app.js +46 -0
  152. package/lib/public/appearance-bootstrap.js +16 -0
  153. package/lib/public/css/clay-tool-activity.css +51 -0
  154. package/lib/public/css/clay-workspace.css +29 -0
  155. package/lib/public/css/command-palette.css +12 -33
  156. package/lib/public/css/contextual-clay.css +240 -0
  157. package/lib/public/css/home-debate-planning.css +2 -0
  158. package/lib/public/css/home-mate-creation.css +5 -0
  159. package/lib/public/css/input.css +6 -0
  160. package/lib/public/css/mate-avatar-gallery.css +12 -0
  161. package/lib/public/css/mate-conversation.css +10 -5
  162. package/lib/public/css/messages.css +6 -2
  163. package/lib/public/css/overlays.css +4 -2
  164. package/lib/public/css/project-admin-overview.css +13 -0
  165. package/lib/public/css/session-folders.css +11 -0
  166. package/lib/public/css/session-github.css +46 -1
  167. package/lib/public/css/shared-browser.css +35 -1
  168. package/lib/public/css/sticky-notes.css +87 -1
  169. package/lib/public/index.html +11 -5
  170. package/lib/public/mate-avatars/B01.png +0 -0
  171. package/lib/public/mate-avatars/B02.png +0 -0
  172. package/lib/public/mate-avatars/B03.png +0 -0
  173. package/lib/public/mate-avatars/B04.png +0 -0
  174. package/lib/public/mate-avatars/B05.png +0 -0
  175. package/lib/public/mate-avatars/B06.png +0 -0
  176. package/lib/public/mate-avatars/B07.png +0 -0
  177. package/lib/public/mate-avatars/B08.png +0 -0
  178. package/lib/public/mate-avatars/B09.png +0 -0
  179. package/lib/public/mate-avatars/B10.png +0 -0
  180. package/lib/public/mate-avatars/B11.png +0 -0
  181. package/lib/public/mate-avatars/B12.png +0 -0
  182. package/lib/public/mate-avatars/B13.png +0 -0
  183. package/lib/public/mate-avatars/B14.png +0 -0
  184. package/lib/public/mate-avatars/B15.png +0 -0
  185. package/lib/public/mate-avatars/B16.png +0 -0
  186. package/lib/public/mate-avatars/B17.png +0 -0
  187. package/lib/public/mate-avatars/B18.png +0 -0
  188. package/lib/public/mate-avatars/B19.png +0 -0
  189. package/lib/public/mate-avatars/B20.png +0 -0
  190. package/lib/public/mate-avatars/B21.png +0 -0
  191. package/lib/public/mate-avatars/B22.png +0 -0
  192. package/lib/public/mate-avatars/B23.png +0 -0
  193. package/lib/public/mate-avatars/B24.png +0 -0
  194. package/lib/public/mate-avatars/B25.png +0 -0
  195. package/lib/public/mate-avatars/B26.png +0 -0
  196. package/lib/public/mate-avatars/B27.png +0 -0
  197. package/lib/public/mate-avatars/B28.png +0 -0
  198. package/lib/public/mate-avatars/B29.png +0 -0
  199. package/lib/public/mate-avatars/B30.png +0 -0
  200. package/lib/public/mate-avatars/B31.png +0 -0
  201. package/lib/public/mate-avatars/B32.png +0 -0
  202. package/lib/public/mate-avatars/B33.png +0 -0
  203. package/lib/public/mate-avatars/B34.png +0 -0
  204. package/lib/public/mate-avatars/B35.png +0 -0
  205. package/lib/public/mate-avatars/B36.png +0 -0
  206. package/lib/public/mate-avatars/B37.png +0 -0
  207. package/lib/public/mate-avatars/B38.png +0 -0
  208. package/lib/public/mate-avatars/B39.png +0 -0
  209. package/lib/public/mate-avatars/B40.png +0 -0
  210. package/lib/public/mate-avatars/B41.png +0 -0
  211. package/lib/public/mate-avatars/B42.png +0 -0
  212. package/lib/public/mate-avatars/B43.png +0 -0
  213. package/lib/public/mate-avatars/B44.png +0 -0
  214. package/lib/public/mate-avatars/B45.png +0 -0
  215. package/lib/public/mate-avatars/B46.png +0 -0
  216. package/lib/public/mate-avatars/B47.png +0 -0
  217. package/lib/public/mate-avatars/B48.png +0 -0
  218. package/lib/public/mate-avatars/C01.png +0 -0
  219. package/lib/public/mate-avatars/C02.png +0 -0
  220. package/lib/public/mate-avatars/C03.png +0 -0
  221. package/lib/public/mate-avatars/C04.png +0 -0
  222. package/lib/public/mate-avatars/C05.png +0 -0
  223. package/lib/public/mate-avatars/C06.png +0 -0
  224. package/lib/public/mate-avatars/C07.png +0 -0
  225. package/lib/public/mate-avatars/C08.png +0 -0
  226. package/lib/public/mate-avatars/C09.png +0 -0
  227. package/lib/public/mate-avatars/C10.png +0 -0
  228. package/lib/public/mate-avatars/C11.png +0 -0
  229. package/lib/public/mate-avatars/C12.png +0 -0
  230. package/lib/public/mate-avatars/C13.png +0 -0
  231. package/lib/public/mate-avatars/C14.png +0 -0
  232. package/lib/public/mate-avatars/C15.png +0 -0
  233. package/lib/public/mate-avatars/C16.png +0 -0
  234. package/lib/public/mate-avatars/C17.png +0 -0
  235. package/lib/public/mate-avatars/C18.png +0 -0
  236. package/lib/public/mate-avatars/C19.png +0 -0
  237. package/lib/public/mate-avatars/C20.png +0 -0
  238. package/lib/public/mate-avatars/C21.png +0 -0
  239. package/lib/public/mate-avatars/C22.png +0 -0
  240. package/lib/public/mate-avatars/C23.png +0 -0
  241. package/lib/public/mate-avatars/C24.png +0 -0
  242. package/lib/public/mate-avatars/C25.png +0 -0
  243. package/lib/public/mate-avatars/C26.png +0 -0
  244. package/lib/public/mate-avatars/C27.png +0 -0
  245. package/lib/public/mate-avatars/C28.png +0 -0
  246. package/lib/public/mate-avatars/C29.png +0 -0
  247. package/lib/public/mate-avatars/C30.png +0 -0
  248. package/lib/public/mate-avatars/C31.png +0 -0
  249. package/lib/public/mate-avatars/C32.png +0 -0
  250. package/lib/public/mate-avatars/C33.png +0 -0
  251. package/lib/public/mate-avatars/C34.png +0 -0
  252. package/lib/public/mate-avatars/C35.png +0 -0
  253. package/lib/public/mate-avatars/C36.png +0 -0
  254. package/lib/public/mate-avatars/C37.png +0 -0
  255. package/lib/public/mate-avatars/C38.png +0 -0
  256. package/lib/public/mate-avatars/C39.png +0 -0
  257. package/lib/public/mate-avatars/C40.png +0 -0
  258. package/lib/public/mate-avatars/C41.png +0 -0
  259. package/lib/public/mate-avatars/C42.png +0 -0
  260. package/lib/public/mate-avatars/C43.png +0 -0
  261. package/lib/public/mate-avatars/C44.png +0 -0
  262. package/lib/public/mate-avatars/C45.png +0 -0
  263. package/lib/public/mate-avatars/C46.png +0 -0
  264. package/lib/public/mate-avatars/C47.png +0 -0
  265. package/lib/public/mate-avatars/C48.png +0 -0
  266. package/lib/public/mate-avatars/catalog.json +482 -0
  267. package/lib/public/mate-avatars/lead-clay.png +0 -0
  268. package/lib/public/modules/admin-settings-projects.js +6 -2
  269. package/lib/public/modules/app-connection.js +11 -1
  270. package/lib/public/modules/app-favicon.js +18 -9
  271. package/lib/public/modules/app-header.js +7 -4
  272. package/lib/public/modules/app-loop-ui.js +2 -0
  273. package/lib/public/modules/app-message-router.js +22 -1
  274. package/lib/public/modules/app-messages.js +115 -17
  275. package/lib/public/modules/app-misc.js +3 -1
  276. package/lib/public/modules/app-notifications.js +11 -5
  277. package/lib/public/modules/app-panels.js +61 -123
  278. package/lib/public/modules/app-projects.js +13 -0
  279. package/lib/public/modules/app-rate-limit.js +7 -27
  280. package/lib/public/modules/app-rendering.js +4 -3
  281. package/lib/public/modules/avatar.js +15 -41
  282. package/lib/public/modules/chat-render-runtime.js +20 -0
  283. package/lib/public/modules/clay-browser-links.js +47 -0
  284. package/lib/public/modules/clay-control-activity.js +214 -0
  285. package/lib/public/modules/clay-control-copy.js +36 -0
  286. package/lib/public/modules/clay-control-detail-targets.js +44 -0
  287. package/lib/public/modules/clay-control-object-targets.js +52 -0
  288. package/lib/public/modules/clay-control-target-visibility.js +12 -0
  289. package/lib/public/modules/clay-control-targets.js +44 -0
  290. package/lib/public/modules/clay-log-links.js +23 -0
  291. package/lib/public/modules/clay-navigation-render.js +52 -0
  292. package/lib/public/modules/clay-owner-navigation.js +33 -0
  293. package/lib/public/modules/clay-session-links.js +31 -0
  294. package/lib/public/modules/clay-studio-bridge.js +20 -0
  295. package/lib/public/modules/clay-studio-document.js +67 -0
  296. package/lib/public/modules/clay-studio-render.js +146 -0
  297. package/lib/public/modules/clay-tool-activity.js +140 -0
  298. package/lib/public/modules/clay-tool-presentation.js +342 -0
  299. package/lib/public/modules/command-palette.js +162 -40
  300. package/lib/public/modules/contextual-ask-session.js +26 -0
  301. package/lib/public/modules/contextual-clay-geometry.js +155 -0
  302. package/lib/public/modules/contextual-clay-session.js +130 -0
  303. package/lib/public/modules/contextual-clay-workspace.js +169 -0
  304. package/lib/public/modules/contextual-clay.js +250 -0
  305. package/lib/public/modules/contextual-composer.js +91 -0
  306. package/lib/public/modules/contextual-mate-context.js +117 -0
  307. package/lib/public/modules/contextual-mate-hint.js +40 -0
  308. package/lib/public/modules/contextual-mate-identity.js +23 -0
  309. package/lib/public/modules/contextual-mate-sessions.js +134 -0
  310. package/lib/public/modules/contextual-search.js +137 -0
  311. package/lib/public/modules/contextual-session-citations.js +58 -0
  312. package/lib/public/modules/debate.js +1 -0
  313. package/lib/public/modules/default-ai.js +11 -3
  314. package/lib/public/modules/elicitation-form.js +5 -0
  315. package/lib/public/modules/filebrowser.js +20 -1
  316. package/lib/public/modules/generation-stop.js +8 -5
  317. package/lib/public/modules/git-panel.js +3 -1
  318. package/lib/public/modules/history-replay-batch.js +13 -1
  319. package/lib/public/modules/home-debate-live.js +2 -0
  320. package/lib/public/modules/home-debate-planning.js +7 -7
  321. package/lib/public/modules/home-mate-avatar-editor.js +127 -208
  322. package/lib/public/modules/home-mate-chat.js +8 -6
  323. package/lib/public/modules/home-mate-creation.js +73 -1
  324. package/lib/public/modules/home-mate-settings.js +19 -12
  325. package/lib/public/modules/icon-strip-tooltip.js +2 -1
  326. package/lib/public/modules/input.js +88 -10
  327. package/lib/public/modules/issues-render.js +3 -2
  328. package/lib/public/modules/knowledge-db-workbench.js +4 -4
  329. package/lib/public/modules/markdown.js +6 -34
  330. package/lib/public/modules/mate-avatar-catalog.js +97 -0
  331. package/lib/public/modules/mate-knowledge-workbench.js +1 -1
  332. package/lib/public/modules/mate-management.js +40 -7
  333. package/lib/public/modules/mcp-connection-view.js +31 -13
  334. package/lib/public/modules/mcp-discovery-view.js +31 -0
  335. package/lib/public/modules/mcp-ui.js +23 -4
  336. package/lib/public/modules/mention.js +3 -0
  337. package/lib/public/modules/message-delivery.js +20 -2
  338. package/lib/public/modules/model-picker.js +2 -0
  339. package/lib/public/modules/pane-activation.js +214 -0
  340. package/lib/public/modules/pane-binding.js +82 -0
  341. package/lib/public/modules/pane-bridge.js +7 -4
  342. package/lib/public/modules/pane-browser-bridge.js +22 -0
  343. package/lib/public/modules/pane-file-bridge.js +4 -0
  344. package/lib/public/modules/pane-issue-bridge.js +4 -1
  345. package/lib/public/modules/pending-message-queue.js +1 -0
  346. package/lib/public/modules/permission-control.js +5 -4
  347. package/lib/public/modules/personal-settings-dialog.js +7 -1
  348. package/lib/public/modules/product-review.js +26 -0
  349. package/lib/public/modules/profile.js +1 -238
  350. package/lib/public/modules/project-access-recovery.js +17 -0
  351. package/lib/public/modules/project-admin-overview.js +21 -0
  352. package/lib/public/modules/project-chat-identity.js +13 -4
  353. package/lib/public/modules/project-logs-render.js +3 -0
  354. package/lib/public/modules/project-mate-navigation.js +144 -22
  355. package/lib/public/modules/rewind.js +5 -0
  356. package/lib/public/modules/scheduled-tasks.js +2 -0
  357. package/lib/public/modules/scheduler.js +2 -0
  358. package/lib/public/modules/search-clay-chat.js +5 -440
  359. package/lib/public/modules/session-actions.js +5 -2
  360. package/lib/public/modules/session-context-menu.js +5 -0
  361. package/lib/public/modules/session-create-form.js +10 -10
  362. package/lib/public/modules/session-folder-layout.js +1 -1
  363. package/lib/public/modules/session-folder-view-menu.js +9 -0
  364. package/lib/public/modules/session-github.js +85 -14
  365. package/lib/public/modules/session-rich-drafts.js +21 -0
  366. package/lib/public/modules/session-switch-defer.js +67 -0
  367. package/lib/public/modules/session-work-primary.js +51 -0
  368. package/lib/public/modules/settings-defaults.js +27 -28
  369. package/lib/public/modules/shared-browser-settings.js +112 -0
  370. package/lib/public/modules/shared-browser-tabs.js +13 -3
  371. package/lib/public/modules/shared-browser.js +29 -6
  372. package/lib/public/modules/sidebar-mobile.js +4 -3
  373. package/lib/public/modules/sidebar-projects.js +1 -0
  374. package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
  375. package/lib/public/modules/sidebar-sessions.js +1 -0
  376. package/lib/public/modules/split-group-restore.js +68 -0
  377. package/lib/public/modules/split-pair-ui.js +1 -0
  378. package/lib/public/modules/split-pane-reconciler.js +15 -0
  379. package/lib/public/modules/split-pane-renderer.js +87 -6
  380. package/lib/public/modules/split-session-boundary.js +1 -1
  381. package/lib/public/modules/split-view.js +60 -68
  382. package/lib/public/modules/sticky-note-markdown.js +72 -6
  383. package/lib/public/modules/sticky-notes-actions.js +30 -0
  384. package/lib/public/modules/sticky-notes-browser.js +9 -2
  385. package/lib/public/modules/sticky-notes-card.js +23 -7
  386. package/lib/public/modules/sticky-notes-checklist.js +116 -0
  387. package/lib/public/modules/sticky-notes-editor.js +108 -44
  388. package/lib/public/modules/sticky-notes-shared.js +50 -2
  389. package/lib/public/modules/sticky-notes-state.js +66 -0
  390. package/lib/public/modules/sticky-notes.js +34 -51
  391. package/lib/public/modules/stt-controller.js +4 -1
  392. package/lib/public/modules/stt-recording.js +1 -1
  393. package/lib/public/modules/stt.js +7 -2
  394. package/lib/public/modules/terminal.js +9 -0
  395. package/lib/public/modules/theme.js +8 -1
  396. package/lib/public/modules/thinking-lifecycle.js +33 -3
  397. package/lib/public/modules/thinking-view.js +23 -1
  398. package/lib/public/modules/tools.js +60 -11
  399. package/lib/public/modules/tui-grab.js +1 -2
  400. package/lib/public/modules/user-settings-appearance.js +10 -3
  401. package/lib/public/modules/user-settings-editors.js +1 -1
  402. package/lib/public/modules/user-settings-layout.js +11 -2
  403. package/lib/public/modules/user-settings-preferences.js +6 -2
  404. package/lib/public/modules/user-settings-profile.js +12 -2
  405. package/lib/public/modules/user-settings.js +3 -2
  406. package/lib/public/modules/vendor-login-browser.js +5 -3
  407. package/lib/public/modules/vendor-login.js +2 -2
  408. package/lib/public/modules/vendor-priority.js +15 -1
  409. package/lib/public/modules/wireframe-workbench.js +5 -2
  410. package/lib/public/muse-avatar.svg +4 -0
  411. package/lib/public/style.css +5 -0
  412. package/lib/public/sw.js +3 -1
  413. package/lib/safe-bash-commands.js +3 -45
  414. package/lib/scheduled-task-records.js +3 -1
  415. package/lib/scheduler.js +2 -0
  416. package/lib/sdk-bridge.js +342 -401
  417. package/lib/sdk-foreground-admission.js +16 -0
  418. package/lib/sdk-mcp-descriptors.js +2 -37
  419. package/lib/sdk-message-processor.js +52 -17
  420. package/lib/sdk-quota-snapshot.js +1 -1
  421. package/lib/sdk-response-recovery.js +1 -0
  422. package/lib/sdk-worker.js +2 -677
  423. package/lib/server-admin.js +63 -16
  424. package/lib/server-appearance-settings.js +13 -1
  425. package/lib/server-contextual-clay-settings.js +40 -0
  426. package/lib/server-contextual-mate-sessions.js +70 -0
  427. package/lib/server-dm.js +2 -1
  428. package/lib/server-global-ws.js +10 -20
  429. package/lib/server-home-chat-events.js +18 -4
  430. package/lib/server-home-chat.js +22 -20
  431. package/lib/server-home-clay-entry.js +23 -4
  432. package/lib/server-home-clay-session-links.js +29 -9
  433. package/lib/server-home-mate-creation.js +1 -0
  434. package/lib/server-home-mcp-consent.js +14 -0
  435. package/lib/server-mates.js +25 -62
  436. package/lib/server-owner-ui.js +118 -0
  437. package/lib/server-path-access.js +38 -0
  438. package/lib/server-project-removal.js +22 -0
  439. package/lib/server-settings.js +6 -1
  440. package/lib/server.js +163 -43
  441. package/lib/session-config-transition.js +45 -0
  442. package/lib/session-folders.js +7 -2
  443. package/lib/session-fork-history.js +21 -0
  444. package/lib/session-github.js +9 -2
  445. package/lib/session-hygiene.js +3 -35
  446. package/lib/session-permission-mode.js +4 -3
  447. package/lib/session-skill-scope.js +11 -0
  448. package/lib/session-visibility.js +5 -2
  449. package/lib/session-work-primary.js +50 -0
  450. package/lib/sessions.js +64 -99
  451. package/lib/shared-browser-cookie-sync.js +32 -0
  452. package/lib/shared-browser-cookies.js +79 -0
  453. package/lib/shared-browser-runtime.js +25 -9
  454. package/lib/shared-browser-storage-sync.js +43 -0
  455. package/lib/shared-browser-storage.js +101 -0
  456. package/lib/shared-browser-tools.js +2 -1
  457. package/lib/shared-browser-worker.js +46 -10
  458. package/lib/terminal-manager.js +65 -6
  459. package/lib/tool-llm.js +1 -1
  460. package/lib/tui-transcript-index.js +1 -132
  461. package/lib/users-contextual-clay-preferences.js +31 -0
  462. package/lib/users-permissions.js +2 -8
  463. package/lib/users.js +7 -0
  464. package/lib/vendor-login-browser.js +1 -11
  465. package/lib/workspace-assignment-service.js +25 -0
  466. package/lib/workspace-query-access.js +4 -1
  467. package/lib/workspace-query-mcp-server.js +1 -1
  468. package/lib/workspace-query-service.js +13 -2
  469. package/lib/ws-request.js +1 -0
  470. package/lib/ws-schema.js +18 -2
  471. package/lib/yoke/acp-agent-profiles.js +7 -5
  472. package/lib/yoke/adapters/antigravity.js +3 -14
  473. package/lib/yoke/adapters/claude-query-contract.js +9 -0
  474. package/lib/yoke/adapters/claude.js +54 -50
  475. package/lib/yoke/adapters/codex-query-contract.js +24 -0
  476. package/lib/yoke/adapters/codex.js +53 -111
  477. package/lib/yoke/adapters/kiro.js +3 -1
  478. package/lib/yoke/adapters/muse-query-contract.js +7 -0
  479. package/lib/yoke/adapters/muse.js +122 -0
  480. package/lib/yoke/auth-events.js +17 -0
  481. package/lib/yoke/claude-hook-installer.js +271 -0
  482. package/lib/yoke/claude-jsonl-watcher.js +204 -0
  483. package/lib/yoke/claude-maintenance.js +55 -0
  484. package/lib/yoke/claude-permission-patterns.js +53 -0
  485. package/lib/yoke/claude-response-recovery.js +155 -0
  486. package/lib/yoke/claude-transcript-hygiene.js +34 -0
  487. package/lib/yoke/claude-worker-startup.js +28 -0
  488. package/lib/yoke/clay-skill-install.js +33 -0
  489. package/lib/yoke/cli-sessions.js +300 -0
  490. package/lib/yoke/codex-app-server.js +7 -12
  491. package/lib/yoke/codex-idle-recovery.js +81 -1
  492. package/lib/yoke/codex-recovery-admission.js +164 -0
  493. package/lib/yoke/configuration.js +13 -0
  494. package/lib/yoke/discovery.js +70 -0
  495. package/lib/yoke/errors.js +8 -0
  496. package/lib/yoke/host-environment.js +7 -0
  497. package/lib/yoke/index.js +9 -51
  498. package/lib/yoke/interface.js +116 -0
  499. package/lib/yoke/kiro-acp-server.js +5 -5
  500. package/lib/yoke/legacy-sessions.js +89 -0
  501. package/lib/yoke/login-protocol.js +25 -0
  502. package/lib/yoke/maintenance.js +12 -0
  503. package/lib/yoke/mcp-proxy.js +32 -0
  504. package/lib/yoke/mcp-source-adapters.js +91 -0
  505. package/lib/yoke/mcp-source-context.js +42 -0
  506. package/lib/yoke/mcp-source-discovery.js +169 -0
  507. package/lib/yoke/mcp-source-plugins.js +68 -0
  508. package/lib/yoke/mcp-source-restrictions.js +47 -0
  509. package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
  510. package/lib/yoke/model-preferences.js +6 -0
  511. package/lib/yoke/muse-artifacts.js +36 -0
  512. package/lib/yoke/muse-controls.js +50 -0
  513. package/lib/yoke/muse-input.js +64 -0
  514. package/lib/yoke/muse-items.js +157 -0
  515. package/lib/yoke/muse-policy.js +52 -0
  516. package/lib/yoke/muse-query.js +428 -0
  517. package/lib/yoke/muse-runtime.js +211 -0
  518. package/lib/yoke/muse-services.js +79 -0
  519. package/lib/yoke/muse-skills.js +79 -0
  520. package/lib/yoke/muse-turns.js +71 -0
  521. package/lib/yoke/options/acp.js +2 -0
  522. package/lib/yoke/options/antigravity.js +2 -0
  523. package/lib/yoke/options/claude.js +21 -0
  524. package/lib/yoke/options/codex-defaults.js +29 -0
  525. package/lib/yoke/options/codex-settings.js +21 -0
  526. package/lib/yoke/options/codex.js +6 -0
  527. package/lib/yoke/options/kiro-defaults.js +22 -0
  528. package/lib/yoke/options/kiro.js +5 -0
  529. package/lib/yoke/options/muse.js +5 -0
  530. package/lib/yoke/provider-contract.js +5 -0
  531. package/lib/yoke/providers/antigravity-executable.js +8 -0
  532. package/lib/yoke/providers/claude-executable.js +40 -0
  533. package/lib/yoke/providers/claude-model-descriptions.js +14 -0
  534. package/lib/yoke/providers/claude-process.js +97 -0
  535. package/lib/yoke/providers/claude-provision.js +75 -0
  536. package/lib/yoke/providers/codex-errors.js +8 -0
  537. package/lib/yoke/providers/muse-executable.js +17 -0
  538. package/lib/yoke/provisioning.js +6 -0
  539. package/lib/yoke/query-options.js +10 -0
  540. package/lib/yoke/response-recovery.js +41 -0
  541. package/lib/yoke/sdk-mcp-descriptors.js +37 -0
  542. package/lib/yoke/sdk-server-factory.js +7 -0
  543. package/lib/yoke/session-history.js +8 -0
  544. package/lib/yoke/session-tool-transport.js +34 -13
  545. package/lib/yoke/settings.js +23 -0
  546. package/lib/yoke/source-locations.js +4 -0
  547. package/lib/yoke/title-query.js +18 -7
  548. package/lib/yoke/tui-transcript-index.js +132 -0
  549. package/lib/yoke/usage.js +48 -0
  550. package/lib/yoke/user-input.js +13 -0
  551. package/lib/yoke/vendor-registry.js +81 -1
  552. package/package.json +10 -4
@@ -18,6 +18,13 @@ function attachAdmin(ctx) {
18
18
  var onGetProjectAccess = ctx.onGetProjectAccess;
19
19
  var onProjectOwnerChanged = ctx.onProjectOwnerChanged;
20
20
 
21
+ function verifyCurrentOwner(req, route) {
22
+ if (!route || req.method === "GET" || !users.isMultiUser()) return;
23
+ var actor = getMultiUserFromReq(req);
24
+ var access = onGetProjectAccess && onGetProjectAccess(route[1]);
25
+ if (!actor || !access || access.ownerId !== actor.id || !users.findUserById(access.ownerId)) throw new Error("Project owner access required");
26
+ }
27
+
21
28
  function handleRequest(req, res, fullUrl) {
22
29
  var mateAccessRoute = /^\/api\/admin\/projects\/([^/]+)\/(visibility|owner|users|access)$/.exec(fullUrl);
23
30
  if (mateAccessRoute) {
@@ -31,6 +38,25 @@ function attachAdmin(ctx) {
31
38
  }
32
39
 
33
40
 
41
+ // Project content authority belongs to the valid owner, never the role.
42
+ if (mateAccessRoute && users.isMultiUser()) {
43
+ var actor = getMultiUserFromReq(req);
44
+ var governing = onGetProjectAccess && onGetProjectAccess(mateAccessRoute[1]);
45
+ var validOwner = governing && governing.ownerId && users.findUserById(governing.ownerId);
46
+ var owns = actor && validOwner && actor.id === validOwner.id;
47
+ if (req.method !== "GET" && !owns) {
48
+ res.writeHead(403, { "Content-Type": "application/json" });
49
+ res.end(JSON.stringify({ error: "Only the valid project owner can change access." }));
50
+ return true;
51
+ }
52
+ if (req.method === "GET" && !owns && actor && actor.role === "admin") {
53
+ var overview = require("./project-admin-overview").metadataFor(actor, target && target.getStatus(), governing, users);
54
+ res.writeHead(overview ? 200 : 404, { "Content-Type": "application/json", "Cache-Control": "no-store" });
55
+ res.end(JSON.stringify(overview || { error: "Project not found" }));
56
+ return true;
57
+ }
58
+ }
59
+
34
60
  // --- Admin API endpoints (multi-user mode only) ---
35
61
 
36
62
  // List all users (admin only)
@@ -83,6 +109,16 @@ function attachAdmin(ctx) {
83
109
  // Look up the user before deletion to get linuxUser for deactivation
84
110
  var targetUser = users.findUserById(targetUserId);
85
111
  var targetLinuxUser = targetUser ? targetUser.linuxUser : null;
112
+ var owned = false;
113
+ projects.forEach(function (project, slug) {
114
+ var access = onGetProjectAccess && onGetProjectAccess(slug);
115
+ if (access && !access.isMate && access.ownerId === targetUserId) owned = true;
116
+ });
117
+ if (owned) {
118
+ res.writeHead(409, { "Content-Type": "application/json" });
119
+ res.end(JSON.stringify({ error: "The owner must transfer ordinary projects before account deletion." }));
120
+ return true;
121
+ }
86
122
  var result = users.removeUser(targetUserId);
87
123
  if (result.error) {
88
124
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -118,6 +154,7 @@ function attachAdmin(ctx) {
118
154
  req.on("end", function () {
119
155
  try {
120
156
  var data = JSON.parse(body);
157
+ verifyCurrentOwner(req, mateAccessRoute);
121
158
  if (!data.username || typeof data.username !== "string" || data.username.trim().length < 1) {
122
159
  res.writeHead(400, { "Content-Type": "application/json" });
123
160
  res.end('{"error":"Username is required"}');
@@ -182,6 +219,11 @@ function attachAdmin(ctx) {
182
219
  res.end('{"error":"User not found"}');
183
220
  return true;
184
221
  }
222
+ if (mu.id !== targetUserId) {
223
+ res.writeHead(403, { "Content-Type": "application/json" });
224
+ res.end(JSON.stringify({ error: "Use account-owner credential recovery. Administrators cannot impersonate another account." }));
225
+ return true;
226
+ }
185
227
  var newPin = users.generatePin();
186
228
  var pinResult = users.updateUserPin(targetUserId, newPin);
187
229
  if (pinResult.error) {
@@ -222,15 +264,10 @@ function attachAdmin(ctx) {
222
264
  req.on("data", function(chunk) { body += chunk; });
223
265
  req.on("end", function() {
224
266
  try {
225
- var parsed = JSON.parse(body);
226
- var result = users.updateLinuxUser(targetUserId, parsed.linuxUser || null);
227
- if (result.error) {
228
- res.writeHead(400, { "Content-Type": "application/json" });
229
- res.end(JSON.stringify({ error: result.error }));
230
- } else {
231
- res.writeHead(200, { "Content-Type": "application/json" });
232
- res.end('{"ok":true}');
233
- }
267
+ JSON.parse(body);
268
+ res.writeHead(403, { "Content-Type": "application/json" });
269
+ res.end(JSON.stringify({ error: "OS identity mapping requires server-side verified provisioning." }));
270
+ return;
234
271
  } catch (e) {
235
272
  res.writeHead(400, { "Content-Type": "application/json" });
236
273
  res.end('{"error":"Invalid request body"}');
@@ -363,6 +400,7 @@ function attachAdmin(ctx) {
363
400
  req.on("end", function () {
364
401
  try {
365
402
  var data = JSON.parse(body);
403
+ verifyCurrentOwner(req, mateAccessRoute);
366
404
  if (!data.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
367
405
  res.writeHead(400, { "Content-Type": "application/json" });
368
406
  res.end('{"error":"Valid email is required"}');
@@ -429,6 +467,7 @@ function attachAdmin(ctx) {
429
467
  req.on("end", function () {
430
468
  try {
431
469
  var data = JSON.parse(body);
470
+ verifyCurrentOwner(req, mateAccessRoute);
432
471
  // Allow clearing SMTP config by sending empty fields
433
472
  if (!data.host && !data.user && !data.pass && !data.from) {
434
473
  smtp.saveSmtpConfig(null);
@@ -484,6 +523,7 @@ function attachAdmin(ctx) {
484
523
  req.on("end", function () {
485
524
  try {
486
525
  var data = JSON.parse(body);
526
+ verifyCurrentOwner(req, mateAccessRoute);
487
527
  // Use provided config or fall back to saved
488
528
  var existingCfg = smtp.getSmtpConfig();
489
529
  var pass = data.pass;
@@ -548,6 +588,7 @@ function attachAdmin(ctx) {
548
588
  req.on("end", function () {
549
589
  try {
550
590
  var data = JSON.parse(body);
591
+ verifyCurrentOwner(req, mateAccessRoute);
551
592
  if (data.visibility !== "public" && data.visibility !== "private") {
552
593
  res.writeHead(400, { "Content-Type": "application/json" });
553
594
  res.end('{"error":"Visibility must be public or private"}');
@@ -582,9 +623,10 @@ function attachAdmin(ctx) {
582
623
  return true;
583
624
  }
584
625
  var mu = getMultiUserFromReq(req);
585
- if (!mu || mu.role !== "admin") {
626
+ var ownerAccess = onGetProjectAccess && onGetProjectAccess(fullUrl.split("/")[4]);
627
+ if (!mu || !ownerAccess || mu.id !== ownerAccess.ownerId) {
586
628
  res.writeHead(403, { "Content-Type": "application/json" });
587
- res.end('{"error":"Admin access required"}');
629
+ res.end('{"error":"Project owner access required"}');
588
630
  return true;
589
631
  }
590
632
  var projSlug = fullUrl.split("/")[4];
@@ -598,17 +640,21 @@ function attachAdmin(ctx) {
598
640
  req.on("end", function () {
599
641
  try {
600
642
  var data = JSON.parse(body);
643
+ verifyCurrentOwner(req, mateAccessRoute);
601
644
  var targetCtx = projects.get(projSlug);
602
645
  if (!targetCtx) {
603
646
  res.writeHead(404, { "Content-Type": "application/json" });
604
647
  res.end('{"error":"Project not found"}');
605
648
  return;
606
649
  }
607
- var ownerId = data.userId || null;
650
+ var ownerId = data.userId;
651
+ if (typeof ownerId !== "string" || !users.findUserById(ownerId)) throw new Error("A valid owner is required");
652
+ var currentAccess = onGetProjectAccess && onGetProjectAccess(projSlug);
653
+ if (!currentAccess || currentAccess.ownerId !== mu.id) throw new Error("Project owner access required");
654
+ if (!onProjectOwnerChanged) throw new Error("Ownership persistence is unavailable");
655
+ var saved = onProjectOwnerChanged(projSlug, ownerId);
656
+ if (saved && saved.error) throw new Error(saved.error);
608
657
  targetCtx.setProjectOwner(ownerId);
609
- if (onProjectOwnerChanged) {
610
- onProjectOwnerChanged(projSlug, ownerId);
611
- }
612
658
  // Broadcast to project clients
613
659
  var ownerName = null;
614
660
  if (ownerId) {
@@ -653,7 +699,8 @@ function attachAdmin(ctx) {
653
699
  req.on("end", function () {
654
700
  try {
655
701
  var data = JSON.parse(body);
656
- if (!Array.isArray(data.allowedUsers)) {
702
+ verifyCurrentOwner(req, mateAccessRoute);
703
+ if (!Array.isArray(data.allowedUsers) || data.allowedUsers.some(function (id) { return typeof id !== "string" || !users.findUserById(id); })) {
657
704
  res.writeHead(400, { "Content-Type": "application/json" });
658
705
  res.end('{"error":"allowedUsers must be an array"}');
659
706
  return;
@@ -34,6 +34,18 @@ function attachAppearanceSettings(ctx) {
34
34
  fs.renameSync(defaultPath + '.tmp', defaultPath);
35
35
  }
36
36
  }
37
+ function getInitialAppearance(req) {
38
+ var user = identity(req);
39
+ if (!user) return null;
40
+ var saved = read(user);
41
+ return {
42
+ configured: saved.configured,
43
+ theme: saved.theme,
44
+ mode: saved.mode,
45
+ lightTheme: saved.lightTheme || null,
46
+ darkTheme: saved.darkTheme || null
47
+ };
48
+ }
37
49
  function handleRequest(req, res, url) {
38
50
  if (url !== '/api/user/appearance') return false;
39
51
  var user = identity(req);
@@ -66,6 +78,6 @@ function attachAppearanceSettings(ctx) {
66
78
  });
67
79
  return true;
68
80
  }
69
- return { handleRequest: handleRequest };
81
+ return { handleRequest: handleRequest, getInitialAppearance: getInitialAppearance };
70
82
  }
71
83
  module.exports = { attachAppearanceSettings: attachAppearanceSettings };
@@ -0,0 +1,40 @@
1
+ // Authenticated personal preferences, using the shared users/config persistence.
2
+ function attachContextualClaySettings(ctx) {
3
+ function reply(res, status, data) {
4
+ res.writeHead(status, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
5
+ res.end(JSON.stringify(data));
6
+ }
7
+ function identity(req) {
8
+ if (!ctx.isRequestAuthed(req)) return null;
9
+ return ctx.users.isMultiUser() ? ctx.getMultiUserFromReq(req) : { id: 'default' };
10
+ }
11
+ function handleRequest(req, res, url) {
12
+ if (url !== '/api/user/contextual-clay-geometry') return false;
13
+ var user = identity(req);
14
+ if (!user) { reply(res, 401, { error: 'Sign in to manage popover preferences.' }); return true; }
15
+ if (req.method === 'GET') {
16
+ try { reply(res, 200, { geometry: ctx.users.getContextualClayGeometry(user.id) }); }
17
+ catch (error) { reply(res, 500, { error: 'Could not read popover preference.' }); }
18
+ return true;
19
+ }
20
+ if (req.method !== 'PUT') { reply(res, 405, { error: 'Method not allowed.' }); return true; }
21
+ if (req.headers['x-clay-settings'] !== '1' || (req.headers['sec-fetch-site'] && ['same-origin', 'none'].indexOf(req.headers['sec-fetch-site']) < 0)) {
22
+ reply(res, 403, { error: 'Save preferences from Clay.' }); return true;
23
+ }
24
+ var body = ''; var tooLarge = false;
25
+ req.setEncoding('utf8');
26
+ req.on('data', function (chunk) { body += chunk; if (body.length > 1024 && !tooLarge) { tooLarge = true; reply(res, 413, { error: 'Request too large.' }); } });
27
+ req.on('end', function () {
28
+ if (tooLarge) return;
29
+ var live = identity(req);
30
+ if (!live || live.id !== user.id) { reply(res, 401, { error: 'Sign in again.' }); return; }
31
+ try {
32
+ var result = ctx.users.setContextualClayGeometry(live.id, JSON.parse(body));
33
+ reply(res, result.error ? 400 : 200, result);
34
+ } catch (error) { reply(res, 400, { error: 'Could not save popover preference.' }); }
35
+ });
36
+ return true;
37
+ }
38
+ return { handleRequest: handleRequest };
39
+ }
40
+ module.exports = { attachContextualClaySettings: attachContextualClaySettings };
@@ -0,0 +1,70 @@
1
+ // Presentation-only session operations share Home's authoritative permissions,
2
+ // model policy, saved-session projection and session manager. No transcript tap.
3
+ function attachContextualMateSessions(ctx) {
4
+ var receipts = new Map();
5
+ var lifetime = 30 * 60 * 1000;
6
+ function stamp(mate) { return JSON.stringify([mate.id, mate.createdBy || null, mate.createdAt || null, mate.builtinKey || null]); }
7
+ function live(ws, userId, msg, original) {
8
+ if (!ctx.isActorLive(ws, userId)) throw new Error('Your account is no longer available.');
9
+ var found = ctx.findMateProject(userId, msg.mateId, true);
10
+ if (!found || found.mate.archived || found.mate.lifecycleDeletion || found.mate.createdBy && found.mate.createdBy !== userId || stamp(found.mate) !== msg.mateStamp) throw new Error('This Mate is no longer available.');
11
+ var status = found.ctx.getStatus();
12
+ if (!status || !status.isMate || status.mateId !== found.mate.id || userId && status.projectOwnerId !== userId) throw new Error('This private Mate workspace is unavailable.');
13
+ found.contextualManager = found.ctx.getSessionManager();
14
+ found.contextualRevision = JSON.stringify([status.path, status.projectOwnerId, status.mateId, stamp(found.mate)]);
15
+ if (original && (found.ctx !== original.ctx || found.contextualRevision !== original.contextualRevision || found.contextualManager !== original.contextualManager)) throw new Error('This Mate conversation changed.');
16
+ return found;
17
+ }
18
+ function reply(ws, msg, data) { ctx.sendMessage(ws, Object.assign({ type: 'contextual_mate_sessions_result', requestId: msg.requestId, mateId: msg.mateId, mateStamp: msg.mateStamp }, data)); }
19
+ async function perform(ws, userId, msg) {
20
+ try {
21
+ if (typeof msg.requestId !== 'string' || !/^mate-conversations-[a-z0-9-]{36}$/.test(msg.requestId)) throw new Error('Invalid conversation request.');
22
+ var found = live(ws, userId, msg), manager = found.ctx.getSessionManager();
23
+ if (!manager) throw new Error('Conversation history is unavailable.');
24
+ if (msg.type === 'home_mate_sessions_list') {
25
+ var list = ctx.listHomeSessions(found, userId);
26
+ reply(ws, msg, { ok: true, sessions: list.slice(0, 500), truncated: list.length > 500 }); return;
27
+ }
28
+ var session;
29
+ if (msg.type === 'home_mate_session_open') {
30
+ session = ctx.resolveHomeSession(found, userId, msg.sessionId);
31
+ if (!session || typeof msg.sessionOriginId !== 'string' || msg.sessionOriginId !== session.sessionOriginId) throw new Error('This conversation is no longer available.');
32
+ } else {
33
+ var now = Date.now();
34
+ receipts.forEach(function (entry, key) { if (now - entry.at > lifetime) receipts.delete(key); });
35
+ var key = JSON.stringify([userId, msg.mateId, msg.requestId]);
36
+ var receipt = receipts.get(key);
37
+ manager.sessions.forEach(function (candidate) { if (candidate.contextualCreationRequestId === msg.requestId && ctx.ownsSession(candidate, userId)) session = candidate; });
38
+ if (session && session.contextualCreationMateStamp !== msg.mateStamp) throw new Error('This request belongs to a replaced Mate.');
39
+ if (receipt && (!session || receipt.origin !== session.sessionOriginId || receipt.stamp !== msg.mateStamp)) throw new Error('The previously created conversation is no longer available.');
40
+ if (!session && msg.lookupOnly) throw new Error('Creation was not confirmed. Start a new chat explicitly if you still want one.');
41
+ if (!session) {
42
+ if (receipts.size >= 1024) throw new Error('Please try starting a conversation later.');
43
+ var resolved = await ctx.homeModels.resolveMateModel(ws, found, userId);
44
+ found = live(ws, userId, msg, found);
45
+ // Recheck after model resolution: concurrent retries select one exact session.
46
+ manager.sessions.forEach(function (candidate) { if (candidate.contextualCreationRequestId === msg.requestId && ctx.ownsSession(candidate, userId)) session = candidate; });
47
+ receipt = receipts.get(key);
48
+ if (receipt && (!session || receipt.origin !== session.sessionOriginId || receipt.stamp !== msg.mateStamp)) throw new Error('The previously created conversation is no longer available.');
49
+ if (session && session.contextualCreationMateStamp !== msg.mateStamp) throw new Error('This request belongs to a replaced Mate.');
50
+ if (!session) {
51
+ if (receipts.size >= 1024) throw new Error('Please try starting a conversation later.');
52
+ session = manager.createSessionRaw({ ownerId: userId, vendor: resolved.vendor, model: resolved.model, effort: resolved.effort || null });
53
+ session.contextualCreationRequestId = msg.requestId;
54
+ session.contextualCreationMateStamp = msg.mateStamp;
55
+ manager.saveSessionFile(session);
56
+ }
57
+ }
58
+ if (!ctx.ownsSession(session, userId)) throw new Error('This conversation is no longer available.');
59
+ receipts.set(key, { at: now, origin: session.sessionOriginId, stamp: msg.mateStamp });
60
+ }
61
+ live(ws, userId, msg, found);
62
+ reply(ws, msg, { ok: true, sessionId: session.localId, sessionOriginId: session.sessionOriginId });
63
+ } catch (error) { reply(ws, msg, { ok: false, error: error.message || 'Conversation unavailable.' }); }
64
+ }
65
+ return { handle: function (ws, userId, msg) {
66
+ if (msg.presentation !== 'contextual' || !/^home_mate_(sessions_list|session_open|new_session)$/.test(msg.type)) return false;
67
+ perform(ws, userId, msg); return true;
68
+ } };
69
+ }
70
+ module.exports = { attachContextualMateSessions: attachContextualMateSessions };
package/lib/server-dm.js CHANGED
@@ -49,7 +49,7 @@ function attachDm(ctx) {
49
49
  var mateCtx2 = mates.buildMateCtx(userId);
50
50
  if (mates.isMate(mateCtx2, msg.targetUserId)) {
51
51
  var mate = mates.getMate(mateCtx2, msg.targetUserId);
52
- if (!mate) return true;
52
+ if (!mate || mate.lifecycleDeletion) return true;
53
53
  // Ensure mate project is registered (survives server restarts)
54
54
  var mateSlug2 = "mate-" + mate.id;
55
55
  if (!projects.has(mateSlug2)) {
@@ -69,6 +69,7 @@ function attachDm(ctx) {
69
69
  id: mate.id,
70
70
  displayName: mp.displayName || mate.name || "New Mate",
71
71
  username: mate.id,
72
+ avatarCatalogId: mp.avatarCatalogId || "",
72
73
  avatarStyle: mp.avatarStyle || "imprint",
73
74
  avatarSeed: mp.avatarSeed || mate.id,
74
75
  avatarColor: mp.avatarColor || "#5857fc",
@@ -63,14 +63,6 @@ function attachGlobalWs(opts) {
63
63
  if (msg.type === "browse_dir") {
64
64
  var rawPath = (msg.path || "").replace(/^~/, config.REAL_HOME);
65
65
  var absTarget = path.resolve(rawPath);
66
- // Multi-user mode: non-admins can only browse their home directory.
67
- if (osUsers && ws._clayUser && ws._clayUser.role !== "admin") {
68
- var browseHome = ws._clayUser.linuxUser ? "/home/" + ws._clayUser.linuxUser : null;
69
- if (!browseHome || (absTarget !== browseHome && (absTarget + "/").indexOf(browseHome + "/") !== 0)) {
70
- sendTo(ws, { type: "browse_dir_result", path: msg.path, entries: [], error: "Access restricted to your home directory" });
71
- return;
72
- }
73
- }
74
66
  var parentDir, prefix;
75
67
  try {
76
68
  var stat = fs.statSync(absTarget);
@@ -87,12 +79,17 @@ function attachGlobalWs(opts) {
87
79
  parentDir = path.dirname(absTarget);
88
80
  prefix = path.basename(absTarget).toLowerCase();
89
81
  }
82
+ if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, parentDir)) {
83
+ sendTo(ws, { type: "browse_dir_result", entries: [], error: "Directory access is not permitted" });
84
+ return;
85
+ }
90
86
  try {
91
87
  var dirItems = fs.readdirSync(parentDir, { withFileTypes: true });
92
88
  var dirEntries = [];
93
89
  for (var di = 0; di < dirItems.length; di++) {
94
90
  var d = dirItems[di];
95
91
  if (!d.isDirectory()) continue;
92
+ if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, path.join(parentDir, d.name))) continue;
96
93
  if (d.name.charAt(0) === ".") continue;
97
94
  if (IGNORED_DIRS.has(d.name)) continue;
98
95
  if (prefix && !d.name.toLowerCase().startsWith(prefix)) continue;
@@ -110,16 +107,9 @@ function attachGlobalWs(opts) {
110
107
  if (msg.type === "add_project") {
111
108
  var addPath = (msg.path || "").replace(/^~/, config.REAL_HOME);
112
109
  var addAbs = path.resolve(addPath);
113
- if (osUsers && ws._clayUser && ws._clayUser.role !== "admin") {
114
- if (!ws._clayUser.linuxUser) {
115
- sendTo(ws, { type: "add_project_result", ok: false, error: "No Linux user assigned" });
116
- return;
117
- }
118
- var userHome = "/home/" + ws._clayUser.linuxUser;
119
- if (addAbs !== userHome && (addAbs + "/").indexOf(userHome + "/") !== 0) {
120
- sendTo(ws, { type: "add_project_result", ok: false, error: "Path not allowed. You can only add directories under " + userHome });
121
- return;
122
- }
110
+ if (opts.canUsePath && !opts.canUsePath(ws._clayUser && ws._clayUser.id, addAbs)) {
111
+ sendTo(ws, { type: "add_project_result", ok: false, error: "Directory access is not permitted" });
112
+ return;
123
113
  }
124
114
  try {
125
115
  var addStat = fs.statSync(addAbs);
@@ -133,7 +123,7 @@ function attachGlobalWs(opts) {
133
123
  }
134
124
  if (typeof onAddProject === "function") {
135
125
  var result = onAddProject(addAbs, ws._clayUser);
136
- sendTo(ws, { type: "add_project_result", ok: result.ok, slug: result.slug, error: result.error, existing: result.existing });
126
+ sendTo(ws, Object.assign({}, result, { type: "add_project_result" }));
137
127
  } else {
138
128
  sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
139
129
  }
@@ -159,7 +149,7 @@ function attachGlobalWs(opts) {
159
149
  }
160
150
  if (typeof onCreateProject === "function") {
161
151
  var createResult = onCreateProject(createName, ws._clayUser);
162
- sendTo(ws, { type: "add_project_result", ok: createResult.ok, slug: createResult.slug, error: createResult.error });
152
+ sendTo(ws, Object.assign({}, createResult, { type: "add_project_result" }));
163
153
  } else {
164
154
  sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
165
155
  }
@@ -3,7 +3,7 @@
3
3
  function homeDebateQuestions(input) {
4
4
  var source = input && Array.isArray(input.questions) && input.questions[0] ? input.questions[0] : null;
5
5
  if (!source) return [];
6
- var question = { header: source.header || "", question: source.question || "", multiSelect: false, options: [] };
6
+ var question = { header: source.header || "", question: source.question || "", multiSelect: false, allowOther: source.allowOther !== false, options: [] };
7
7
  var options = Array.isArray(source.options) ? source.options.slice(0, 6) : [];
8
8
  for (var i = 0; i < options.length; i++) question.options.push({ label: options[i].label || "Option", description: options[i].description || "" });
9
9
  return [question];
@@ -36,6 +36,7 @@ function findDebateTurn(messages, event) {
36
36
  function debateIdentity(source, fallback) {
37
37
  var prior = fallback || {};
38
38
  return {
39
+ avatarCatalogId: source.avatarCatalogId || prior.avatarCatalogId || "",
39
40
  avatarStyle: source.avatarStyle || prior.avatarStyle || "imprint",
40
41
  avatarSeed: source.avatarSeed || prior.avatarSeed || source.mateId || "mate",
41
42
  avatarColor: source.avatarColor || prior.avatarColor || "",
@@ -112,7 +113,7 @@ function applyAssignmentHistoryEvent(messages, event) {
112
113
  messages.push({ role: "assignment", assignment: assignment });
113
114
  }
114
115
 
115
- function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
116
+ function historyToHomeChat(history, debateSetupMode, mateCreationMode, pendingAskUser) {
116
117
  var messages = [];
117
118
  var pending = "";
118
119
  var interviewMode = debateSetupMode === true || mateCreationMode === true;
@@ -124,6 +125,12 @@ function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
124
125
  for (var i = 0; i < history.length; i++) {
125
126
  var event = history[i];
126
127
  if (!event) continue;
128
+ if (event.type === 'tool_executing' && event.name === 'AskUserQuestion' && ['mcp-import', 'mate-schedule', 'mcp_fallback', 'product-control'].indexOf(event.source) >= 0) {
129
+ flushAssistant();
130
+ var activeConsent = pendingAskUser === undefined || !!(pendingAskUser && pendingAskUser[event.id]);
131
+ messages.push({ role: 'question', flow: event.source === 'mcp-import' ? 'mcp_import' : 'mate_question', toolId: event.id, questions: homeDebateQuestions(event.input), status: activeConsent ? 'pending' : 'expired', error: activeConsent ? '' : 'This question is no longer active. Ask for a new review.' });
132
+ continue;
133
+ }
127
134
  if (event.type === "project_assignment_proposal" || event.type === "project_assignment_status") {
128
135
  flushAssistant();
129
136
  applyAssignmentHistoryEvent(messages, event);
@@ -185,7 +192,7 @@ function historyToHomeChat(history, debateSetupMode, mateCreationMode) {
185
192
  } else if (interviewMode && event.type === "tool_executing" && event.name === "AskUserQuestion" && event.id && event.input) {
186
193
  flushAssistant();
187
194
  messages.push({ role: "question", flow: mateCreationMode === true ? "mate_creation" : "debate", toolId: event.id, questions: homeDebateQuestions(event.input), status: "pending", error: "" });
188
- } else if ((event.type === "ask_user_answered" || event.type === "home_debate_question_expired" || event.type === "home_mate_creation_question_expired") && event.toolId) {
195
+ } else if ((event.type === "ask_user_answered" || event.type === "home_debate_question_expired" || event.type === "home_mate_creation_question_expired" || event.type === "mcp_import_consent_expired" || event.type === "mate_schedule_question_expired") && event.toolId) {
189
196
  for (var k = messages.length - 1; k >= 0; k--) {
190
197
  if (messages[k].role === "question" && messages[k].toolId === event.toolId) {
191
198
  messages[k].status = event.type === "ask_user_answered" ? "answered" : "expired";
@@ -273,7 +280,7 @@ function transformEvent(event, mateId, session, requestId, stableSessionId) {
273
280
  }
274
281
  if (session && session.homeDebatePlanning === true && HOME_DEBATE_EVENT_TYPES[event.type]) {
275
282
  var live = { type: "home_debate_event", eventType: event.type };
276
- var fields = ["turnId", "decisionId", "decision", "toolName", "command", "commandTruncated", "topic", "format", "moderatorId", "moderatorName", "panelists", "mateName", "role", "round", "activity", "delta", "text", "reason", "action", "avatarStyle", "avatarSeed", "avatarColor", "avatarCustom"];
283
+ var fields = ["turnId", "decisionId", "decision", "toolName", "command", "commandTruncated", "topic", "format", "moderatorId", "moderatorName", "panelists", "mateName", "role", "round", "activity", "delta", "text", "reason", "action", "avatarCatalogId", "avatarStyle", "avatarSeed", "avatarColor", "avatarCustom"];
277
284
  for (var fi = 0; fi < fields.length; fi++) if (Object.prototype.hasOwnProperty.call(event, fields[fi])) live[fields[fi]] = event[fields[fi]];
278
285
  if (event.mateId) live.speakerMateId = event.mateId;
279
286
  return Object.assign(live, metadata);
@@ -298,6 +305,13 @@ function transformEvent(event, mateId, session, requestId, stableSessionId) {
298
305
  if (event.type === "debate_proposal_resolved" && event.proposalId) return Object.assign({ type: "home_debate_proposal_resolved", proposalId: event.proposalId, action: event.action || "cancel", error: event.error || "" }, metadata);
299
306
  if (session && session.mateCreationMode === true && event.type === "mate_creation_proposal" && event.proposal) return Object.assign({ type: "home_mate_creation_proposal", proposal: event.proposal }, metadata);
300
307
  if (session && session.mateCreationMode === true && event.type === "mate_creation_proposal_resolved" && event.proposalId) return Object.assign({ type: "home_mate_creation_proposal_resolved", proposalId: event.proposalId, action: event.action || "cancel", createdMateId: event.mateId || null, mateName: event.mateName || null, error: event.error || "" }, metadata);
308
+ if (!(session && (session.debateSetupMode === true || session.mateCreationMode === true)) && event.type === 'tool_executing' && event.name === 'AskUserQuestion' && ['mate-schedule', 'mcp_fallback', 'product-control'].indexOf(event.source) >= 0) return Object.assign({ type: 'home_mate_question', toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
309
+ if (session && session.debateSetupMode !== true && session.mateCreationMode !== true && event.type === 'ask_user_answered' && event.toolId && (session.history || []).some(function (item) { return item.id === event.toolId && ['mate-schedule', 'mcp_fallback', 'product-control'].indexOf(item.source) >= 0; })) return Object.assign({ type: 'home_mate_question_resolved', toolId: event.toolId, status: 'answered', answers: event.answers }, metadata);
310
+ if (event.type === 'tool_executing' && event.name === 'AskUserQuestion' && event.source === 'mcp-import') return Object.assign({ type: 'home_mcp_import_question', toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
311
+ if (event.type === 'product_control_question_expired') return Object.assign({ type: 'home_mate_question_resolved', toolId: event.toolId, status: 'expired', error: event.error }, metadata);
312
+ if (event.type === 'mate_schedule_question_expired') return Object.assign({ type: 'home_mate_question_resolved', toolId: event.toolId, status: 'expired', error: event.error }, metadata);
313
+ if (event.type === 'mcp_import_consent_expired') return Object.assign({ type: 'home_mcp_import_question_resolved', toolId: event.toolId, status: 'expired', error: event.error }, metadata);
314
+ if (session && event.type === 'ask_user_answered' && event.toolId && (session.history || []).some(function (item) { return item.id === event.toolId && item.source === 'mcp-import'; })) return Object.assign({ type: 'home_mcp_import_question_resolved', toolId: event.toolId, status: 'answered', answers: event.answers }, metadata);
301
315
  if (session && session.debateSetupMode === true && event.type === "tool_executing" && event.name === "AskUserQuestion" && event.id && event.input) {
302
316
  return Object.assign({ type: "home_debate_question", toolId: event.id, questions: homeDebateQuestions(event.input) }, metadata);
303
317
  }
@@ -31,7 +31,7 @@ function attachHomeChat(deps) {
31
31
  }
32
32
  if (!mateId && allMates[i].builtinKey === "clay") mate = allMates[i];
33
33
  }
34
- if (!mate) return null;
34
+ if (!mate || mate.lifecycleDeletion) return null;
35
35
  var slug = "mate-" + mate.id;
36
36
  if (!projects.has(slug)) {
37
37
  if (!ensureRegistered) return null;
@@ -123,6 +123,7 @@ function attachHomeChat(deps) {
123
123
  model: sessionString(session.model, 240),
124
124
  createdAt: createdAt,
125
125
  lastActivity: lastActivity,
126
+ sessionOriginId: session.sessionOriginId || null,
126
127
  isProcessing: !!session.isProcessing,
127
128
  sessionRole: hierarchy[session.localId].role,
128
129
  parentSessionId: hierarchy[session.localId].parentSessionId == null ? null : sessionReference(sessionManager.sessions.get(hierarchy[session.localId].parentSessionId)),
@@ -184,6 +185,12 @@ function attachHomeChat(deps) {
184
185
  }
185
186
  });
186
187
  if (!unsubscribe) return;
188
+ var unregisterConsent = null;
189
+ if (openedSession && typeof found.ctx.registerMcpConsentViewer === 'function') {
190
+ try { unregisterConsent = found.ctx.registerMcpConsentViewer(ws, openedSession); } catch (error) {}
191
+ }
192
+ var unsubscribeEvents = unsubscribe;
193
+ unsubscribe = function () { if (unregisterConsent) unregisterConsent(); unsubscribeEvents(); };
187
194
  ws[tapKey] = {
188
195
  unsubscribe: unsubscribe,
189
196
  sessionId: sessionId,
@@ -222,6 +229,7 @@ function attachHomeChat(deps) {
222
229
  var homeDebates = attachHomeDebates({ mates: mates, findMateProject: findMateProject, ownsSession: ownsSession, sessionReference: sessionReference, sendMessage: sendMessage });
223
230
  var homeClaySessionLinks = attachHomeClaySessionLinks({
224
231
  projects: projects,
232
+ findMateProject: findMateProject, ownsSession: ownsSession, isActorLive: isActorLive,
225
233
  workspaceQueryService: deps.workspaceQueryService,
226
234
  projectLogsService: deps.projectLogsService,
227
235
  sendMessage: sendMessage,
@@ -238,7 +246,7 @@ function attachHomeChat(deps) {
238
246
  requestId: requestId || null,
239
247
  model: session.model || null,
240
248
  vendor: session.vendor || null,
241
- messages: historyToHomeChat(session.history || [], session.debateSetupMode === true, session.mateCreationMode === true),
249
+ messages: historyToHomeChat(session.history || [], session.debateSetupMode === true, session.mateCreationMode === true, session.pendingAskUser),
242
250
  isProcessing: session.isProcessing === true,
243
251
  };
244
252
  if (session.homeClayEntryMode === "search") {
@@ -293,7 +301,10 @@ function attachHomeChat(deps) {
293
301
  homeModels: homeModels, isActorLive: isActorLive, persistActiveSession: persistActiveSession,
294
302
  });
295
303
  var homeMateCreation = attachHomeMateCreation({ findMateProject: findMateProject, resolveHomeSession: resolveHomeSession, sessionReference: sessionReference, setupTap: setupTap, sendHistory: sendHistory, sendSessionList: sendSessionList, sendError: sendError, sendModelError: sendModelError, homeModels: homeModels, isActorLive: isActorLive, persistActiveSession: persistActiveSession });
296
- var homeClayEntry = attachHomeClayEntry({ findMateProject: findMateProject, ownsSession: ownsSession, sessionReference: sessionReference, setupSearchTap: setupSearchTap, sendHistory: sendHistory, sendSessionList: sendSessionList, sendError: sendError, sendModelError: sendModelError, homeModels: homeModels, isActorLive: isActorLive });
304
+ var homeMcpConsent = require('./server-home-mcp-consent').attachHomeMcpConsent({ findMateProject: findMateProject, resolveHomeSession: resolveHomeSession, messageTap: messageTap, isActorLive: isActorLive, sendError: sendError });
305
+ var homeClayEntry = attachHomeClayEntry({ findMateProject: findMateProject, ownsSession: ownsSession, sessionReference: sessionReference, setupSearchTap: setupSearchTap, sendHistory: sendHistory, sendSessionList: sendSessionList, sendError: sendError, sendModelError: sendModelError, sendMessage: sendMessage, homeModels: homeModels, isActorLive: isActorLive });
306
+
307
+ var contextualSessions = require('./server-contextual-mate-sessions').attachContextualMateSessions({ findMateProject: findMateProject, ownsSession: ownsSession, resolveHomeSession: resolveHomeSession, listHomeSessions: listHomeSessions, isActorLive: isActorLive, homeModels: homeModels, sendMessage: sendMessage });
297
308
 
298
309
  async function openExactSession(ws, found, userId, selected, msg) {
299
310
  await ensureSessionModel(ws, found, userId, selected, null);
@@ -397,20 +408,8 @@ function attachHomeChat(deps) {
397
408
  historyError.sessionId = sessionReference(activeSession);
398
409
  throw historyError;
399
410
  }
400
- sessionManager.sendAndRecord(activeSession, { type: "user_message", text: text });
401
411
  try {
402
- if (!activeSession.isProcessing) {
403
- activeSession.isProcessing = true;
404
- activeSession.sentToolResults = {};
405
- if (typeof options.onRecorded === "function") options.onRecorded(activeSession);
406
- if (!activeSession.queryInstance && (!activeSession.worker || activeSession.messageQueue !== "worker")) {
407
- sdk.startQuery(activeSession, options.queryText || text, null, null);
408
- } else {
409
- sdk.pushMessage(activeSession, options.queryText || text, null);
410
- }
411
- } else {
412
- sdk.pushMessage(activeSession, options.queryText || text, null);
413
- }
412
+ await require('./mate-message-delivery').deliver({ sm: sessionManager, sdk: sdk }, activeSession, text, options);
414
413
  } catch (error) {
415
414
  error.sessionId = sessionReference(activeSession);
416
415
  throw error;
@@ -418,7 +417,7 @@ function attachHomeChat(deps) {
418
417
  return sessionReferenceValue;
419
418
  }
420
419
 
421
- function handleMessage(ws, msg) {
420
+ function handleMessage(ws, msg, routedProjectSlug) {
422
421
  if (!msg || typeof msg.type !== "string") return false;
423
422
  if (msg.type === "home_mate_stop" || msg.type === "home_mate_permission_response") {
424
423
  var controlUserId = ws._clayUser ? ws._clayUser.id : null;
@@ -449,10 +448,12 @@ function attachHomeChat(deps) {
449
448
  }
450
449
  return true;
451
450
  }
452
- if (msg.type !== "issue_reference_resolve" && msg.type !== "home_debates_list" && msg.type !== "home_clay_ask" && msg.type !== "home_clay_session_resolve" && msg.type !== "home_clay_log_resolve" && 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_debate_question_response" && msg.type !== "home_debate_control" && msg.type !== "home_mate_creation_plan" && msg.type !== "home_mate_creation_question_response" && 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") {
451
+ if (msg.type !== "issue_reference_resolve" && msg.type !== "home_debates_list" && msg.type !== "home_clay_ask" && msg.type !== "home_clay_session_resolve" && msg.type !== "home_clay_log_resolve" && 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_mcp_import_response" && msg.type !== "home_mate_question_response" && msg.type !== "home_debate_question_response" && msg.type !== "home_debate_control" && msg.type !== "home_mate_creation_plan" && msg.type !== "home_mate_creation_question_response" && 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") {
453
452
  return false;
454
453
  }
455
454
 
455
+ if (contextualSessions.handle(ws, ws._clayUser ? ws._clayUser.id : null, msg)) return true;
456
+
456
457
  if (msg.type === "home_mate_present") {
457
458
  ws._homeChatPresented = msg.visible === true;
458
459
  return true;
@@ -474,11 +475,12 @@ function attachHomeChat(deps) {
474
475
  return true;
475
476
  }
476
477
 
478
+ if (msg.type === "home_mcp_import_response" || msg.type === "home_mate_question_response") { homeMcpConsent.respond(ws, userId, msg); return true; }
477
479
  if (msg.type === "issue_reference_resolve") { resolveIssueLink(ws, msg); return true; }
478
480
  if (homeDebates.handle(ws, userId, msg)) return true;
479
481
  if (msg.type === "home_clay_ask") { homeClayEntry.start(ws, userId, msg); return true; }
480
- if (msg.type === "home_clay_session_resolve") { homeClaySessionLinks.resolve(ws, msg); return true; }
481
- if (msg.type === "home_clay_log_resolve") { homeClaySessionLinks.resolveLog(ws, msg); return true; }
482
+ if (msg.type === "home_clay_session_resolve") { homeClaySessionLinks.resolve(ws, msg, routedProjectSlug); return true; }
483
+ if (msg.type === "home_clay_log_resolve") { homeClaySessionLinks.resolveLog(ws, msg, routedProjectSlug); return true; }
482
484
 
483
485
  if (msg.type === "home_mate_debate_plan") {
484
486
  homeDebate.start(ws, userId, msg);