clay-server 5.1.1-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 (588) hide show
  1. package/lib/account-auth-policy.js +21 -0
  2. package/lib/account-auth-socket.js +30 -0
  3. package/lib/account-auth-throttle.js +44 -0
  4. package/lib/account-auth-transport.js +48 -0
  5. package/lib/account-login-page.js +28 -0
  6. package/lib/account-passkey-challenges.js +31 -0
  7. package/lib/account-passkey-page.js +89 -0
  8. package/lib/account-passkey-policy.js +39 -0
  9. package/lib/account-password-page.js +69 -0
  10. package/lib/account-passwords.js +36 -0
  11. package/lib/account-remembered.js +77 -0
  12. package/lib/account-session-page.js +51 -0
  13. package/lib/account-session-store.js +82 -0
  14. package/lib/builtin-mates.js +19 -16
  15. package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
  16. package/lib/canonical-clay-record-authority.js +15 -0
  17. package/lib/canonical-clay-scheduling-authority.js +19 -0
  18. package/lib/claude-hook-installer.js +1 -239
  19. package/lib/claude-jsonl-watcher.js +1 -204
  20. package/lib/clay-control-presentation-binding.js +96 -0
  21. package/lib/clay-control-presentation.js +128 -0
  22. package/lib/clay-control-target-projection.js +26 -0
  23. package/lib/clay-mate-chat-receipts.js +26 -0
  24. package/lib/clay-mate-chat.js +88 -0
  25. package/lib/clay-mate-knowledge-input.js +26 -0
  26. package/lib/clay-mate-knowledge.js +95 -0
  27. package/lib/clay-mate-lifecycle.js +95 -0
  28. package/lib/clay-product-control-input.js +33 -0
  29. package/lib/clay-product-control-tools.js +51 -0
  30. package/lib/clay-product-control.js +247 -0
  31. package/lib/clay-project-lifecycle.js +154 -0
  32. package/lib/clay-project-record-input.js +44 -0
  33. package/lib/clay-project-records.js +84 -0
  34. package/lib/clay-scheduling-input.js +21 -0
  35. package/lib/clay-scheduling-receipts.js +26 -0
  36. package/lib/clay-scheduling.js +119 -0
  37. package/lib/clay-screen-controls.js +104 -0
  38. package/lib/clay-skill-install.js +1 -33
  39. package/lib/clay-workspace-controls.js +84 -0
  40. package/lib/clay-workspace-input.js +17 -0
  41. package/lib/clay-workspace-receipts.js +26 -0
  42. package/lib/cli-sessions.js +1 -300
  43. package/lib/codex-defaults.js +1 -28
  44. package/lib/context-usage.js +3 -2
  45. package/lib/contextual-screen-snapshot.js +38 -0
  46. package/lib/daemon-project-access.js +11 -0
  47. package/lib/daemon-project-lifecycle-callbacks.js +15 -0
  48. package/lib/daemon-project-lifecycle.js +262 -0
  49. package/lib/daemon-projects.js +1 -1
  50. package/lib/daemon.js +80 -276
  51. package/lib/default-ai-runtime.js +4 -8
  52. package/lib/dm-digest-cursor.js +120 -0
  53. package/lib/email-mcp-server.js +1 -1
  54. package/lib/issues-service.js +29 -15
  55. package/lib/kiro-defaults.js +1 -22
  56. package/lib/knowledge-db-import-validation.js +46 -0
  57. package/lib/knowledge-db-import.js +99 -0
  58. package/lib/knowledge-db-service.js +24 -33
  59. package/lib/knowledge-db-storage-nedb-maintenance.js +99 -0
  60. package/lib/knowledge-db-storage-nedb.js +66 -0
  61. package/lib/knowledge-db-storage.js +72 -0
  62. package/lib/knowledge-db-validation.js +0 -0
  63. package/lib/knowledge-document-index.js +2 -1
  64. package/lib/knowledge-file-store.js +7 -1
  65. package/lib/knowledge-product-operations.js +46 -0
  66. package/lib/mate-avatar-catalog.js +12 -0
  67. package/lib/mate-avatar-migration.js +41 -0
  68. package/lib/mate-context-service.js +138 -0
  69. package/lib/mate-context-tools.js +21 -0
  70. package/lib/mate-creation-mcp-server.js +2 -0
  71. package/lib/mate-knowledge-canonical-access.js +10 -0
  72. package/lib/mate-knowledge-mate-bound.js +53 -0
  73. package/lib/mate-knowledge-mcp-server.js +55 -8
  74. package/lib/mate-knowledge-service.js +16 -34
  75. package/lib/mate-knowledge-text-tools.js +106 -0
  76. package/lib/mate-lifecycle-service.js +94 -0
  77. package/lib/mate-message-delivery.js +43 -0
  78. package/lib/mate-ready-creation.js +9 -1
  79. package/lib/mate-schedule-input.js +29 -0
  80. package/lib/mate-schedule-lifecycle.js +151 -0
  81. package/lib/mate-scheduling.js +103 -0
  82. package/lib/mates.js +18 -6
  83. package/lib/mcp-agent-tools.js +117 -0
  84. package/lib/mcp-connection-store.js +119 -15
  85. package/lib/mcp-import-credentials.js +31 -0
  86. package/lib/mcp-local-transport.js +13 -0
  87. package/lib/mcp-oauth.js +8 -6
  88. package/lib/mcp-proxy.js +2 -32
  89. package/lib/mcp-query-bridge.js +30 -0
  90. package/lib/mcp-remote-connections.js +74 -20
  91. package/lib/mcp-source-adapters.js +1 -0
  92. package/lib/mcp-source-context.js +1 -0
  93. package/lib/mcp-source-discovery.js +1 -0
  94. package/lib/mcp-source-plugins.js +1 -0
  95. package/lib/mcp-source-restrictions.js +1 -0
  96. package/lib/mcp-tool-policy.js +9 -0
  97. package/lib/migrate-single-user.js +3 -23
  98. package/lib/notes-checklist.js +50 -0
  99. package/lib/notes.js +49 -3
  100. package/lib/os-user-diagnostics.js +2 -4
  101. package/lib/os-users.js +24 -70
  102. package/lib/pane-pending-interactions.js +20 -0
  103. package/lib/pane-session-activation.js +114 -0
  104. package/lib/pane-session-transport.js +26 -0
  105. package/lib/project-admin-overview.js +51 -0
  106. package/lib/project-ask-user.js +8 -4
  107. package/lib/project-connection.js +14 -10
  108. package/lib/project-control-git-view.js +12 -0
  109. package/lib/project-debate.js +1 -0
  110. package/lib/project-delegated-follow-up.js +2 -1
  111. package/lib/project-directory-claim.js +65 -0
  112. package/lib/project-file-operations.js +61 -0
  113. package/lib/project-filesystem.js +15 -85
  114. package/lib/project-full-access.js +23 -2
  115. package/lib/project-http.js +7 -4
  116. package/lib/project-knowledge.js +32 -18
  117. package/lib/project-lifecycle-operations.js +98 -0
  118. package/lib/project-lifecycle-process-witness.js +32 -0
  119. package/lib/project-lifecycle-runtime.js +50 -0
  120. package/lib/project-linux-access.js +22 -0
  121. package/lib/project-logs-canonical-clay.js +27 -0
  122. package/lib/project-logs-clay-query.js +16 -0
  123. package/lib/project-logs-schema.js +4 -2
  124. package/lib/project-logs-service.js +8 -7
  125. package/lib/project-logs.js +1 -0
  126. package/lib/project-loop.js +1 -0
  127. package/lib/project-mate-chat-control.js +55 -0
  128. package/lib/project-mate-creation-proposal.js +18 -3
  129. package/lib/project-mate-interaction.js +40 -62
  130. package/lib/project-mcp.js +54 -16
  131. package/lib/project-models.js +14 -31
  132. package/lib/project-notifications.js +76 -17
  133. package/lib/project-ownership.js +77 -0
  134. package/lib/project-pair-result-delivery.js +14 -3
  135. package/lib/project-pair-usage.js +12 -13
  136. package/lib/project-pending-message-queue.js +4 -1
  137. package/lib/project-product-control.js +89 -0
  138. package/lib/project-product-session-queue.js +46 -0
  139. package/lib/project-push-access.js +28 -0
  140. package/lib/project-scheduled-message-queue.js +30 -0
  141. package/lib/project-scheduled-messages.js +67 -68
  142. package/lib/project-scheduled-task-control.js +83 -0
  143. package/lib/project-scheduled-tasks.js +13 -2
  144. package/lib/project-scheduling-access.js +10 -0
  145. package/lib/project-server-settings.js +1 -0
  146. package/lib/project-session-actions.js +65 -0
  147. package/lib/project-session-delete.js +8 -1
  148. package/lib/project-session-document.js +27 -7
  149. package/lib/project-session-github.js +63 -19
  150. package/lib/project-session-history-actions.js +167 -0
  151. package/lib/project-session-linear.js +14 -6
  152. package/lib/project-session-notes.js +7 -3
  153. package/lib/project-session-pair.js +1 -1
  154. package/lib/project-session-runtime-actions.js +64 -0
  155. package/lib/project-session-spawn.js +2 -3
  156. package/lib/project-session-vendor.js +55 -0
  157. package/lib/project-sessions.js +103 -272
  158. package/lib/project-shared-browser.js +78 -17
  159. package/lib/project-studio-presentation.js +58 -0
  160. package/lib/project-user-knowledge.js +2 -1
  161. package/lib/project-user-message.js +67 -1
  162. package/lib/project-vendor-login.js +6 -36
  163. package/lib/project-workspace-operations.js +126 -0
  164. package/lib/project-workspace-query.js +19 -2
  165. package/lib/project.js +178 -45
  166. package/lib/public/app.js +46 -0
  167. package/lib/public/appearance-bootstrap.js +16 -0
  168. package/lib/public/auth/account-login.css +98 -0
  169. package/lib/public/auth/account-login.js +104 -0
  170. package/lib/public/css/clay-tool-activity.css +51 -0
  171. package/lib/public/css/clay-workspace.css +29 -0
  172. package/lib/public/css/command-palette.css +12 -33
  173. package/lib/public/css/contextual-clay.css +240 -0
  174. package/lib/public/css/home-debate-planning.css +2 -0
  175. package/lib/public/css/home-mate-creation.css +5 -0
  176. package/lib/public/css/input.css +6 -0
  177. package/lib/public/css/mate-avatar-gallery.css +12 -0
  178. package/lib/public/css/mate-conversation.css +10 -5
  179. package/lib/public/css/messages.css +6 -2
  180. package/lib/public/css/overlays.css +4 -2
  181. package/lib/public/css/project-admin-overview.css +13 -0
  182. package/lib/public/css/session-folders.css +11 -0
  183. package/lib/public/css/session-github.css +46 -1
  184. package/lib/public/css/shared-browser.css +35 -1
  185. package/lib/public/css/sticky-notes.css +87 -1
  186. package/lib/public/css/user-settings-sessions.css +42 -0
  187. package/lib/public/index.html +28 -10
  188. package/lib/public/mate-avatars/B01.png +0 -0
  189. package/lib/public/mate-avatars/B02.png +0 -0
  190. package/lib/public/mate-avatars/B03.png +0 -0
  191. package/lib/public/mate-avatars/B04.png +0 -0
  192. package/lib/public/mate-avatars/B05.png +0 -0
  193. package/lib/public/mate-avatars/B06.png +0 -0
  194. package/lib/public/mate-avatars/B07.png +0 -0
  195. package/lib/public/mate-avatars/B08.png +0 -0
  196. package/lib/public/mate-avatars/B09.png +0 -0
  197. package/lib/public/mate-avatars/B10.png +0 -0
  198. package/lib/public/mate-avatars/B11.png +0 -0
  199. package/lib/public/mate-avatars/B12.png +0 -0
  200. package/lib/public/mate-avatars/B13.png +0 -0
  201. package/lib/public/mate-avatars/B14.png +0 -0
  202. package/lib/public/mate-avatars/B15.png +0 -0
  203. package/lib/public/mate-avatars/B16.png +0 -0
  204. package/lib/public/mate-avatars/B17.png +0 -0
  205. package/lib/public/mate-avatars/B18.png +0 -0
  206. package/lib/public/mate-avatars/B19.png +0 -0
  207. package/lib/public/mate-avatars/B20.png +0 -0
  208. package/lib/public/mate-avatars/B21.png +0 -0
  209. package/lib/public/mate-avatars/B22.png +0 -0
  210. package/lib/public/mate-avatars/B23.png +0 -0
  211. package/lib/public/mate-avatars/B24.png +0 -0
  212. package/lib/public/mate-avatars/B25.png +0 -0
  213. package/lib/public/mate-avatars/B26.png +0 -0
  214. package/lib/public/mate-avatars/B27.png +0 -0
  215. package/lib/public/mate-avatars/B28.png +0 -0
  216. package/lib/public/mate-avatars/B29.png +0 -0
  217. package/lib/public/mate-avatars/B30.png +0 -0
  218. package/lib/public/mate-avatars/B31.png +0 -0
  219. package/lib/public/mate-avatars/B32.png +0 -0
  220. package/lib/public/mate-avatars/B33.png +0 -0
  221. package/lib/public/mate-avatars/B34.png +0 -0
  222. package/lib/public/mate-avatars/B35.png +0 -0
  223. package/lib/public/mate-avatars/B36.png +0 -0
  224. package/lib/public/mate-avatars/B37.png +0 -0
  225. package/lib/public/mate-avatars/B38.png +0 -0
  226. package/lib/public/mate-avatars/B39.png +0 -0
  227. package/lib/public/mate-avatars/B40.png +0 -0
  228. package/lib/public/mate-avatars/B41.png +0 -0
  229. package/lib/public/mate-avatars/B42.png +0 -0
  230. package/lib/public/mate-avatars/B43.png +0 -0
  231. package/lib/public/mate-avatars/B44.png +0 -0
  232. package/lib/public/mate-avatars/B45.png +0 -0
  233. package/lib/public/mate-avatars/B46.png +0 -0
  234. package/lib/public/mate-avatars/B47.png +0 -0
  235. package/lib/public/mate-avatars/B48.png +0 -0
  236. package/lib/public/mate-avatars/C01.png +0 -0
  237. package/lib/public/mate-avatars/C02.png +0 -0
  238. package/lib/public/mate-avatars/C03.png +0 -0
  239. package/lib/public/mate-avatars/C04.png +0 -0
  240. package/lib/public/mate-avatars/C05.png +0 -0
  241. package/lib/public/mate-avatars/C06.png +0 -0
  242. package/lib/public/mate-avatars/C07.png +0 -0
  243. package/lib/public/mate-avatars/C08.png +0 -0
  244. package/lib/public/mate-avatars/C09.png +0 -0
  245. package/lib/public/mate-avatars/C10.png +0 -0
  246. package/lib/public/mate-avatars/C11.png +0 -0
  247. package/lib/public/mate-avatars/C12.png +0 -0
  248. package/lib/public/mate-avatars/C13.png +0 -0
  249. package/lib/public/mate-avatars/C14.png +0 -0
  250. package/lib/public/mate-avatars/C15.png +0 -0
  251. package/lib/public/mate-avatars/C16.png +0 -0
  252. package/lib/public/mate-avatars/C17.png +0 -0
  253. package/lib/public/mate-avatars/C18.png +0 -0
  254. package/lib/public/mate-avatars/C19.png +0 -0
  255. package/lib/public/mate-avatars/C20.png +0 -0
  256. package/lib/public/mate-avatars/C21.png +0 -0
  257. package/lib/public/mate-avatars/C22.png +0 -0
  258. package/lib/public/mate-avatars/C23.png +0 -0
  259. package/lib/public/mate-avatars/C24.png +0 -0
  260. package/lib/public/mate-avatars/C25.png +0 -0
  261. package/lib/public/mate-avatars/C26.png +0 -0
  262. package/lib/public/mate-avatars/C27.png +0 -0
  263. package/lib/public/mate-avatars/C28.png +0 -0
  264. package/lib/public/mate-avatars/C29.png +0 -0
  265. package/lib/public/mate-avatars/C30.png +0 -0
  266. package/lib/public/mate-avatars/C31.png +0 -0
  267. package/lib/public/mate-avatars/C32.png +0 -0
  268. package/lib/public/mate-avatars/C33.png +0 -0
  269. package/lib/public/mate-avatars/C34.png +0 -0
  270. package/lib/public/mate-avatars/C35.png +0 -0
  271. package/lib/public/mate-avatars/C36.png +0 -0
  272. package/lib/public/mate-avatars/C37.png +0 -0
  273. package/lib/public/mate-avatars/C38.png +0 -0
  274. package/lib/public/mate-avatars/C39.png +0 -0
  275. package/lib/public/mate-avatars/C40.png +0 -0
  276. package/lib/public/mate-avatars/C41.png +0 -0
  277. package/lib/public/mate-avatars/C42.png +0 -0
  278. package/lib/public/mate-avatars/C43.png +0 -0
  279. package/lib/public/mate-avatars/C44.png +0 -0
  280. package/lib/public/mate-avatars/C45.png +0 -0
  281. package/lib/public/mate-avatars/C46.png +0 -0
  282. package/lib/public/mate-avatars/C47.png +0 -0
  283. package/lib/public/mate-avatars/C48.png +0 -0
  284. package/lib/public/mate-avatars/catalog.json +482 -0
  285. package/lib/public/mate-avatars/lead-clay.png +0 -0
  286. package/lib/public/modules/account-auth-settings.js +71 -0
  287. package/lib/public/modules/account-transport-settings.js +51 -0
  288. package/lib/public/modules/admin-settings-projects.js +6 -2
  289. package/lib/public/modules/app-connection.js +11 -1
  290. package/lib/public/modules/app-favicon.js +18 -9
  291. package/lib/public/modules/app-header.js +7 -4
  292. package/lib/public/modules/app-loop-ui.js +2 -0
  293. package/lib/public/modules/app-message-router.js +22 -1
  294. package/lib/public/modules/app-messages.js +119 -17
  295. package/lib/public/modules/app-misc.js +3 -1
  296. package/lib/public/modules/app-notifications.js +11 -5
  297. package/lib/public/modules/app-panels.js +61 -123
  298. package/lib/public/modules/app-projects.js +13 -0
  299. package/lib/public/modules/app-rate-limit.js +7 -27
  300. package/lib/public/modules/app-rendering.js +4 -3
  301. package/lib/public/modules/avatar.js +15 -41
  302. package/lib/public/modules/chat-render-runtime.js +20 -0
  303. package/lib/public/modules/clay-browser-links.js +47 -0
  304. package/lib/public/modules/clay-control-activity.js +214 -0
  305. package/lib/public/modules/clay-control-copy.js +36 -0
  306. package/lib/public/modules/clay-control-detail-targets.js +44 -0
  307. package/lib/public/modules/clay-control-object-targets.js +52 -0
  308. package/lib/public/modules/clay-control-target-visibility.js +12 -0
  309. package/lib/public/modules/clay-control-targets.js +44 -0
  310. package/lib/public/modules/clay-log-links.js +23 -0
  311. package/lib/public/modules/clay-navigation-render.js +52 -0
  312. package/lib/public/modules/clay-owner-navigation.js +33 -0
  313. package/lib/public/modules/clay-session-links.js +31 -0
  314. package/lib/public/modules/clay-studio-bridge.js +20 -0
  315. package/lib/public/modules/clay-studio-document.js +67 -0
  316. package/lib/public/modules/clay-studio-render.js +146 -0
  317. package/lib/public/modules/clay-tool-activity.js +140 -0
  318. package/lib/public/modules/clay-tool-presentation.js +342 -0
  319. package/lib/public/modules/command-palette.js +162 -40
  320. package/lib/public/modules/contextual-ask-session.js +26 -0
  321. package/lib/public/modules/contextual-clay-geometry.js +155 -0
  322. package/lib/public/modules/contextual-clay-session.js +130 -0
  323. package/lib/public/modules/contextual-clay-workspace.js +169 -0
  324. package/lib/public/modules/contextual-clay.js +250 -0
  325. package/lib/public/modules/contextual-composer.js +91 -0
  326. package/lib/public/modules/contextual-mate-context.js +117 -0
  327. package/lib/public/modules/contextual-mate-hint.js +40 -0
  328. package/lib/public/modules/contextual-mate-identity.js +23 -0
  329. package/lib/public/modules/contextual-mate-sessions.js +134 -0
  330. package/lib/public/modules/contextual-search.js +137 -0
  331. package/lib/public/modules/contextual-session-citations.js +58 -0
  332. package/lib/public/modules/debate.js +1 -0
  333. package/lib/public/modules/default-ai.js +11 -3
  334. package/lib/public/modules/elicitation-form.js +5 -0
  335. package/lib/public/modules/filebrowser.js +20 -1
  336. package/lib/public/modules/generation-stop.js +8 -5
  337. package/lib/public/modules/git-panel.js +3 -1
  338. package/lib/public/modules/history-replay-batch.js +13 -1
  339. package/lib/public/modules/home-debate-live.js +2 -0
  340. package/lib/public/modules/home-debate-planning.js +7 -7
  341. package/lib/public/modules/home-mate-avatar-editor.js +127 -208
  342. package/lib/public/modules/home-mate-chat.js +8 -6
  343. package/lib/public/modules/home-mate-creation.js +73 -1
  344. package/lib/public/modules/home-mate-settings.js +19 -12
  345. package/lib/public/modules/icon-strip-tooltip.js +2 -1
  346. package/lib/public/modules/input.js +88 -10
  347. package/lib/public/modules/issues-render.js +3 -2
  348. package/lib/public/modules/knowledge-db-workbench.js +4 -4
  349. package/lib/public/modules/markdown.js +6 -34
  350. package/lib/public/modules/mate-avatar-catalog.js +97 -0
  351. package/lib/public/modules/mate-knowledge-workbench.js +1 -1
  352. package/lib/public/modules/mate-management.js +40 -7
  353. package/lib/public/modules/mcp-connection-view.js +31 -13
  354. package/lib/public/modules/mcp-discovery-view.js +31 -0
  355. package/lib/public/modules/mcp-ui.js +23 -4
  356. package/lib/public/modules/mention.js +3 -0
  357. package/lib/public/modules/message-delivery.js +20 -2
  358. package/lib/public/modules/model-picker.js +2 -0
  359. package/lib/public/modules/pane-activation.js +214 -0
  360. package/lib/public/modules/pane-binding.js +82 -0
  361. package/lib/public/modules/pane-bridge.js +7 -4
  362. package/lib/public/modules/pane-browser-bridge.js +22 -0
  363. package/lib/public/modules/pane-file-bridge.js +4 -0
  364. package/lib/public/modules/pane-issue-bridge.js +4 -1
  365. package/lib/public/modules/passkey-browser.js +69 -0
  366. package/lib/public/modules/passkey-server-settings.js +57 -0
  367. package/lib/public/modules/pending-message-queue.js +1 -0
  368. package/lib/public/modules/permission-control.js +5 -4
  369. package/lib/public/modules/personal-settings-dialog.js +7 -1
  370. package/lib/public/modules/product-review.js +26 -0
  371. package/lib/public/modules/profile.js +1 -238
  372. package/lib/public/modules/project-access-recovery.js +17 -0
  373. package/lib/public/modules/project-admin-overview.js +21 -0
  374. package/lib/public/modules/project-chat-identity.js +13 -4
  375. package/lib/public/modules/project-logs-render.js +6 -2
  376. package/lib/public/modules/project-mate-navigation.js +144 -22
  377. package/lib/public/modules/rewind.js +5 -0
  378. package/lib/public/modules/scheduled-tasks.js +2 -0
  379. package/lib/public/modules/scheduler.js +2 -0
  380. package/lib/public/modules/search-clay-chat.js +5 -440
  381. package/lib/public/modules/server-settings-controls.js +10 -0
  382. package/lib/public/modules/server-settings.js +7 -2
  383. package/lib/public/modules/session-actions.js +5 -2
  384. package/lib/public/modules/session-context-menu.js +5 -0
  385. package/lib/public/modules/session-create-form.js +10 -10
  386. package/lib/public/modules/session-folder-layout.js +1 -1
  387. package/lib/public/modules/session-folder-view-menu.js +9 -0
  388. package/lib/public/modules/session-github.js +85 -14
  389. package/lib/public/modules/session-rich-drafts.js +21 -0
  390. package/lib/public/modules/session-switch-defer.js +67 -0
  391. package/lib/public/modules/session-work-primary.js +51 -0
  392. package/lib/public/modules/settings-defaults.js +27 -28
  393. package/lib/public/modules/shared-browser-settings.js +112 -0
  394. package/lib/public/modules/shared-browser-tabs.js +13 -3
  395. package/lib/public/modules/shared-browser.js +29 -6
  396. package/lib/public/modules/sidebar-mobile.js +4 -3
  397. package/lib/public/modules/sidebar-projects.js +1 -0
  398. package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
  399. package/lib/public/modules/sidebar-sessions.js +1 -0
  400. package/lib/public/modules/split-group-restore.js +68 -0
  401. package/lib/public/modules/split-pair-ui.js +1 -0
  402. package/lib/public/modules/split-pane-reconciler.js +15 -0
  403. package/lib/public/modules/split-pane-renderer.js +87 -6
  404. package/lib/public/modules/split-session-boundary.js +1 -1
  405. package/lib/public/modules/split-view.js +60 -68
  406. package/lib/public/modules/sticky-note-markdown.js +72 -6
  407. package/lib/public/modules/sticky-notes-actions.js +30 -0
  408. package/lib/public/modules/sticky-notes-browser.js +9 -2
  409. package/lib/public/modules/sticky-notes-card.js +23 -7
  410. package/lib/public/modules/sticky-notes-checklist.js +116 -0
  411. package/lib/public/modules/sticky-notes-editor.js +108 -44
  412. package/lib/public/modules/sticky-notes-shared.js +50 -2
  413. package/lib/public/modules/sticky-notes-state.js +66 -0
  414. package/lib/public/modules/sticky-notes.js +34 -51
  415. package/lib/public/modules/stt-controller.js +4 -1
  416. package/lib/public/modules/stt-recording.js +1 -1
  417. package/lib/public/modules/stt.js +7 -2
  418. package/lib/public/modules/terminal.js +9 -0
  419. package/lib/public/modules/theme.js +8 -1
  420. package/lib/public/modules/thinking-lifecycle.js +33 -3
  421. package/lib/public/modules/thinking-view.js +23 -1
  422. package/lib/public/modules/tools.js +60 -11
  423. package/lib/public/modules/tui-grab.js +1 -2
  424. package/lib/public/modules/user-settings-account.js +14 -1
  425. package/lib/public/modules/user-settings-appearance.js +10 -3
  426. package/lib/public/modules/user-settings-editors.js +1 -1
  427. package/lib/public/modules/user-settings-layout.js +11 -2
  428. package/lib/public/modules/user-settings-preferences.js +6 -2
  429. package/lib/public/modules/user-settings-profile.js +12 -2
  430. package/lib/public/modules/user-settings-sessions.js +120 -0
  431. package/lib/public/modules/user-settings.js +6 -2
  432. package/lib/public/modules/vendor-login-browser.js +5 -3
  433. package/lib/public/modules/vendor-login.js +2 -2
  434. package/lib/public/modules/vendor-priority.js +15 -1
  435. package/lib/public/modules/wireframe-workbench.js +5 -2
  436. package/lib/public/modules/you-activity.js +3 -1
  437. package/lib/public/modules/you.js +91 -6
  438. package/lib/public/muse-avatar.svg +4 -0
  439. package/lib/public/style.css +6 -0
  440. package/lib/public/sw.js +3 -1
  441. package/lib/safe-bash-commands.js +3 -45
  442. package/lib/scheduled-task-records.js +3 -1
  443. package/lib/scheduler.js +2 -0
  444. package/lib/sdk-bridge.js +342 -401
  445. package/lib/sdk-foreground-admission.js +16 -0
  446. package/lib/sdk-mcp-descriptors.js +2 -37
  447. package/lib/sdk-message-processor.js +52 -17
  448. package/lib/sdk-quota-snapshot.js +1 -1
  449. package/lib/sdk-response-recovery.js +1 -0
  450. package/lib/sdk-worker.js +2 -677
  451. package/lib/server-account-passkeys.js +186 -0
  452. package/lib/server-account-passwords.js +127 -0
  453. package/lib/server-account-security.js +53 -0
  454. package/lib/server-admin.js +63 -16
  455. package/lib/server-appearance-settings.js +13 -1
  456. package/lib/server-auth.js +107 -79
  457. package/lib/server-contextual-clay-settings.js +40 -0
  458. package/lib/server-contextual-mate-sessions.js +70 -0
  459. package/lib/server-dm.js +2 -1
  460. package/lib/server-global-ws.js +10 -20
  461. package/lib/server-home-chat-events.js +18 -4
  462. package/lib/server-home-chat.js +22 -20
  463. package/lib/server-home-clay-entry.js +23 -4
  464. package/lib/server-home-clay-session-links.js +29 -9
  465. package/lib/server-home-mate-creation.js +1 -0
  466. package/lib/server-home-mcp-consent.js +14 -0
  467. package/lib/server-mates.js +25 -62
  468. package/lib/server-owner-ui.js +118 -0
  469. package/lib/server-path-access.js +38 -0
  470. package/lib/server-project-removal.js +22 -0
  471. package/lib/server-settings.js +8 -2
  472. package/lib/server.js +165 -43
  473. package/lib/session-config-transition.js +45 -0
  474. package/lib/session-folders.js +7 -2
  475. package/lib/session-fork-history.js +21 -0
  476. package/lib/session-github.js +9 -2
  477. package/lib/session-hygiene.js +3 -35
  478. package/lib/session-permission-mode.js +4 -3
  479. package/lib/session-skill-scope.js +11 -0
  480. package/lib/session-visibility.js +5 -2
  481. package/lib/session-work-primary.js +50 -0
  482. package/lib/sessions.js +64 -99
  483. package/lib/shared-browser-cookie-sync.js +32 -0
  484. package/lib/shared-browser-cookies.js +79 -0
  485. package/lib/shared-browser-runtime.js +25 -9
  486. package/lib/shared-browser-storage-sync.js +43 -0
  487. package/lib/shared-browser-storage.js +101 -0
  488. package/lib/shared-browser-tools.js +2 -1
  489. package/lib/shared-browser-worker.js +46 -10
  490. package/lib/terminal-manager.js +65 -6
  491. package/lib/tool-llm.js +1 -1
  492. package/lib/tui-transcript-index.js +1 -132
  493. package/lib/user-knowledge-service.js +23 -1
  494. package/lib/users-auth.js +38 -3
  495. package/lib/users-contextual-clay-preferences.js +31 -0
  496. package/lib/users-create.js +97 -0
  497. package/lib/users-permissions.js +2 -8
  498. package/lib/users-server-pin.js +37 -0
  499. package/lib/users.js +18 -84
  500. package/lib/vendor-login-browser.js +1 -11
  501. package/lib/workspace-assignment-service.js +25 -0
  502. package/lib/workspace-query-access.js +4 -1
  503. package/lib/workspace-query-mcp-server.js +1 -1
  504. package/lib/workspace-query-service.js +13 -2
  505. package/lib/ws-request.js +1 -0
  506. package/lib/ws-schema.js +18 -2
  507. package/lib/yoke/acp-agent-profiles.js +7 -5
  508. package/lib/yoke/adapters/antigravity.js +3 -14
  509. package/lib/yoke/adapters/claude-query-contract.js +9 -0
  510. package/lib/yoke/adapters/claude.js +54 -50
  511. package/lib/yoke/adapters/codex-query-contract.js +24 -0
  512. package/lib/yoke/adapters/codex.js +53 -111
  513. package/lib/yoke/adapters/kiro.js +3 -1
  514. package/lib/yoke/adapters/muse-query-contract.js +7 -0
  515. package/lib/yoke/adapters/muse.js +122 -0
  516. package/lib/yoke/auth-events.js +17 -0
  517. package/lib/yoke/claude-hook-installer.js +271 -0
  518. package/lib/yoke/claude-jsonl-watcher.js +204 -0
  519. package/lib/yoke/claude-maintenance.js +55 -0
  520. package/lib/yoke/claude-permission-patterns.js +53 -0
  521. package/lib/yoke/claude-response-recovery.js +155 -0
  522. package/lib/yoke/claude-transcript-hygiene.js +34 -0
  523. package/lib/yoke/claude-worker-startup.js +28 -0
  524. package/lib/yoke/clay-skill-install.js +33 -0
  525. package/lib/yoke/cli-sessions.js +300 -0
  526. package/lib/yoke/codex-app-server.js +7 -12
  527. package/lib/yoke/codex-idle-recovery.js +81 -1
  528. package/lib/yoke/codex-recovery-admission.js +164 -0
  529. package/lib/yoke/configuration.js +13 -0
  530. package/lib/yoke/discovery.js +70 -0
  531. package/lib/yoke/errors.js +8 -0
  532. package/lib/yoke/host-environment.js +7 -0
  533. package/lib/yoke/index.js +9 -51
  534. package/lib/yoke/interface.js +116 -0
  535. package/lib/yoke/kiro-acp-server.js +5 -5
  536. package/lib/yoke/legacy-sessions.js +89 -0
  537. package/lib/yoke/login-protocol.js +25 -0
  538. package/lib/yoke/maintenance.js +12 -0
  539. package/lib/yoke/mcp-proxy.js +32 -0
  540. package/lib/yoke/mcp-source-adapters.js +91 -0
  541. package/lib/yoke/mcp-source-context.js +42 -0
  542. package/lib/yoke/mcp-source-discovery.js +169 -0
  543. package/lib/yoke/mcp-source-plugins.js +68 -0
  544. package/lib/yoke/mcp-source-restrictions.js +47 -0
  545. package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
  546. package/lib/yoke/model-preferences.js +6 -0
  547. package/lib/yoke/muse-artifacts.js +36 -0
  548. package/lib/yoke/muse-controls.js +50 -0
  549. package/lib/yoke/muse-input.js +64 -0
  550. package/lib/yoke/muse-items.js +157 -0
  551. package/lib/yoke/muse-policy.js +52 -0
  552. package/lib/yoke/muse-query.js +428 -0
  553. package/lib/yoke/muse-runtime.js +211 -0
  554. package/lib/yoke/muse-services.js +79 -0
  555. package/lib/yoke/muse-skills.js +79 -0
  556. package/lib/yoke/muse-turns.js +71 -0
  557. package/lib/yoke/options/acp.js +2 -0
  558. package/lib/yoke/options/antigravity.js +2 -0
  559. package/lib/yoke/options/claude.js +21 -0
  560. package/lib/yoke/options/codex-defaults.js +29 -0
  561. package/lib/yoke/options/codex-settings.js +21 -0
  562. package/lib/yoke/options/codex.js +6 -0
  563. package/lib/yoke/options/kiro-defaults.js +22 -0
  564. package/lib/yoke/options/kiro.js +5 -0
  565. package/lib/yoke/options/muse.js +5 -0
  566. package/lib/yoke/provider-contract.js +5 -0
  567. package/lib/yoke/providers/antigravity-executable.js +8 -0
  568. package/lib/yoke/providers/claude-executable.js +40 -0
  569. package/lib/yoke/providers/claude-model-descriptions.js +14 -0
  570. package/lib/yoke/providers/claude-process.js +97 -0
  571. package/lib/yoke/providers/claude-provision.js +75 -0
  572. package/lib/yoke/providers/codex-errors.js +8 -0
  573. package/lib/yoke/providers/muse-executable.js +17 -0
  574. package/lib/yoke/provisioning.js +6 -0
  575. package/lib/yoke/query-options.js +10 -0
  576. package/lib/yoke/response-recovery.js +41 -0
  577. package/lib/yoke/sdk-mcp-descriptors.js +37 -0
  578. package/lib/yoke/sdk-server-factory.js +7 -0
  579. package/lib/yoke/session-history.js +8 -0
  580. package/lib/yoke/session-tool-transport.js +34 -13
  581. package/lib/yoke/settings.js +23 -0
  582. package/lib/yoke/source-locations.js +4 -0
  583. package/lib/yoke/title-query.js +18 -7
  584. package/lib/yoke/tui-transcript-index.js +132 -0
  585. package/lib/yoke/usage.js +48 -0
  586. package/lib/yoke/user-input.js +13 -0
  587. package/lib/yoke/vendor-registry.js +81 -1
  588. package/package.json +11 -4
package/lib/users-auth.js CHANGED
@@ -1,4 +1,5 @@
1
1
  var crypto = require("crypto");
2
+ var serverPin = require('./users-server-pin');
2
3
 
3
4
  function attachAuth(deps) {
4
5
  var loadUsers = deps.loadUsers;
@@ -80,7 +81,29 @@ function attachAuth(deps) {
80
81
  // --- Pin hashing ---
81
82
 
82
83
  function hashPin(pin) {
83
- return crypto.createHash("sha256").update("clay-user:" + pin).digest("hex");
84
+ var salt = crypto.randomBytes(16).toString("hex");
85
+ var hash = crypto.scryptSync("clay-user:" + pin, salt, 64, { N: 16384, r: 8, p: 1 }).toString("hex");
86
+ return "scrypt-v1:" + salt + ":" + hash;
87
+ }
88
+
89
+ function verifyPin(pin, storedHash, user) {
90
+ // Older JSON clients could submit a numeric PIN; preserve that spelling.
91
+ if (typeof pin === "number" && Number.isSafeInteger(pin) && pin >= 0) pin = String(pin);
92
+ if (typeof pin !== "string" || typeof storedHash !== "string") return false;
93
+ var migratedHash = serverPin.resolve(storedHash, user, deps.loadConfig);
94
+ if (migratedHash) return serverPin.verify(pin, migratedHash);
95
+ var expected;
96
+ var actual;
97
+ if (/^[a-f0-9]{64}$/.test(storedHash)) {
98
+ expected = Buffer.from(storedHash, "hex");
99
+ actual = crypto.createHash("sha256").update("clay-user:" + pin).digest();
100
+ } else {
101
+ var parts = /^scrypt-v1:([a-f0-9]{32}):([a-f0-9]{128})$/.exec(storedHash);
102
+ if (!parts) return false;
103
+ expected = Buffer.from(parts[2], "hex");
104
+ actual = crypto.scryptSync("clay-user:" + pin, parts[1], 64, { N: 16384, r: 8, p: 1 });
105
+ }
106
+ return crypto.timingSafeEqual(actual, expected);
84
107
  }
85
108
 
86
109
  // Generate a random 6-digit PIN
@@ -96,6 +119,7 @@ function attachAuth(deps) {
96
119
  // --- Authentication ---
97
120
 
98
121
  function authenticateUser(username, pin) {
122
+ if (typeof username !== "string") return null;
99
123
  var data = loadUsers();
100
124
  var user = null;
101
125
  for (var i = 0; i < data.users.length; i++) {
@@ -105,8 +129,18 @@ function attachAuth(deps) {
105
129
  }
106
130
  }
107
131
  if (!user) return null;
108
- var pinH = hashPin(pin);
109
- if (user.pinHash !== pinH) return null;
132
+ if (!verifyPin(pin, user.pinHash, user)) return null;
133
+ if (user.pinHash.indexOf('scrypt-v1:') !== 0) {
134
+ var previousHash = user.pinHash;
135
+ try {
136
+ user.pinHash = hashPin(pin);
137
+ saveUsers(data);
138
+ } catch (e) {
139
+ // A best-effort upgrade must never reject a verified existing PIN.
140
+ user.pinHash = previousHash;
141
+ console.error("[users] PIN hash upgrade could not be saved; it will be retried on login.");
142
+ }
143
+ }
110
144
  return user;
111
145
  }
112
146
 
@@ -136,6 +170,7 @@ function attachAuth(deps) {
136
170
  clearSetupCode: clearSetupCode,
137
171
  validateSetupCode: validateSetupCode,
138
172
  hashPin: hashPin,
173
+ verifyPin: verifyPin,
139
174
  generatePin: generatePin,
140
175
  authenticateUser: authenticateUser,
141
176
  generateUserAuthToken: generateUserAuthToken,
@@ -0,0 +1,31 @@
1
+ // Personal geometry is never a canonical product-control operation.
2
+ function validGeometry(value) {
3
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
4
+ var keys = Object.keys(value);
5
+ if (keys.length !== 4 || keys.some(function (key) { return ['left', 'top', 'width', 'height'].indexOf(key) < 0; })) return false;
6
+ return keys.every(function (key) { return typeof value[key] === 'number' && Number.isFinite(value[key]); }) &&
7
+ value.left >= 0 && value.left <= 16384 && value.top >= 0 && value.top <= 16384 &&
8
+ value.width >= 340 && value.width <= 2560 && value.height >= 360 && value.height <= 2160;
9
+ }
10
+ function attachContextualClayPreferences(deps) {
11
+ function get(userId) {
12
+ var user = deps.loadUsers().users.find(function (entry) { return entry.id === userId; });
13
+ var saved = user && user.contextualClayGeometry;
14
+ if (!user && userId === 'default') saved = require('./config').loadConfig().contextualClayGeometry;
15
+ return validGeometry(saved) ? Object.assign({}, saved) : null;
16
+ }
17
+ function set(userId, geometry) {
18
+ if (!validGeometry(geometry)) return { error: 'Invalid popover geometry.' };
19
+ var value = Object.assign({}, geometry);
20
+ var data = deps.loadUsers();
21
+ var user = data.users.find(function (entry) { return entry.id === userId; });
22
+ if (user) { user.contextualClayGeometry = value; deps.saveUsers(data); }
23
+ else if (userId === 'default') {
24
+ var config = require('./config');
25
+ config.saveConfig(Object.assign({}, config.loadConfig(), { contextualClayGeometry: value }));
26
+ } else return { error: 'Account no longer available.' };
27
+ return { geometry: value };
28
+ }
29
+ return { getContextualClayGeometry: get, setContextualClayGeometry: set };
30
+ }
31
+ module.exports = { attachContextualClayPreferences: attachContextualClayPreferences, validGeometry: validGeometry };
@@ -0,0 +1,97 @@
1
+ var crypto = require("crypto");
2
+ var serverPin = require("./users-server-pin");
3
+
4
+ function attachCreation(deps) {
5
+ var loadUsers = deps.loadUsers;
6
+ var saveUsers = deps.saveUsers;
7
+ var generateUserId = deps.generateUserId;
8
+ var ensureUserBuiltinMates = deps.ensureUserBuiltinMates;
9
+ var auth = deps.auth;
10
+
11
+ function createUser(opts) {
12
+ var data = loadUsers();
13
+ // Check username uniqueness
14
+ for (var i = 0; i < data.users.length; i++) {
15
+ if (data.users[i].username.toLowerCase() === opts.username.toLowerCase()) {
16
+ return { error: "This username is already taken" };
17
+ }
18
+ }
19
+ // Check email uniqueness (when provided)
20
+ if (opts.email) {
21
+ for (var i = 0; i < data.users.length; i++) {
22
+ if (data.users[i].email && data.users[i].email.toLowerCase() === opts.email.toLowerCase()) {
23
+ return { error: "This email is already registered" };
24
+ }
25
+ }
26
+ }
27
+ var user = {
28
+ id: generateUserId(),
29
+ username: opts.username,
30
+ email: opts.email || null,
31
+ displayName: opts.displayName || opts.username,
32
+ pinHash: auth.hashPin(opts.pin),
33
+ role: opts.role || "user",
34
+ mustChangePin: !!opts.mustChangePin,
35
+ createdAt: Date.now(),
36
+ linuxUser: opts.linuxUser || null,
37
+ profile: opts.profile || {
38
+ name: opts.displayName || opts.username,
39
+ lang: "en-US",
40
+ avatarColor: "#5857fc",
41
+ avatarStyle: "imprint",
42
+ avatarSeed: crypto.randomBytes(4).toString("hex"),
43
+ },
44
+ };
45
+ data.users.push(user);
46
+ saveUsers(data);
47
+
48
+ // Seed immediately for ordinary multi-user storage. OS-user provisioning
49
+ // calls this again after the Linux mapping exists, targeting its final home.
50
+ ensureUserBuiltinMates(user.id);
51
+
52
+ return { ok: true, user: user };
53
+ }
54
+
55
+ function createUserWithoutPin(opts, migration) {
56
+ var data = loadUsers();
57
+ for (var i = 0; i < data.users.length; i++) {
58
+ if (data.users[i].username.toLowerCase() === opts.username.toLowerCase()) {
59
+ return { error: "This username is already taken" };
60
+ }
61
+ }
62
+ if (opts.email) {
63
+ for (var i = 0; i < data.users.length; i++) {
64
+ if (data.users[i].email && data.users[i].email.toLowerCase() === opts.email.toLowerCase()) {
65
+ return { error: "This email is already registered" };
66
+ }
67
+ }
68
+ }
69
+ var user = {
70
+ id: generateUserId(),
71
+ username: opts.username,
72
+ email: opts.email || null,
73
+ displayName: opts.displayName || opts.username,
74
+ pinHash: migration && migration.pinHash ? serverPin.tag(migration.pinHash) : null,
75
+ role: opts.role || "user",
76
+ createdAt: Date.now(),
77
+ profile: opts.profile || {
78
+ name: opts.displayName || opts.username,
79
+ lang: "en-US",
80
+ avatarColor: "#5857fc",
81
+ avatarStyle: "imprint",
82
+ avatarSeed: crypto.randomBytes(4).toString("hex"),
83
+ },
84
+ };
85
+ data.users.push(user);
86
+ if (migration) { data.multiUser = true; data.setupCode = null; }
87
+ saveUsers(data);
88
+
89
+ ensureUserBuiltinMates(user.id);
90
+
91
+ return { ok: true, user: user };
92
+ }
93
+
94
+ return { createUser: createUser, createUserWithoutPin: createUserWithoutPin };
95
+ }
96
+
97
+ module.exports = { attachCreation: attachCreation };
@@ -64,15 +64,12 @@ function attachPermissions(deps) {
64
64
  // --- Project access helpers ---
65
65
 
66
66
  function canAccessProject(userId, project) {
67
- if (!project) return false;
67
+ if (!project || !userId || !findUserById(userId) || project.ownershipRecovery === "required") return false;
68
68
  if (project.isMate === true || (typeof project.slug === "string" && project.slug.indexOf("mate-") === 0)) {
69
69
  return !!userId && !!project.ownerId && project.ownerId === userId;
70
70
  }
71
71
  // Public projects are accessible to all authenticated users
72
72
  if (!project.visibility || project.visibility === "public") return true;
73
- // Admin always has access
74
- var user = findUserById(userId);
75
- if (user && user.role === "admin") return true;
76
73
  // Owner always has access to their own project
77
74
  if (project.ownerId && project.ownerId === userId) return true;
78
75
  // Private project -- check allowedUsers
@@ -96,10 +93,7 @@ function attachPermissions(deps) {
96
93
  return !!userId && !!session.ownerId && session.ownerId === userId;
97
94
  }
98
95
  if (session.userKnowledgeOwnerId) return !!userId && session.userKnowledgeOwnerId === userId && session.ownerId === userId;
99
- // Resolve the stored user record so client-supplied roles cannot elevate access.
100
- var user = findUserById(userId);
101
- if (user && user.role === "admin") return true;
102
- // Sessions without ownerId are legacy -- only admin can see them
96
+ // Unowned historical sessions require explicit recovery; role is not ownership.
103
97
  if (!session.ownerId) return false;
104
98
  // Owner can always see their own sessions
105
99
  if (session.ownerId === userId) return true;
@@ -0,0 +1,37 @@
1
+ var crypto = require('crypto');
2
+ var PREFIX = 'server-pin-v1:';
3
+
4
+ function isServerHash(hash) {
5
+ return typeof hash === 'string' && (/^[a-f0-9]{64}$/.test(hash) || /^[a-f0-9]{32}:[a-f0-9]{128}$/.test(hash));
6
+ }
7
+
8
+ function tag(hash) {
9
+ if (!isServerHash(hash)) throw new Error('Invalid legacy server PIN hash');
10
+ return PREFIX + hash;
11
+ }
12
+
13
+ function resolve(hash, user, loadConfig) {
14
+ if (typeof hash !== 'string') return null;
15
+ if (hash.indexOf(PREFIX) === 0) {
16
+ var original = hash.slice(PREFIX.length);
17
+ return isServerHash(original) ? original : null;
18
+ }
19
+ if (!user || !isServerHash(hash) || typeof loadConfig !== 'function') return null;
20
+ // Only the recorded migrated owner may use an untagged server credential.
21
+ var config;
22
+ try { config = loadConfig(); } catch (e) { return null; }
23
+ if (config && config.singleUserMigratedAt && config.singleUserMigratedUserId === user.id && config.pinHash === hash) return hash;
24
+ return null;
25
+ }
26
+
27
+ function verify(pin, hash) {
28
+ if (!isServerHash(hash)) return false;
29
+ var parts = hash.split(':');
30
+ var expected = Buffer.from(parts.length === 2 ? parts[1] : hash, 'hex');
31
+ var actual = parts.length === 2
32
+ ? crypto.scryptSync('clay:' + pin, parts[0], 64)
33
+ : crypto.createHash('sha256').update('clay:' + pin).digest();
34
+ return crypto.timingSafeEqual(actual, expected);
35
+ }
36
+
37
+ module.exports = { tag: tag, resolve: resolve, verify: verify };
package/lib/users.js CHANGED
@@ -71,50 +71,6 @@ function ensureUserBuiltinMates(userId) {
71
71
  }
72
72
  }
73
73
 
74
- function createUser(opts) {
75
- var data = loadUsers();
76
- // Check username uniqueness
77
- for (var i = 0; i < data.users.length; i++) {
78
- if (data.users[i].username.toLowerCase() === opts.username.toLowerCase()) {
79
- return { error: "This username is already taken" };
80
- }
81
- }
82
- // Check email uniqueness (when provided)
83
- if (opts.email) {
84
- for (var i = 0; i < data.users.length; i++) {
85
- if (data.users[i].email && data.users[i].email.toLowerCase() === opts.email.toLowerCase()) {
86
- return { error: "This email is already registered" };
87
- }
88
- }
89
- }
90
- var user = {
91
- id: generateUserId(),
92
- username: opts.username,
93
- email: opts.email || null,
94
- displayName: opts.displayName || opts.username,
95
- pinHash: auth.hashPin(opts.pin),
96
- role: opts.role || "user",
97
- mustChangePin: !!opts.mustChangePin,
98
- createdAt: Date.now(),
99
- linuxUser: opts.linuxUser || null,
100
- profile: opts.profile || {
101
- name: opts.displayName || opts.username,
102
- lang: "en-US",
103
- avatarColor: "#5857fc",
104
- avatarStyle: "imprint",
105
- avatarSeed: crypto.randomBytes(4).toString("hex"),
106
- },
107
- };
108
- data.users.push(user);
109
- saveUsers(data);
110
-
111
- // Seed immediately for ordinary multi-user storage. OS-user provisioning
112
- // calls this again after the Linux mapping exists, targeting its final home.
113
- ensureUserBuiltinMates(user.id);
114
-
115
- return { ok: true, user: user };
116
- }
117
-
118
74
  function createAdmin(opts) {
119
75
  return createUser({
120
76
  username: opts.username,
@@ -188,7 +144,7 @@ function getSoloNoPinUser() {
188
144
  var data = loadUsers();
189
145
  if (!data.users || data.users.length !== 1) return null;
190
146
  var u = data.users[0];
191
- if (u.pinHash) return null;
147
+ if (u.pinHash || u.passwordHash || data.accountAuthMethod === 'password') return null;
192
148
  return u;
193
149
  }
194
150
 
@@ -199,6 +155,10 @@ function getOtherUsers(excludeUserId) {
199
155
  }
200
156
 
201
157
  function removeUser(userId) {
158
+ var registered = require("./config").loadConfig();
159
+ if (registered && (registered.projects || []).some(function (project) {
160
+ return !require("./project-ownership").isPersonal(project) && project.ownerId === userId;
161
+ })) return { error: "Transfer ordinary owned projects before deleting this account." };
202
162
  var data = loadUsers();
203
163
  var before = data.users.length;
204
164
  data.users = data.users.filter(function (u) { return u.id !== userId; });
@@ -224,6 +184,11 @@ function updateUserPin(userId, newPin) {
224
184
  for (var i = 0; i < data.users.length; i++) {
225
185
  if (data.users[i].id === userId) {
226
186
  data.users[i].pinHash = auth.hashPin(newPin);
187
+ if (data.accountAuthMethod === 'password') {
188
+ delete data.users[i].passwordHash;
189
+ delete data.users[i].passkeys;
190
+ delete data.users[i].passkeyUserHandle;
191
+ }
227
192
  data.users[i].mustChangePin = false;
228
193
  saveUsers(data);
229
194
  return { ok: true };
@@ -306,44 +271,6 @@ function createInvite(createdByUserId, targetEmail) {
306
271
  return invite;
307
272
  }
308
273
 
309
- function createUserWithoutPin(opts) {
310
- var data = loadUsers();
311
- for (var i = 0; i < data.users.length; i++) {
312
- if (data.users[i].username.toLowerCase() === opts.username.toLowerCase()) {
313
- return { error: "This username is already taken" };
314
- }
315
- }
316
- if (opts.email) {
317
- for (var i = 0; i < data.users.length; i++) {
318
- if (data.users[i].email && data.users[i].email.toLowerCase() === opts.email.toLowerCase()) {
319
- return { error: "This email is already registered" };
320
- }
321
- }
322
- }
323
- var user = {
324
- id: generateUserId(),
325
- username: opts.username,
326
- email: opts.email || null,
327
- displayName: opts.displayName || opts.username,
328
- pinHash: null,
329
- role: opts.role || "user",
330
- createdAt: Date.now(),
331
- profile: opts.profile || {
332
- name: opts.displayName || opts.username,
333
- lang: "en-US",
334
- avatarColor: "#5857fc",
335
- avatarStyle: "imprint",
336
- avatarSeed: crypto.randomBytes(4).toString("hex"),
337
- },
338
- };
339
- data.users.push(user);
340
- saveUsers(data);
341
-
342
- ensureUserBuiltinMates(user.id);
343
-
344
- return { ok: true, user: user };
345
- }
346
-
347
274
  function findInvite(code) {
348
275
  var data = loadUsers();
349
276
  for (var i = 0; i < data.invites.length; i++) {
@@ -400,8 +327,12 @@ function removeExpiredInvites() {
400
327
 
401
328
  // --- Wire extracted modules ---
402
329
 
403
- var auth = attachAuth({ loadUsers: loadUsers, saveUsers: saveUsers, findAdmin: findAdmin });
330
+ var auth = attachAuth({ loadUsers: loadUsers, saveUsers: saveUsers, findAdmin: findAdmin, loadConfig: require('./config').loadConfig });
331
+ var creation = require("./users-create").attachCreation({ loadUsers: loadUsers, saveUsers: saveUsers, generateUserId: generateUserId, ensureUserBuiltinMates: ensureUserBuiltinMates, auth: auth });
332
+ var createUser = creation.createUser;
333
+ var createUserWithoutPin = creation.createUserWithoutPin;
404
334
  var permissions = attachPermissions({ loadUsers: loadUsers, saveUsers: saveUsers, findUserById: findUserById });
335
+ var contextualClayPreferences = require("./users-contextual-clay-preferences").attachContextualClayPreferences({ loadUsers: loadUsers, saveUsers: saveUsers });
405
336
  var preferences = attachPreferences({ loadUsers: loadUsers, saveUsers: saveUsers });
406
337
  var projectMateFilterPreferences = attachProjectMateFilterPreferences({ loadUsers: loadUsers, saveUsers: saveUsers });
407
338
  var homeDockPreferences = attachHomeDockPreferences({ loadUsers: loadUsers, saveUsers: saveUsers });
@@ -489,6 +420,7 @@ module.exports = {
489
420
  validateSetupCode: validateSetupCode,
490
421
  generateUserId: generateUserId,
491
422
  hashPin: hashPin,
423
+ verifyPin: auth.verifyPin,
492
424
  createUser: createUser,
493
425
  createAdmin: createAdmin,
494
426
  findAdmin: findAdmin,
@@ -547,6 +479,8 @@ module.exports = {
547
479
  setToolPalette: setToolPalette,
548
480
  getTerminalFont: getTerminalFont,
549
481
  setTerminalFont: setTerminalFont,
482
+ getContextualClayGeometry: contextualClayPreferences.getContextualClayGeometry,
483
+ setContextualClayGeometry: contextualClayPreferences.setContextualClayGeometry,
550
484
  getHomeDockPreference: getHomeDockPreference,
551
485
  setHomeDockPreference: setHomeDockPreference,
552
486
  getHomeSurfacePreference: getHomeSurfacePreference,
@@ -7,17 +7,7 @@ var spawn = require("child_process").spawn;
7
7
  var buildUserEnv = require("./build-user-env").buildUserEnv;
8
8
  var wrapSpawnAsUser = require("./os-users").wrapSpawnAsUser;
9
9
 
10
- function loginUrl(value, vendor) {
11
- try {
12
- var url = new URL(value);
13
- var hosts = vendor === "codex" ? ["auth.openai.com"] : ["claude.ai", "claude.com", "console.anthropic.com", "platform.claude.com"];
14
- if (url.protocol !== "https:" || url.username || url.password || hosts.indexOf(url.hostname) < 0) return null;
15
- if (!url.searchParams.get("state") || !url.searchParams.get("code_challenge")) return null;
16
- var callback = new URL(url.searchParams.get("redirect_uri"));
17
- if (callback.protocol !== "http:" || ["localhost", "127.0.0.1", "[::1]"].indexOf(callback.hostname) < 0) return null;
18
- return url.href;
19
- } catch (e) { return null; }
20
- }
10
+ var loginUrl = require("./yoke/login-protocol").loginUrl;
21
11
 
22
12
  function createLoginBrowser(options) {
23
13
  var initial = null;
@@ -19,6 +19,8 @@ function attachWorkspaceAssignmentService(ctx) {
19
19
  var records = [];
20
20
  var unsubscribers = {};
21
21
  var pendingRestartReplay = {};
22
+ var presentations = new WeakMap();
23
+ var presentationTargets = new WeakMap();
22
24
 
23
25
  function recordFile(userId) {
24
26
  return storageDir ? path.join(storageDir, userStorageKey(userId)) : null;
@@ -130,7 +132,27 @@ function attachWorkspaceAssignmentService(ctx) {
130
132
  return { project: project, manager: manager, session: session };
131
133
  }
132
134
 
135
+ function present(record, principal) {
136
+ try {
137
+ var display = ctx.getPresentation && ctx.getPresentation(principal), project = exactTarget(record);
138
+ if (!display || !project) return;
139
+ var view = { project: project, session: null, origin: null }; presentationTargets.set(record, view);
140
+ if (record.delivery === 'follow_up') project.getSessionManager().sessions.forEach(function (session) { if (ctx.sessionRef(record.targetProjectSlug, session) === record.targetSessionRef) { view.session = session; view.origin = session.sessionOriginId; } });
141
+ var projection = require('./clay-control-target-projection');
142
+ var target = view.session ? { kind: 'session', projectSlug: record.targetProjectSlug, sessionId: view.session.localId, sessionOriginId: view.origin } : { kind: 'project', projectSlug: record.targetProjectSlug, runtimeId: projection.runtime(project.getSessionManager()) };
143
+ var observer = display.track('assignment', record.delivery === 'follow_up' ? 'follow_up' : 'assign', target, function () {
144
+ if (exactTarget(record) !== project || view.session && (project.getSessionManager().sessions.get(view.session.localId) !== view.session || view.session.sessionOriginId !== view.origin || (view.session.ownerId || null) !== (record.userId || null))) throw new Error('Assignment target changed.');
145
+ }, 'review');
146
+ if (observer) { presentations.set(record, observer); var expiry = setTimeout(function () { presentations.delete(record); }, 300000); expiry.unref(); }
147
+ } catch (error) { /* Presentation never changes the assignment decision. */ }
148
+ }
133
149
  function emit(record, eventType) {
150
+ var observer = presentations.get(record);
151
+ if (observer) {
152
+ if (record.status === 'starting') observer.phase('queued');
153
+ else if (record.status === 'running') observer.phase('running');
154
+ else if (record.status !== 'proposed') { observer.finish({ status: record.status === 'interrupted' ? 'failed' : record.status, outcome: record.status === 'interrupted' ? 'uncertain' : undefined }); presentations.delete(record); }
155
+ }
134
156
  var source = exactSource(record);
135
157
  if (!source) return;
136
158
  source.manager.sendAndRecord(source.session, {
@@ -193,6 +215,7 @@ function attachWorkspaceAssignmentService(ctx) {
193
215
  if (!exactSource(record)) throw new Error("Source conversation is no longer available.");
194
216
  records.push(record);
195
217
  saveUser(record.userId);
218
+ present(record, principal);
196
219
  emit(record, "project_assignment_proposal");
197
220
  return publicRecord(record);
198
221
  }
@@ -229,6 +252,7 @@ function attachWorkspaceAssignmentService(ctx) {
229
252
  if (!exactSource(record)) throw new Error("Source conversation is no longer available.");
230
253
  records.push(record);
231
254
  saveUser(record.userId);
255
+ present(record, principal);
232
256
  emit(record, "project_assignment_proposal");
233
257
  return publicRecord(record);
234
258
  }
@@ -267,6 +291,7 @@ function attachWorkspaceAssignmentService(ctx) {
267
291
  }
268
292
 
269
293
  function watch(record, manager, session) {
294
+ var view = presentationTargets.get(record); if (view) { view.session = session; view.origin = session.sessionOriginId; var observer = presentations.get(record); if (observer && observer.target) observer.target({ kind: 'session', projectSlug: record.targetProjectSlug, sessionId: session.localId, sessionOriginId: session.sessionOriginId }); }
270
295
  var unsubscribe = manager.subscribeSession(session.localId, function (event) {
271
296
  if (event.type === "session_id") {
272
297
  record.targetSessionRef = ctx.sessionRef(record.targetProjectSlug, session);
@@ -96,7 +96,10 @@ function attachWorkspaceQueryAccess(deps) {
96
96
  // as ownership would let a stale status skip the authoritative record.
97
97
  var access = record(status);
98
98
  if (!access) return denied;
99
- if (access.ownerId && access.ownerId === principal.userId) return { owned: true, accessible: true };
99
+ if (access.ownerId && access.ownerId === principal.userId) {
100
+ var ownerPermitted = permitted(principal.userId, access);
101
+ return { owned: ownerPermitted, accessible: ownerPermitted };
102
+ }
100
103
  return { owned: false, accessible: permitted(principal.userId, access) };
101
104
  }
102
105
 
@@ -32,7 +32,7 @@ function handler(bound, method) {
32
32
  };
33
33
  }
34
34
 
35
- var SESSION_CITATION = " When citing a returned session in user-visible text, write [clayos/<sessionRef> — short label] so Clay Studio renders an owner-validated session control.";
35
+ var SESSION_CITATION = " Cite returned sessions as Markdown links: [short human label](session:OPAQUE_REFERENCE), replacing the entire target with the exact returned sessionRef. Do not prepend a project name, change the opaque reference, or wrap citations in backticks/code. For a specific returned entry, append #entry-<entryIndex> using its exact returned entry index. Legacy [clayos/<sessionRef> — short label] remains supported. Labels are presentation only; Clay Studio resolves the exact reference with the authenticated owner's permissions.";
36
36
 
37
37
  function commonTools(bound) {
38
38
  return [
@@ -168,6 +168,13 @@ function attachWorkspaceQueryService(ctx) {
168
168
  } else if (source.session.ownerId) {
169
169
  return null;
170
170
  }
171
+ if (source.viewerId !== undefined) {
172
+ var viewerPrincipal = {
173
+ userId: isMultiUser() ? source.viewerId : null,
174
+ singleUserOwnerId: isMultiUser() ? null : source.viewerId,
175
+ };
176
+ if (!ownsSession(viewerPrincipal, source.session)) return null;
177
+ }
171
178
  return createBound({
172
179
  userId: isMultiUser() ? source.session.ownerId : null,
173
180
  sourceProjectSlug: source.projectSlug,
@@ -366,11 +373,13 @@ function attachWorkspaceQueryService(ctx) {
366
373
 
367
374
  function resolveSessionNavigation(principal, ref) {
368
375
  if (typeof ref !== "string" || !/^session:[A-Za-z0-9_-]{24}$/.test(ref)) throw new Error("Invalid session reference.");
376
+ var entryIndex = arguments.length > 2 ? arguments[2] : null;
377
+ if (entryIndex !== null && entryIndex !== undefined && (!Number.isSafeInteger(entryIndex) || entryIndex < 0)) throw new Error("Invalid session entry reference.");
369
378
  var projects = collect(principal);
370
379
  for (var p = 0; p < projects.length; p++) {
371
380
  var session = findSession(projects[p], ref);
372
381
  if (!session) continue;
373
- return {
382
+ var target = {
374
383
  projectSlug: projects[p].projectSlug,
375
384
  projectTitle: projects[p].projectTitle,
376
385
  isMate: projects[p].isMate,
@@ -379,6 +388,8 @@ function attachWorkspaceQueryService(ctx) {
379
388
  homeSessionId: session.cliSessionId || "local:" + session.localId,
380
389
  title: cleanMetadata(session.title || "New Session", 160),
381
390
  };
391
+ if (entryIndex !== null && entryIndex !== undefined) target.entryIndex = entryIndex;
392
+ return target;
382
393
  }
383
394
  throw new Error("Session not found in the owned workspace.");
384
395
  }
@@ -450,7 +461,7 @@ function attachWorkspaceQueryService(ctx) {
450
461
  if (!principal.isClay) throw new Error("Workspace-wide activity is available only to builtin Clay.");
451
462
  return workspaceActivity(principal, args || {});
452
463
  },
453
- resolveSessionNavigation: function (args) { return resolveSessionNavigation(principal, args && args.sessionRef); },
464
+ resolveSessionNavigation: function (args) { return resolveSessionNavigation(principal, args && args.sessionRef, args && args.entryIndex); },
454
465
  listRecentDecisions: function (args) {
455
466
  if (!principal.isClay) throw new Error("Workspace decisions are available only to builtin Clay.");
456
467
  return recentDecisions(principal, args || {});
package/lib/ws-request.js CHANGED
@@ -8,6 +8,7 @@ function parseWsRequestUrl(requestUrl) {
8
8
  path: parsed.pathname || "/",
9
9
  pane: parsed.query.pane === "1",
10
10
  paneSession: paneSession,
11
+ contextual: parsed.query.pane === "1" && parsed.query.contextual === "1",
11
12
  };
12
13
  }
13
14
 
package/lib/ws-schema.js CHANGED
@@ -11,6 +11,11 @@
11
11
  * Use it as a reference when adding new message types.
12
12
  */
13
13
 
14
+ // message.contextualSnapshot: version=1, viewId, nullable projectTitle,
15
+ // conversationTitle/projectSlug (160 characters), nullable positive sessionId,
16
+ // screen=Home|Project|Direct message. Private canonical owner delivery only.
17
+ // Persisted user_message metadata is echoed in message_ack only after recording;
18
+ // queued admission ACK has no snapshot. Never part of user text/pastes or authority.
14
19
  var schema = {
15
20
 
16
21
  // -----------------------------------------------------------------------
@@ -62,6 +67,7 @@ var schema = {
62
67
  "project_assignment_response": { direction: "c2s", handler: "lib/workspace-assignment-service.js", description: "Approve or cancel an exact-session cross-project assignment proposal" },
63
68
  "home_clay_session_resolve": { direction: "c2s", handler: "lib/server-home-chat.js", description: "Resolve an opaque Mate session reference through the exact bound source session" },
64
69
  "home_clay_session_target": { direction: "s2c", handler: "lib/public/modules/command-palette.js", description: "Return an owner-validated navigation target for a rendered Mate session reference" },
70
+ "home_clay_contextual_session": { direction: "s2c", handler: "lib/public/modules/contextual-search.js", description: "Return the exact fresh canonical session for an idempotent contextual Ask request; does not submit or execute a message" },
65
71
  "issues_list": { direction: "c2s", handler: "lib/project-issues.js", description: "Project Issues issues list" },
66
72
  "issue_read": { direction: "c2s", handler: "lib/project-issues.js", description: "Project Issues issue read" },
67
73
  "issue_create": { direction: "c2s", handler: "lib/project-issues.js", description: "Project Issues issue create" },
@@ -482,6 +488,7 @@ var schema = {
482
488
  "term_resized": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Terminal was resized" },
483
489
  "term_exited": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Terminal process exited" },
484
490
  "term_closed": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Terminal session was closed" },
491
+ "term_control_projection": { direction: "s2c", handler: "lib/public/modules/terminal.js", description: "Authoritative terminal identity/revision after owner resize without echoing resize input" },
485
492
  "term_list": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Full list of open terminals" },
486
493
  "term_error": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Terminal error (e.g. access denied)" },
487
494
  "shell_command": { direction: "c2s", handler: "lib/project-shell-command.js", description: "Run a one-shot shell command for agent context" },
@@ -495,10 +502,11 @@ var schema = {
495
502
  "note_written": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Agent created or updated a sticky note" },
496
503
  "note_update": { direction: "c2s", handler: "lib/project-user-message.js", description: "Update a sticky note" },
497
504
  "note_updated": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Sticky note was updated" },
498
- "note_close": { direction: "c2s", handler: "lib/project-user-message.js", description: "Close a sticky note (reversible; never deletes)" },
505
+ "note_update_result": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Correlated sticky note update result" },
506
+ "note_close": { direction: "c2s", handler: "lib/project-user-message.js", description: "Close a sticky note; human draft-aware requests remove empty notes, tool and legacy closes stay reversible" },
499
507
  "note_reopen": { direction: "c2s", handler: "lib/project-user-message.js", description: "Reopen a closed sticky note" },
500
508
  "note_delete": { direction: "c2s", handler: "lib/project-user-message.js", description: "Retired: older clients still send this; handled as a non-destructive close" },
501
- "note_deleted": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Retired: never sent. Closing broadcasts note_updated instead" },
509
+ "note_deleted": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "A sticky note was permanently removed after a human-authorized storage transaction" },
502
510
  "note_list_request": { direction: "c2s", handler: "lib/project-user-message.js", description: "Request the full notes list" },
503
511
  "note_bring_front": { direction: "c2s", handler: "lib/project-user-message.js", description: "Bring a note to front (update z-order)" },
504
512
  "notes_list": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Full list of sticky notes" },
@@ -784,6 +792,7 @@ var schema = {
784
792
  // -----------------------------------------------------------------------
785
793
  "home_mate_open": { direction: "c2s", handler: "lib/server-home-chat.js", description: "Open or restore the selected mate's embedded chat session" },
786
794
  "home_clay_ask": { direction: "c2s", handler: "lib/server-home-chat.js", description: "Start a fresh builtin Clay conversation from the global search drawer" },
795
+ "contextual_mate_sessions_result": { direction: "s2c", handler: "lib/public/modules/contextual-mate-sessions.js", description: "Exact owner-private saved Mate conversation list or selection receipt; no transcript tap or underlying navigation" },
787
796
  "home_mate_sessions_list": { direction: "c2s", handler: "lib/server-home-chat.js", description: "List the current user's conversations with the selected mate" },
788
797
  "home_mate_session_open": { direction: "c2s", handler: "lib/server-home-chat.js", description: "Open one explicit conversation with the selected mate" },
789
798
  "home_mate_send": { direction: "c2s", handler: "lib/server-home-chat.js", description: "Send a message to the selected mate from the home hub" },
@@ -809,6 +818,13 @@ var schema = {
809
818
  "default_vendor_get": { direction: "c2s", handler: "lib/server-default-vendor.js", description: "Read the authenticated user's New session vendor preference" },
810
819
  "default_vendor_set": { direction: "c2s", handler: "lib/server-default-vendor.js", description: "Validate and persist the authenticated user's New session vendor preference" },
811
820
  "default_vendor_state": { direction: "s2c", handler: "lib/public/modules/default-vendor.js", description: "Correlated or same-user-broadcast New session vendor preference" },
821
+ "clay_ui_ready": { direction: "c2s", handler: "lib/server-owner-ui.js", description: "Advertise exact owner UI navigation support on this socket" },
822
+ "clay_navigation_offer": { direction: "s2c", handler: "lib/public/modules/clay-owner-navigation.js", description: "Offer one exact reviewed navigation to a selected owner connection" },
823
+ "clay_navigation_claim": { direction: "c2s", handler: "lib/server-owner-ui.js", description: "Claim an offered navigation with live source/target revalidation" },
824
+ "clay_navigation_apply": { direction: "s2c", handler: "lib/public/modules/clay-owner-navigation.js", description: "Invoke the shared conversation navigator after live claim" },
825
+ "clay_studio_rendered": { direction: "c2s", handler: "lib/project-studio-presentation.js", description: "Exact source-viewer workbench render receipt; no product effects" },
826
+ "clay_navigation_rendered": { direction: "c2s", handler: "lib/server-owner-ui.js", description: "Bounded exact-viewer rendered conversation evidence; acceptance alone remains separate" },
827
+ "clay_navigation_ack": { direction: "c2s", handler: "lib/server-owner-ui.js", description: "Client invocation acknowledgement; never proof of visible rendering" },
812
828
  "context_view_get": { direction: "c2s", handler: "lib/server-context-view.js", description: "Read the authenticated user's context display preference" },
813
829
  "context_view_set": { direction: "c2s", handler: "lib/server-context-view.js", description: "Persist the authenticated user's context display preference" },
814
830
  "context_view_state": { direction: "s2c", handler: "lib/public/modules/context-view-preference.js", description: "Correlated or same-user-broadcast context display preference" },