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
@@ -0,0 +1,40 @@
1
+ import { store } from './store.js';
2
+ import { contextualMate, contextualTrigger } from './contextual-mate-identity.js';
3
+ import { getHomeMateName } from './home-mate-selection.js';
4
+
5
+ export function renderContextualMateHint() {
6
+ var state = store.get('contextualClay') || {};
7
+ var mate = contextualMate(state.mateId);
8
+ var active = state.mode === 'popover' && mate;
9
+ var narrow = window.matchMedia('(max-width: 768px)').matches;
10
+ var moved = document.querySelector('.contextual-mate-mobile-trigger');
11
+ if (moved && (!active || !narrow || moved.dataset.mateId !== mate.id)) {
12
+ moved.classList.remove('contextual-mate-mobile-trigger');
13
+ document.getElementById('icon-strip-projects').appendChild(moved);
14
+ }
15
+ var anchor = active && contextualTrigger(mate.id);
16
+ if (anchor && narrow && mate.builtinKey !== 'clay') {
17
+ anchor.classList.add('contextual-mate-mobile-trigger'); if (anchor.parentNode !== document.body) document.body.appendChild(anchor);
18
+ }
19
+ document.body.classList.toggle('contextual-mate-hint-mobile', !!active && narrow);
20
+ document.body.classList.toggle('contextual-mate-ordinary-mobile', !!active && narrow && mate.builtinKey !== 'clay');
21
+ document.querySelectorAll('[aria-describedby="contextual-mate-hint"]').forEach(function (item) { if (item !== anchor) item.removeAttribute('aria-describedby'); });
22
+ var hint = document.getElementById('contextual-mate-hint');
23
+ if (!hint || !active || !anchor || !anchor.getClientRects().length) { if (hint) hint.hidden = true; return null; }
24
+ anchor.setAttribute('aria-describedby', hint.id);
25
+ var name = getHomeMateName(mate);
26
+ hint.textContent = (window.matchMedia('(pointer: coarse)').matches ? 'Tap' : 'Click') + ' again to open ' + name;
27
+ hint.title = hint.textContent;
28
+ hint.setAttribute('aria-label', 'Open ' + name + ' workspace');
29
+ hint.hidden = false;
30
+ var rect = anchor.getBoundingClientRect();
31
+ hint.style.maxWidth = (narrow ? window.innerWidth - 64 : Math.min(260, window.innerWidth - rect.right - 24)) + 'px';
32
+ hint.style.left = (narrow ? 50 : rect.right + 8) + 'px';
33
+ hint.style.top = (narrow ? 8 : Math.max(8, Math.min(window.innerHeight - 38, rect.top + (rect.height - 28) / 2))) + 'px';
34
+ return hint.getBoundingClientRect();
35
+ }
36
+ export function initContextualMateHint(activate) {
37
+ var hint = document.createElement('button'); hint.type = 'button'; hint.id = 'contextual-mate-hint'; hint.hidden = true;
38
+ hint.addEventListener('click', function () { activate((store.get('contextualClay') || {}).mateId); });
39
+ document.body.appendChild(hint);
40
+ }
@@ -0,0 +1,23 @@
1
+ import { store } from './store.js';
2
+
3
+ export function contextualMate(id) {
4
+ var mate = (store.get('cachedMatesList') || []).find(function (item) { return item && item.id === id; });
5
+ if (!mate || mate.archived || mate.contentAccess === false || mate.accessible === false) return null;
6
+ var owner = store.get('myUserId');
7
+ if (owner && mate.createdBy && mate.createdBy !== owner) return null;
8
+ var project = (store.get('projectsHubList') || []).find(function (item) { return item.slug === 'mate-' + id; });
9
+ if (project && project.contentAccess === false) return null;
10
+ return mate;
11
+ }
12
+ export function contextualMateStamp(mate) { return JSON.stringify([mate.id, mate.createdBy || null, mate.createdAt || null, mate.builtinKey || null]); }
13
+ export function contextualFrame(id, sessionId) {
14
+ var mateId = id || (store.get('contextualClay') || {}).mateId;
15
+ var current = store.get('contextualClay') || {};
16
+ if (!sessionId && current.mateId === mateId && current.startingAsk) return null;
17
+ var selected = sessionId || (current.mateId === mateId && current.sessionId) || (store.get('contextualSessionSelection') || {})[mateId];
18
+ return Array.from(document.querySelectorAll('#contextual-clay iframe')).find(function (frame) { return frame.dataset.mateId === mateId && (!selected || String(selected) === frame.dataset.sessionId); }) || null;
19
+ }
20
+ export function contextualTrigger(id) {
21
+ var mate = contextualMate(id || (store.get('contextualClay') || {}).mateId);
22
+ return mate && mate.builtinKey !== 'clay' ? document.querySelector('.icon-strip-project-mate[data-mate-id="' + CSS.escape(mate.id) + '"]') : document.querySelector('.icon-strip-brand');
23
+ }
@@ -0,0 +1,134 @@
1
+ // Saved conversations are independent of which compact renderers are mounted.
2
+ import { store } from './store.js';
3
+ import { getWs } from './ws-ref.js';
4
+ import { contextualMate, contextualMateStamp, contextualFrame } from './contextual-mate-identity.js';
5
+ import { selectContextualConversation } from './contextual-clay.js';
6
+ import { pauseContextualSearchForSelection } from './contextual-search.js';
7
+ import { iconHtml, refreshIcons } from './icons.js';
8
+ import { showToast } from './utils.js';
9
+
10
+ function selection() { var value = store.get('contextualClay') || {}; return JSON.stringify([value.mateId, value.sessionId, value.startingAsk]); }
11
+ function host() { return document.getElementById('contextual-clay'); }
12
+ function requestState(kind) { return store.get(kind === 'list' ? 'contextualConversationHistory' : 'contextualConversationRequest'); }
13
+ function save(kind, value) { var update = {}; update[kind === 'list' ? 'contextualConversationHistory' : 'contextualConversationRequest'] = value; store.set(update); }
14
+ function valid(request) { var mate = request && contextualMate(request.mateId); return request && request.ownerId === store.get('myUserId') && mate && contextualMateStamp(mate) === request.stamp; }
15
+ function guardDraft() {
16
+ var frame = contextualFrame();
17
+ try {
18
+ if (frame && frame.conversation) frame.conversation.checkDraft();
19
+ return true;
20
+ } catch (error) { showToast(error.message, 'warn'); return false; }
21
+ }
22
+ function send(kind, item, lookup) {
23
+ var mate = contextualMate((store.get('contextualClay') || {}).mateId), socket = getWs();
24
+ if (!mate) return;
25
+ var old = requestState(kind);
26
+ if (kind !== 'list' && old && old.status === 'loading') { showToast('Wait for the current conversation request to finish.', 'warn'); return; }
27
+ if (kind !== 'list' && !guardDraft()) return;
28
+ var request = lookup ? Object.assign({}, old) : { requestId: 'mate-conversations-' + crypto.randomUUID(), mateId: mate.id, stamp: contextualMateStamp(mate), ownerId: store.get('myUserId'), selection: selection(), kind: kind, item: item };
29
+ if (!valid(request)) return;
30
+ request.status = 'loading'; request.error = null; request.socket = socket;
31
+ save(kind, request);
32
+ if (!store.get('connected') || !socket || socket.readyState !== 1) { save(kind, Object.assign({}, request, { status: 'error', error: 'Reconnect to load or start a conversation.' })); return; }
33
+ var payload = { type: kind === 'list' ? 'home_mate_sessions_list' : kind === 'new' ? 'home_mate_new_session' : 'home_mate_session_open', presentation: 'contextual', mateId: request.mateId, mateStamp: request.stamp, requestId: request.requestId };
34
+ if (item) { payload.sessionId = item.id; payload.sessionOriginId = item.sessionOriginId; }
35
+ if (lookup && kind === 'new') payload.lookupOnly = true;
36
+ try { socket.send(JSON.stringify(payload)); }
37
+ catch (error) { save(kind, Object.assign({}, request, { status: 'error', error: 'The request is unconfirmed. Check again after reconnecting.' })); }
38
+ setTimeout(function () {
39
+ var current = requestState(kind);
40
+ if (current && current.requestId === request.requestId && current.status === 'loading') save(kind, Object.assign({}, current, { status: 'error', error: kind === 'new' ? 'Creation is unconfirmed. Check the same request or browse history.' : 'Conversation history did not respond. Try again.' }));
41
+ }, 15000);
42
+ }
43
+ function age(timestamp) {
44
+ if (!timestamp) return '';
45
+ var date = new Date(timestamp), today = new Date();
46
+ return date.toDateString() === today.toDateString() ? 'Today' : date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
47
+ }
48
+ function render() {
49
+ var surface = host(); if (!surface) return;
50
+ var mateId = (store.get('contextualClay') || {}).mateId;
51
+ var request = requestState('action'), history = requestState('list');
52
+ var busy = request && request.mateId === mateId && request.status === 'loading';
53
+ surface.querySelector('[data-mate-new]').disabled = !!busy;
54
+ surface.querySelector('[data-mate-new]').setAttribute('aria-busy', String(!!busy));
55
+ var notice = surface.querySelector('[data-conversation-notice]');
56
+ notice.hidden = !request || request.mateId !== mateId || request.status === 'done';
57
+ if (!notice.hidden) {
58
+ notice.querySelector('span').textContent = request.error || (request.kind === 'new' ? 'Starting a new chat…' : 'Opening conversation…');
59
+ notice.querySelector('button').hidden = request.status !== 'error';
60
+ notice.querySelector('button').textContent = request.kind === 'new' ? 'Check request' : 'Try again';
61
+ }
62
+ var list = surface.querySelector('[data-mate-session-list]');
63
+ if (!surface.querySelector('[data-mate-history]').open) return;
64
+ var key = JSON.stringify([history && history.requestId, history && history.status, history && history.error, mateId, (store.get('contextualClay') || {}).sessionId, !!busy]);
65
+ if (list.dataset.renderKey === key) return;
66
+ list.dataset.renderKey = key;
67
+ list.replaceChildren();
68
+ if (!history || history.mateId !== mateId || history.status !== 'done') {
69
+ var status = document.createElement('p'); status.setAttribute('role', 'status');
70
+ status.textContent = history && history.mateId === mateId && history.error || 'Loading conversations…'; list.appendChild(status);
71
+ if (history && history.status === 'error') { var retry = document.createElement('button'); retry.type = 'button'; retry.textContent = 'Try again'; retry.onclick = function () { send('list'); }; list.appendChild(retry); }
72
+ return;
73
+ }
74
+ if (!history.sessions.length) { var empty = document.createElement('p'); empty.textContent = 'No saved conversations yet.'; list.appendChild(empty); }
75
+ history.sessions.forEach(function (item) {
76
+ var button = document.createElement('button'); button.type = 'button'; button.dataset.sessionId = String(item.localId);
77
+ button.setAttribute('aria-current', String(String((store.get('contextualClay') || {}).sessionId) === String(item.localId)));
78
+ var title = document.createElement('span'); title.textContent = item.title || 'New conversation';
79
+ var detail = document.createElement('small'); detail.textContent = item.isProcessing ? 'Working' : age(item.lastActivity || item.createdAt);
80
+ button.append(title, detail); button.title = title.textContent; button.disabled = !!busy;
81
+ button.onclick = function () { send('open', item); };
82
+ list.appendChild(button);
83
+ });
84
+ if (history.truncated) { var limit = document.createElement('p'); limit.textContent = 'Showing the 500 most recent conversations.'; list.appendChild(limit); }
85
+ }
86
+ export function attachContextualConversations(surface) {
87
+ var actions = surface.querySelector('.contextual-clay-actions');
88
+ var tools = document.createElement('div'); tools.className = 'contextual-conversation-tools';
89
+ tools.innerHTML = '<button type="button" data-mate-new aria-label="New chat" title="New chat">' + iconHtml('square-pen') + '<span>New chat</span></button><details data-mate-history><summary role="button" aria-label="Conversation history" aria-haspopup="dialog" aria-expanded="false" aria-controls="contextual-conversation-history" title="Conversation history">' + iconHtml('history') + '</summary><div id="contextual-conversation-history" role="dialog" aria-label="Conversation history"><span class="contextual-history-label">Conversations</span><div data-mate-session-list></div></div></details>';
90
+ actions.prepend(tools);
91
+ var notice = document.createElement('div'); notice.dataset.conversationNotice = ''; notice.hidden = true;
92
+ notice.innerHTML = '<span role="status"></span><button type="button">Check request</button>';
93
+ surface.insertBefore(notice, surface.querySelector('.contextual-clay-body'));
94
+ tools.querySelector('[data-mate-new]').onclick = function () { send('new'); };
95
+ tools.querySelector('details').addEventListener('toggle', function () { this.querySelector('summary').setAttribute('aria-expanded', String(this.open)); if (this.open) send('list'); });
96
+ surface.addEventListener('pointerdown', function (event) { var menu = tools.querySelector('details'); if (menu.open && !menu.contains(event.target)) menu.open = false; });
97
+
98
+ notice.querySelector('button').onclick = function () { var value = requestState('action'); if (value) send(value.kind, value.item, true); };
99
+ tools.addEventListener('keydown', function (event) {
100
+ if (event.key === 'Tab') {
101
+ var menu = tools.querySelector('details'), items = Array.from(tools.querySelectorAll('[data-mate-session-list] button:not(:disabled)'));
102
+ if (menu.open && (event.shiftKey && event.target === menu.querySelector('summary') || !event.shiftKey && event.target === items[items.length - 1])) queueMicrotask(function () { menu.open = false; });
103
+ return;
104
+ }
105
+ if (!/^Arrow(Down|Up)$/.test(event.key)) return;
106
+ var buttons = Array.from(tools.querySelectorAll('[data-mate-session-list] button:not(:disabled)'));
107
+ if (!buttons.length) return;
108
+ var index = buttons.indexOf(document.activeElement);
109
+ buttons[index < 0 ? (event.key === 'ArrowDown' ? 0 : buttons.length - 1) : (index + (event.key === 'ArrowDown' ? 1 : buttons.length - 1)) % buttons.length].focus(); event.preventDefault();
110
+ });
111
+ refreshIcons(); render();
112
+ }
113
+ export function handleContextualConversations(msg) {
114
+ if (msg.type !== 'contextual_mate_sessions_result') return false;
115
+ var kind = requestState('list') && requestState('list').requestId === msg.requestId ? 'list' : 'action';
116
+ var request = requestState(kind);
117
+ if (!request || request.status !== 'loading' || request.requestId !== msg.requestId || request.socket !== getWs() || !valid(request) || msg.mateId !== request.mateId || msg.mateStamp !== request.stamp) return true;
118
+ if (!msg.ok) { save(kind, Object.assign({}, request, { status: 'error', error: msg.error || 'Conversation unavailable.' })); return true; }
119
+ if (kind === 'list') { save(kind, Object.assign({}, request, { status: 'done', sessions: msg.sessions || [], truncated: msg.truncated })); return true; }
120
+ if (!Number.isSafeInteger(msg.sessionId) || msg.sessionId <= 0 || typeof msg.sessionOriginId !== 'string') return true;
121
+ if (request.selection !== selection() || (store.get('contextualClay') || {}).mode !== 'popover') { save(kind, Object.assign({}, request, { status: 'error', error: 'Your selection changed. The conversation remains in history.' })); return true; }
122
+ if (!guardDraft()) { save(kind, Object.assign({}, request, { status: 'error', error: 'Finish uploading or recording, then check this conversation again.' })); return true; }
123
+ pauseContextualSearchForSelection();
124
+ if (!selectContextualConversation(contextualMate(request.mateId), msg.sessionId, msg.sessionOriginId)) { save(kind, Object.assign({}, request, { status: 'error', error: 'This conversation could not be opened. Your draft is retained.' })); return true; }
125
+ surfaceClose(true); save(kind, Object.assign({}, request, { status: 'done' })); return true;
126
+ }
127
+ function surfaceClose(restoreFocus) { var surface = host(); if (surface) { var menu = surface.querySelector('[data-mate-history]'); var focused = menu.contains(document.activeElement); menu.open = false; if (focused || restoreFocus) menu.querySelector('summary').focus({ preventScroll: true }); } }
128
+ store.subscribe(function (value, previous) {
129
+ if (value.paneMode) return;
130
+ if (value.myUserId !== previous.myUserId) { store.set({ contextualConversationHistory: null, contextualConversationRequest: null }); return; }
131
+ if ((value.contextualClay || {}).mateId !== (previous.contextualClay || {}).mateId) surfaceClose();
132
+ if (previous.connected && !value.connected) ['list', 'action'].forEach(function (kind) { var request = requestState(kind); if (request && request.status === 'loading') save(kind, Object.assign({}, request, { status: 'error', error: 'Disconnected. Check again when connected; your conversation is retained.' })); });
133
+ render();
134
+ });
@@ -0,0 +1,137 @@
1
+ import { store } from './store.js';
2
+ import { getWs } from './ws-ref.js';
3
+ import { activateContextualMate } from './project-mate-navigation.js';
4
+ import { contextualMate, contextualMateStamp, contextualFrame } from './contextual-mate-identity.js';
5
+ import { showContextualAsk, enterComposer } from './contextual-clay.js';
6
+ import { showToast } from './utils.js';
7
+
8
+ function current() { return store.get('contextualSearchAsk'); }
9
+ function view() { return JSON.stringify([store.get('myUserId'), store.get('currentSlug'), store.get('activeSessionId'), store.get('homeShellVisible'), store.get('homeSubSurface'), store.get('dmMode'), store.get('rightWorkbenchOwner'), store.get('rightWorkbenchRevision')]); }
10
+ function patch(change) { store.set({ contextualSearchAsk: Object.assign({}, current(), change) }); }
11
+ function live(request) {
12
+ var mate = contextualMate(request.mateId);
13
+ return request.ownerId === store.get('myUserId') && mate && mate.builtinKey === 'clay' && contextualMateStamp(mate) === request.stamp;
14
+ }
15
+ function sendCreation() {
16
+ var request = current(), ws = getWs();
17
+ if (!request || !live(request)) { patch({ status: 'error', error: 'Clay is unavailable. Your question is retained.' }); return; }
18
+ if (!store.get('connected') || !ws || ws.readyState !== 1) { patch({ status: 'error', error: 'Reconnect, then retry. Your question is retained.' }); return; }
19
+ patch({ status: 'creating', socket: ws, view: view(), error: null });
20
+ try { ws.send(JSON.stringify({ type: 'home_clay_ask', presentation: 'contextual', requestId: request.requestId, text: request.text, sessionOriginId: request.sessionOriginId || null })); }
21
+ catch (error) { patch({ status: 'error', error: 'Creation is unconfirmed. Retry checks the same request.' }); }
22
+ setTimeout(function () { if (current() && current().requestId === request.requestId && current().status === 'creating') patch({ status: 'error', error: 'Conversation creation is unconfirmed. Retry checks the same request.' }); }, 15000);
23
+ }
24
+ export function pauseContextualSearchForSelection() {
25
+ if (current() && /^(creating|opening)$/.test(current().status)) stop();
26
+ }
27
+ function stop(execution) {
28
+ var request = current(), frame = request && request.sessionId && contextualFrame(request.mateId, request.sessionId);
29
+ if (frame && frame.conversation) { if (execution === true) frame.conversation.stopAsk(); else frame.conversation.pauseAsk(); }
30
+ patch({ status: 'stopped', error: request && request.clientMessageId ? 'Automatic delivery is paused. Inspect the conversation to confirm whether work stopped.' : 'Stopped before submission. Your question is retained; it will not be submitted automatically.' });
31
+ }
32
+ function resume() {
33
+ var request = current();
34
+ if (!request || !live(request)) return;
35
+ if (request.clientMessageId) { showToast('Inspect this conversation before retrying an uncertain message.', 'warn'); return; }
36
+ showContextualAsk(contextualMate(request.mateId), request.requestId, request.sessionId);
37
+ sendCreation();
38
+ }
39
+ function submit() {
40
+ var request = current();
41
+ if (!request || request.status !== 'opening') return;
42
+ if (!live(request) || request.view !== view()) { patch({ status: 'error', error: 'The view changed. Retry explicitly from the current view.' }); return; }
43
+ var frame = contextualFrame(request.mateId, request.sessionId);
44
+ if (!frame || frame.hidden || !frame.conversation || !frame.conversation.identity().ready) return;
45
+ var identity = frame.conversation.identity();
46
+ if (identity.ownerId !== request.ownerId || identity.sessionId !== request.sessionId || identity.sessionOriginId !== request.sessionOriginId || identity.mateId !== request.mateId) { patch({ status: 'error', error: 'The exact conversation identity changed. Nothing was submitted.' }); return; }
47
+ patch({ status: 'sending' });
48
+ var receipt = frame.conversation.submitAsk({ requestId: request.requestId, text: request.text, ownerId: request.ownerId, sessionId: request.sessionId, sessionOriginId: request.sessionOriginId });
49
+ if (!receipt || !receipt.clientMessageId) { patch({ status: 'error', error: 'Submission is unconfirmed. Inspect the retained question before retrying.' }); return; }
50
+ patch({ status: 'sent', clientMessageId: receipt.clientMessageId });
51
+ }
52
+ function render() {
53
+ var host = document.getElementById('contextual-clay');
54
+ if (!host) return;
55
+ var status = host.querySelector('[data-contextual-ask-status]');
56
+ if (!status) {
57
+ status = document.createElement('section'); status.dataset.contextualAskStatus = ''; status.setAttribute('role', 'region'); status.setAttribute('aria-label', 'Pending question');
58
+ status.innerHTML = '<div class="contextual-pending-question"><span>Pending question</span><blockquote data-ask-question></blockquote></div><div class="contextual-pending-progress"><p role="status" aria-live="polite" aria-atomic="true"></p><div><button type="button" data-ask-retry>Retry</button><button type="button" data-ask-stop>Stop</button><button type="button" data-ask-inspect>Open conversation</button></div></div>';
59
+ host.querySelector('.contextual-clay-body').appendChild(status);
60
+ status.querySelector('[data-ask-inspect]').addEventListener('click', function () { var request = current(); if (request && live(request)) activateContextualMate(request.mateId); });
61
+ status.querySelector('[data-ask-retry]').addEventListener('click', resume);
62
+ status.querySelector('[data-ask-stop]').addEventListener('click', function () { stop(true); });
63
+ host.addEventListener('contextual-clay-ready', submit);
64
+ host.addEventListener('contextual-clay-availability', function () {
65
+ var request = current(), frame = request && contextualFrame(request.mateId, request.sessionId);
66
+ if (request && request.status === 'opening' && frame && frame.conversation && frame.conversation.identity().available === false) patch({ status: 'error', error: 'This new conversation is unavailable. Your question is retained.' });
67
+ });
68
+ host.addEventListener('contextual-context-submitted', function (event) {
69
+ var request = current(), frame = request && contextualFrame(request.mateId, request.sessionId);
70
+ if (request && frame && frame.contentWindow === event.detail.source && request.clientMessageId && request.clientMessageId === event.detail.message.clientMessageId) patch({ status: 'acknowledged', acknowledged: true });
71
+ });
72
+ host.addEventListener('contextual-ask-stopped', function (event) { var request = current(), frame = request && contextualFrame(request.mateId, request.sessionId); if (frame && frame.contentWindow === event.detail.source) stop(); });
73
+ }
74
+ var focused = document.activeElement, ownedFocus = status.contains(focused);
75
+ var request = current(), selected = store.get('contextualClay') || {};
76
+ status.hidden = !request || selected.mateId !== request.mateId || request.acknowledged || request.status === 'acknowledged' || selected.sessionId && selected.sessionId !== request.sessionId;
77
+ if (request) {
78
+ status.querySelector('[data-ask-question]').textContent = request.text;
79
+ status.querySelector('p').textContent = request.error || (request.status === 'creating' ? 'Starting a new conversation. Your question is waiting.' : request.status === 'opening' ? 'Preparing this conversation. Nothing submitted yet.' : 'Waiting for confirmation. Delivery is not confirmed yet.');
80
+ status.querySelector('[data-ask-inspect]').hidden = !request.clientMessageId;
81
+ status.querySelector('[data-ask-retry]').hidden = request.status !== 'error' && request.status !== 'stopped' || !!request.clientMessageId;
82
+ status.querySelector('[data-ask-stop]').hidden = request.status === 'stopped';
83
+ }
84
+ host.dataset.askPending = String(!status.hidden);
85
+ var selectedFrame = contextualFrame();
86
+ host.querySelector('[data-clay-loading]').hidden = !status.hidden || !!(selectedFrame && selectedFrame.conversation && selectedFrame.conversation.identity().ready);
87
+ host.querySelectorAll('iframe').forEach(function (frame) { frame.inert = !status.hidden && frame.dataset.mateId === request.mateId && String(frame.dataset.sessionId) === String(request.sessionId); });
88
+ if (status.hidden) {
89
+ enterComposer();
90
+ if (ownedFocus && selectedFrame && selectedFrame.conversation && selectedFrame.conversation.identity().ready) selectedFrame.contentDocument.getElementById('input').focus({ preventScroll: true });
91
+ } else if (ownedFocus && focused.hidden) {
92
+ var nextControl = status.querySelector('[data-ask-retry]:not([hidden]), [data-ask-inspect]:not([hidden]), [data-ask-stop]:not([hidden])');
93
+ if (nextControl) nextControl.focus({ preventScroll: true });
94
+ }
95
+
96
+ }
97
+
98
+ export function startContextualSearch(text) {
99
+ text = typeof text === 'string' ? text.trim().slice(0, 12000) : '';
100
+ var mate = (store.get('cachedMatesList') || []).find(function (item) { return item.builtinKey === 'clay' && contextualMate(item.id); });
101
+ if (!text || !mate) { showToast('Clay is unavailable. Your question remains in Search.', 'warn'); return false; }
102
+ var request = current();
103
+ if (request && /^(creating|opening|sending|sent)$/.test(request.status)) { showToast('Clay is still starting the previous question. This question remains in Search.', 'warn'); return false; }
104
+ var requestId = 'contextual-search-' + crypto.randomUUID();
105
+ if (!showContextualAsk(mate, requestId, null)) return false;
106
+ store.set({ contextualSearchAsk: { requestId: requestId, text: text, mateId: mate.id, ownerId: store.get('myUserId'), stamp: contextualMateStamp(mate), status: 'creating', view: view() } });
107
+ render(); sendCreation(); return true;
108
+ }
109
+ export function retryContextualSearch() {
110
+ var request = current();
111
+ if (!request || !live(request) || request.clientMessageId || !/^(error|stopped)$/.test(request.status)) return false;
112
+ resume(); return true;
113
+ }
114
+ export function handleContextualSearchMessage(msg) {
115
+ var request = current();
116
+ if (!request || request.requestId !== msg.requestId) return false;
117
+ if (msg.type === 'home_mate_error') { patch({ status: 'error', error: msg.text || 'The conversation could not be started. Your question is retained.' }); return true; }
118
+ if (msg.type !== 'home_clay_contextual_session') return false;
119
+ if (request.status !== 'creating' || request.socket !== getWs() || !live(request) || request.mateId !== msg.mateId || !Number.isSafeInteger(msg.sessionId) || msg.sessionId <= 0 || typeof msg.sessionOriginId !== 'string' || request.sessionOriginId && request.sessionOriginId !== msg.sessionOriginId) return true;
120
+ if (request.view !== view()) { patch({ sessionId: msg.sessionId, sessionOriginId: msg.sessionOriginId, status: 'error', error: 'The view changed. Retry explicitly from the current view.' }); return true; }
121
+ patch({ sessionId: msg.sessionId, sessionOriginId: msg.sessionOriginId, status: 'opening' });
122
+ showContextualAsk(contextualMate(request.mateId), request.requestId, msg.sessionId);
123
+ var frame = contextualFrame(request.mateId, msg.sessionId);
124
+ if (frame) frame.dataset.contextualTitle = request.text.slice(0, 80);
125
+ setTimeout(function () { if (current() && current().requestId === request.requestId && current().status === 'opening') patch({ status: 'error', error: 'The conversation is not ready. Retry checks this same conversation.' }); }, 15000);
126
+ submit(); return true;
127
+ }
128
+ store.subscribe(function (value, previous) {
129
+ if (current() && current().ownerId !== value.myUserId) { store.set({ contextualSearchAsk: null }); return; }
130
+ if (current() && !live(current()) && /^(creating|opening)$/.test(current().status)) patch({ status: 'error', error: 'Clay is no longer available. Your question is retained.' });
131
+ if (current() && previous.connected && !value.connected && /^(creating|opening)$/.test(current().status)) patch({ status: 'error', error: 'Disconnected. Retry checks the same new conversation; your question is retained.' });
132
+ render();
133
+ });
134
+ document.addEventListener('click', function (event) {
135
+ var request = current();
136
+ if (request && store.get('currentSlug') === 'mate-' + request.mateId && store.get('activeSessionId') === request.sessionId && event.target.closest('#generation-stop, #autonomous-run-stop, #send-btn.stop')) stop();
137
+ }, true);
@@ -0,0 +1,58 @@
1
+ // Human citation clicks leave the pinned pane intact and use the parent viewer's
2
+ // existing authenticated reference resolver, never a project label as a target.
3
+ import { store } from './store.js';
4
+ import { getWs } from './ws-ref.js';
5
+ import { contextualFrame, contextualMate, contextualMateStamp } from './contextual-mate-identity.js';
6
+ import { parseClaySessionReference } from './clay-log-links.js';
7
+ import { requestClayRecordLink } from './command-palette.js';
8
+
9
+ function capture() {
10
+ var frame = contextualFrame(), state = store.get('contextualClay') || {}, mate = contextualMate(state.mateId);
11
+ var identity = frame && frame.conversation && frame.conversation.identity();
12
+ if (!mate || state.mode !== 'popover' || !frame || frame.hidden || frame.inert || !identity || !identity.ready || frame.conversation.source !== frame.contentWindow || identity.ownerId !== store.get('myUserId') || identity.mateId !== mate.id || frame.dataset.identityStamp !== contextualMateStamp(mate)) return null;
13
+ var surface = document.getElementById('contextual-clay');
14
+ return { mateId: mate.id, stamp: contextualMateStamp(mate), sessionId: identity.sessionId, originId: identity.sessionOriginId, ownerId: identity.ownerId, view: surface.dataset.screenReference, socket: getWs() };
15
+ }
16
+ export function validContextualCitation(context) {
17
+ var live = capture();
18
+ return !!(context && live && live.socket === context.socket && live.mateId === context.mateId && live.stamp === context.stamp && live.sessionId === context.sessionId && live.originId === context.originId && live.ownerId === context.ownerId && live.view === context.view);
19
+ }
20
+ export function contextualCitationLink(context, requestId) {
21
+ var frames = Array.from(document.querySelectorAll('#contextual-clay iframe'));
22
+ for (var frame of frames) {
23
+ var mate = contextualMate(frame.dataset.mateId), identity = frame.conversation && frame.conversation.identity();
24
+ if (!mate || !identity || identity.ownerId !== store.get('myUserId') || frame.dataset.identityStamp !== contextualMateStamp(mate)) continue;
25
+ if (context && (identity.mateId !== context.mateId || identity.sessionId !== context.sessionId || identity.sessionOriginId !== context.originId || context.ownerId !== identity.ownerId)) continue;
26
+ var link = Array.from(frame.contentDocument.querySelectorAll('.clayos-session-link')).find(function (item) { return item.dataset.sessionRequest === requestId; });
27
+ if (link) return link;
28
+ }
29
+ return null;
30
+ }
31
+ export function attachContextualSessionCitations(surface) {
32
+ surface.resolveSessionCitation = function (source, link) {
33
+ var context = capture(), frame = contextualFrame();
34
+ if (!context || !frame || frame.contentWindow !== source || !link || link.ownerDocument !== frame.contentDocument || !link.closest('.msg-assistant') || !parseClaySessionReference(link.dataset.sessionRef || '')) return false;
35
+ context.ref = link.dataset.sessionRef;
36
+ return requestClayRecordLink(link, context);
37
+ };
38
+ }
39
+ export function forwardContextualSessionCitation(link) {
40
+ if (!store.get('paneMode') || new URLSearchParams(location.search).get('contextual') !== '1') return false;
41
+ try {
42
+ var surface = window.parent.document.getElementById('contextual-clay');
43
+ if (surface && surface.resolveSessionCitation && surface.resolveSessionCitation(window, link)) return true;
44
+ } catch (error) { /* A changed authentication document cannot receive clicks. */ }
45
+ if (link.classList.contains('is-error')) return true;
46
+ link.classList.add('is-error'); link.title = 'This conversation or view changed. Reopen it before navigating.';
47
+ return true;
48
+ }
49
+ // Project transport replacement may discard an old reply before the palette
50
+ // sees it. Retire that pending UI receipt at the context change itself.
51
+ store.subscribe(function (value) {
52
+ var pending = value.sessionNavigationRequestContext;
53
+ if (value.paneMode || !pending || !pending.citation) return;
54
+ if (pending.projectSlug === value.currentSlug && pending.sessionId === value.activeSessionId && validContextualCitation(pending.citation)) return;
55
+ var link = contextualCitationLink(pending.citation, value.sessionNavigationRequestId);
56
+ if (link) { link.classList.remove('is-loading'); link.classList.add('is-error'); link.title = 'The view changed. Click again from the current conversation.'; delete link.dataset.sessionRequest; }
57
+ store.set({ sessionNavigationRequestId: null, sessionNavigationRequestContext: null });
58
+ });
@@ -58,6 +58,7 @@ function buildAvatarUrl(meta) {
58
58
  return mateAvatarUrl({
59
59
  id: meta.mateId,
60
60
  profile: {
61
+ avatarCatalogId: meta.avatarCatalogId || "",
61
62
  avatarStyle: meta.avatarStyle || "imprint",
62
63
  avatarSeed: meta.avatarSeed || meta.mateId || "mate",
63
64
  avatarColor: meta.avatarColor || "#5857fc",
@@ -110,6 +110,13 @@ function inlineCurrentSelection(state, draft) {
110
110
  return state.preference || state.selection || draft || {};
111
111
  }
112
112
 
113
+ function updateDraft(draft) {
114
+ var state = store.get('defaultAiState') || {};
115
+ var saved = state.preference || state.selection || {};
116
+ var dirty = ['vendor', 'model', 'effort'].some(function (key) {return (draft[key] || '') !== (saved[key] || '');});
117
+ store.set({defaultAiDraft:draft, defaultAiDraftDirty:dirty});
118
+ }
119
+
113
120
  function renderInlineSummary() {
114
121
  var state = store.get("defaultAiState") || {};
115
122
  var draft = store.get("defaultAiDraft") || {};
@@ -209,16 +216,16 @@ function render() {
209
216
  effort.disabled = !models.length || state.saving === true;
210
217
 
211
218
  vendor.addEventListener("change", function () {
212
- store.set({ defaultAiDraft: { vendor: vendor.value, model: "", effort: "" }, defaultAiDraftDirty: true });
219
+ updateDraft({ vendor: vendor.value, model: "", effort: "" });
213
220
  requestCatalog(vendor.value);
214
221
  render();
215
222
  });
216
223
  model.addEventListener("change", function () {
217
- store.set({ defaultAiDraft: { vendor: vendor.value, model: model.value, effort: "" }, defaultAiDraftDirty: true });
224
+ updateDraft({ vendor: vendor.value, model: model.value, effort: "" });
218
225
  render();
219
226
  });
220
227
  effort.addEventListener("change", function () {
221
- store.set({ defaultAiDraft: { vendor: vendor.value, model: model.value, effort: effort.value }, defaultAiDraftDirty: true });
228
+ updateDraft({ vendor: vendor.value, model: model.value, effort: effort.value });
222
229
  render();
223
230
  });
224
231
  addFieldLabel("Provider", vendor);
@@ -304,6 +311,7 @@ function applyCatalogMessage(msg, state) {
304
311
  draft = Object.assign({}, draft, { model: msg.selection.model, effort: msg.selection.effort || "" });
305
312
  }
306
313
  store.set({ defaultAiState: next, defaultAiDraft: draft });
314
+ updateDraft(draft);
307
315
  }
308
316
 
309
317
  function applyStateMessage(msg, state) {
@@ -4,6 +4,8 @@
4
4
  import { escapeHtml } from './utils.js';
5
5
  import { iconHtml } from './icons.js';
6
6
  import { getWs } from './ws-ref.js';
7
+ import { store } from './store.js';
8
+ import { currentPaneReview } from './pane-binding.js';
7
9
  import { fieldInfo, patternIsBounded, validateForm } from './elicitation-schema.js';
8
10
 
9
11
  var UNSET = "__clay_unset__";
@@ -154,12 +156,14 @@ function showFormError(container, message) {
154
156
  }
155
157
 
156
158
  function send(container, action, content, onSent) {
159
+ if (!currentPaneReview(container)) return false;
157
160
  var ws = getWs();
158
161
  if (!ws || ws.readyState !== 1) {
159
162
  showFormError(container, "Not connected. Try again when the connection is restored.");
160
163
  return false;
161
164
  }
162
165
  var msg = { type: "elicitation_response", requestId: container.dataset.requestId, action: action };
166
+ if (container.paneBinding) msg.paneBinding = container.paneBinding;
163
167
  if (action === "accept") msg.content = content;
164
168
  ws.send(JSON.stringify(msg));
165
169
  setBusy(container, true);
@@ -177,6 +181,7 @@ function actionButton(label, className, handler) {
177
181
 
178
182
  export function buildElicitationCard(msg, onSent) {
179
183
  var container = el("div", "permission-container elicitation-container");
184
+ container.paneBinding = store.get('panePendingBinding') || store.get('paneCommittedBinding') || null;
180
185
  container.dataset.requestId = msg.requestId;
181
186
  var header = el("div", "permission-header");
182
187
  header.innerHTML = '<span class="permission-icon">' + iconHtml("key") + '</span>' +
@@ -1,3 +1,5 @@
1
+ import { presentedDocument, refreshPresentedDocument, closePresentedDocument } from './clay-studio-document.js';
2
+ import { registerStudioPaint } from './clay-studio-render.js';
1
3
  import { iconHtml, refreshIcons } from './icons.js';
2
4
  import { escapeHtml, copyToClipboard } from './utils.js';
3
5
  import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks, exportMarkdownAsPdf } from './markdown.js';
@@ -192,6 +194,9 @@ export function initFileBrowser(_ctx) {
192
194
 
193
195
  document.getElementById("file-viewer-download").addEventListener("click", function () {
194
196
  if (!currentFilePath) return;
197
+ if ((store.get("studioDocumentView") || {}).descriptor && store.get("studioDocumentView").descriptor.path === currentFilePath) {
198
+ var link = document.createElement('a'); link.href = URL.createObjectURL(new Blob([currentContent || ''], { type: 'text/markdown;charset=utf-8' })); link.download = currentFilePath.split('/').pop(); link.click(); setTimeout(function () { URL.revokeObjectURL(link.href); }, 1000); return;
199
+ }
195
200
  downloadProjectFile(currentFilePath);
196
201
  });
197
202
 
@@ -459,12 +464,14 @@ function handleTreeKeyDown(e) {
459
464
 
460
465
  // --- File watch helpers ---
461
466
  function sendWatch(filePath) {
467
+ if ((store.get("studioDocumentView") || {}).descriptor && store.get("studioDocumentView").descriptor.path === filePath) return;
462
468
  if (ctx.ws && ctx.connected) {
463
469
  ctx.ws.send(JSON.stringify({ type: "fs_watch", path: filePath }));
464
470
  }
465
471
  }
466
472
 
467
473
  function sendUnwatch() {
474
+ if (store.get("studioDocumentView")) { closePresentedDocument(); return; }
468
475
  if (ctx.ws && ctx.connected) {
469
476
  ctx.ws.send(JSON.stringify({ type: "fs_unwatch" }));
470
477
  }
@@ -532,6 +539,7 @@ export function resetFileBrowser() {
532
539
  treeData = {};
533
540
  currentContent = null;
534
541
  currentFilePath = null;
542
+ store.set({ clayControlFileView: null });
535
543
  isRendered = false;
536
544
  currentIsMarkdown = false;
537
545
  currentIsSvg = false;
@@ -568,6 +576,7 @@ export function openFile(filePath, opts) {
568
576
  if (!state.connected) return false;
569
577
  if (opts && opts.projectSlug && opts.projectSlug !== state.currentSlug) return false;
570
578
  if (opts && opts.sessionId && String(opts.sessionId) !== String(state.activeSessionId)) return false;
579
+ closePresentedDocument();
571
580
  var workbenchRevision = claimRightWorkbench("file-viewer");
572
581
  if (followedFileChanged(filePath) || (opts && opts.diff && isFollowingMarkdown(filePath))) {
573
582
  cancelMarkdownFollow();
@@ -635,6 +644,7 @@ export function presentMarkdownEdit(msg) {
635
644
  content: typeof msg.content === "string" ? msg.content : "",
636
645
  size: msg.size || 0,
637
646
  });
647
+ registerStudioPaint(msg, document.querySelector("#file-viewer .file-viewer-header"), null, document.getElementById("file-viewer-body"));
638
648
  }
639
649
 
640
650
  function followedFileChanged(filePath) {
@@ -723,6 +733,7 @@ function requestDirectory(dirPath) {
723
733
  }
724
734
 
725
735
  function requestFileContent(filePath) {
736
+ if (refreshPresentedDocument(filePath)) return;
726
737
  var requestId = "file-read-" + Date.now() + "-" + Math.random().toString(36).slice(2);
727
738
  var state = store.snap();
728
739
  store.set({ fileReadRequest: { requestId: requestId, path: filePath, projectSlug: state.currentSlug || null, sessionId: state.activeSessionId != null ? String(state.activeSessionId) : null, accountId: state.myUserId || null, workbenchRevision: store.get('rightWorkbenchRevision') || 0 } });
@@ -1148,6 +1159,7 @@ function renderEntries(container, entries, depth) {
1148
1159
  // --- File viewer ---
1149
1160
 
1150
1161
  function showFileContent(msg, expectedRevision) {
1162
+ var priorTarget = document.querySelector("#file-viewer .file-viewer-header"); if (priorTarget) delete priorTarget.dataset.controlSurface;
1151
1163
  if (!updateFileViewerTab(msg.path, { content: msg.content })) return;
1152
1164
  if (expectedRevision != null && !isRightWorkbenchCurrent("file-viewer", expectedRevision)) return;
1153
1165
  var pathEl = document.getElementById("file-viewer-path");
@@ -1170,6 +1182,8 @@ function showFileContent(msg, expectedRevision) {
1170
1182
  pendingRefresh = false;
1171
1183
  currentContent = null;
1172
1184
  currentFilePath = msg.path;
1185
+ var sourceView = store.get('studioDocumentView'), sourceDescriptor = sourceView && sourceView.descriptor.path === msg.path ? sourceView.descriptor : null;
1186
+ store.set({ clayControlFileView: { path: msg.path, revision: msg.controlRevision || null, projectSlug: sourceDescriptor ? sourceDescriptor.sourceSlug : store.get('currentSlug'), runtimeId: sourceDescriptor ? sourceDescriptor.runtimeId : store.get('controlRuntimeId') } });
1173
1187
  currentIsMarkdown = false;
1174
1188
  currentIsSvg = false;
1175
1189
  store.set({ fileViewerIsPlantUml: false, fileViewerIsHtml: false });
@@ -1279,6 +1293,8 @@ function showFileContent(msg, expectedRevision) {
1279
1293
  store.set({ pendingFileNavigation: null });
1280
1294
  }
1281
1295
 
1296
+ var sourceView = presentedDocument(msg.path);
1297
+ if (sourceView) Array.from(bodyEl.querySelectorAll('.clay-file-link')).forEach(function (link) { link.dataset.fileProjectSlug = sourceView.descriptor.sourceSlug; link.dataset.fileSessionId = String(sourceView.descriptor.sourceSessionId); });
1282
1298
  // Request edit history for this file (skip on auto-refresh)
1283
1299
  if (!keepRenderState) {
1284
1300
  historyVisible = false;
@@ -1361,7 +1377,9 @@ function pathsReferToSameFile(left, right) {
1361
1377
  return a === b || a.endsWith("/" + b) || b.endsWith("/" + a);
1362
1378
  }
1363
1379
 
1364
- export function handleFileChanged(msg) {
1380
+ export function handleFileChanged(msg, presentedSource) {
1381
+ var source = store.get('studioDocumentView');
1382
+ if (source && source.descriptor.path === msg.path && (!presentedSource || presentedDocument(msg.path) !== presentedSource)) return;
1365
1383
  if (!msg.path || !pathsReferToSameFile(msg.path, currentFilePath)) return;
1366
1384
  if (ctx.fileViewerEl.classList.contains("hidden")) return;
1367
1385
  if (historyVisible || inlineDiffActive) return;
@@ -1602,6 +1620,7 @@ function formatSize(bytes) {
1602
1620
  // --- File edit history ---
1603
1621
 
1604
1622
  function requestFileHistory(filePath) {
1623
+ if ((store.get("studioDocumentView") || {}).descriptor && store.get("studioDocumentView").descriptor.path === filePath) return;
1605
1624
  if (ctx.ws && ctx.connected) {
1606
1625
  ctx.ws.send(JSON.stringify({ type: "fs_file_history", path: filePath }));
1607
1626
  }
@@ -2,6 +2,13 @@ import { store } from './store.js';
2
2
  import { getWs } from './ws-ref.js';
3
3
  import { isDriverOperatedView } from './worker-pane-lock.js';
4
4
 
5
+ export function stopGeneration() {
6
+ var ws = getWs();
7
+ if (!store.get('processing') || !store.get('connected') || !ws || ws.readyState !== 1) return false;
8
+ ws.send(JSON.stringify({ type: 'stop' }));
9
+ return true;
10
+ }
11
+
5
12
  // Fallback Stop control for when Send cannot double as Stop: a draft sitting
6
13
  // in the composer (Send stays Send so the draft can still go out), or a
7
14
  // locked configured Worker pane (Send and the rest of the composer are
@@ -31,11 +38,7 @@ export function initGenerationStop() {
31
38
  button.title = store.get('connected') ? 'Stop generating' : 'Reconnect to stop generating';
32
39
  place();
33
40
  }
34
- button.addEventListener('click', function () {
35
- var ws = getWs();
36
- if (!store.get('processing') || !store.get('connected') || !ws || ws.readyState !== 1) return;
37
- ws.send(JSON.stringify({ type: 'stop' }));
38
- });
41
+ button.addEventListener('click', stopGeneration);
39
42
  store.subscribe(function (state, previous) {
40
43
  if (state.processing !== previous.processing || state.connected !== previous.connected
41
44
  || state.splitGroups !== previous.splitGroups || state.activeSessionId !== previous.activeSessionId