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,112 @@
1
+ import { store } from './store.js';
2
+ import { getWs } from './ws-ref.js';
3
+ import { escapeHtml as escapeText } from './utils.js';
4
+
5
+ function escapeHtml(value) { return escapeText(String(value)).replace(/"/g, '"').replace(/'/g, '''); }
6
+ function state() { return store.get('sharedBrowserSettings') || {}; }
7
+ function set(patch) { store.set({ sharedBrowserSettings: Object.assign({}, state(), patch) }); }
8
+ function root() { return document.getElementById('shared-browser-settings'); }
9
+ function button(label, action, target, description) {
10
+ return '<button type="button" data-settings-action="' + action + '" data-target="' + escapeHtml(target || '') + '" data-label="' + escapeHtml(description || target || '') + '">' + escapeHtml(label) + '</button>';
11
+ }
12
+ function request(operation, target) {
13
+ var ws = getWs();
14
+ if (!ws || ws.readyState !== 1) { set({ error: 'Reconnect to manage browser data.', pending: false }); renderBrowserSettings(); return; }
15
+ var id = crypto.randomUUID();
16
+ set({ pending: true, requestId: id, error: '', notice: '' });
17
+ ws.send(JSON.stringify({ type: 'shared_browser_settings', sessionId: store.get('activeSessionId'), requestId: id, operation: operation, target: target }));
18
+ renderBrowserSettings();
19
+ setTimeout(function () {
20
+ if (state().requestId === id && state().pending) { set({ pending: false, error: 'The request timed out. Refresh to check the saved state.' }); renderBrowserSettings(); }
21
+ }, 15000);
22
+ }
23
+ export function closeBrowserSettings(restoreFocus) {
24
+ var wasOpen = !!state().open;
25
+ set({ open: false, review: null }); renderBrowserSettings();
26
+ var trigger = document.querySelector('[data-action="settings"]'); if (trigger && wasOpen && restoreFocus !== false) trigger.focus();
27
+ }
28
+ export function browserSettingsHtml() {
29
+ return '<section id="shared-browser-settings" class="shared-browser-settings" aria-label="Browser settings" hidden></section>';
30
+ }
31
+ export function bindBrowserSettings(panel) {
32
+ panel.querySelector('[data-action="settings"]').onclick = function () {
33
+ set({ open: true, page: 'sites', data: null, review: null, filter: '' });
34
+ request('list');
35
+ root().querySelector('[data-settings-action="back"]').focus();
36
+ };
37
+ root().addEventListener('keydown', function (event) {
38
+ if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); closeBrowserSettings(); }
39
+ });
40
+ root().addEventListener('input', function (event) {
41
+ if (event.target.matches('[data-settings-filter]')) { set({ filter: event.target.value }); renderRows(); root().dataset.key = JSON.stringify([state(), store.get('connected')]); }
42
+ });
43
+ root().addEventListener('click', function (event) {
44
+ var control = event.target.closest('[data-settings-action]');
45
+ if (!control || control.disabled) return;
46
+ var action = control.dataset.settingsAction;
47
+ if (action === 'back') { closeBrowserSettings(); return; }
48
+ if (action === 'sites' || action === 'history') { set({ page: action, filter: '', review: null, notice: '', error: '' }); renderBrowserSettings(); return; }
49
+ if (action === 'refresh') { request('list'); return; }
50
+ if (action === 'cancel') { set({ review: null }); renderBrowserSettings(); root().querySelector('[data-settings-action="refresh"]').focus(); return; }
51
+ if (action === 'confirm') { var review = state().review; if (review) request(review.action, review.target); return; }
52
+ set({ notice: '', error: '', review: { action: action, target: control.dataset.target, label: control.dataset.label || control.dataset.target } });
53
+ renderBrowserSettings(); root().querySelector('[data-settings-action="cancel"]').focus();
54
+ });
55
+ }
56
+ function renderRows() {
57
+ var el = root(), s = state(); if (!el || !s.open) return;
58
+ var rows = el.querySelector('.browser-settings-rows'); if (!rows) return;
59
+ var filter = (s.filter || '').toLowerCase();
60
+ var data = s.data || { sites: [], history: [] };
61
+ if (s.page === 'history') {
62
+ rows.innerHTML = data.history.filter(function (entry) { return entry.url.toLowerCase().includes(filter); }).map(function (entry) {
63
+ return '<div class="browser-settings-row"><div><span class="browser-settings-url">' + escapeHtml(entry.url) + '</span><small>' + escapeHtml(new Date(entry.at).toLocaleString()) + '</small></div>' + button('Remove', 'delete_history', entry.id, entry.url) + '</div>';
64
+ }).join('');
65
+ } else {
66
+ rows.innerHTML = data.sites.filter(function (site) { return site.host.toLowerCase().includes(filter); }).map(function (site) {
67
+ return '<details><summary>' + escapeHtml(site.host) + '<small>' + site.cookies.length + (site.cookies.length === 1 ? ' cookie · ' : ' cookies · ') + site.origins.length + (site.origins.length === 1 ? ' storage origin' : ' storage origins') + '</small></summary><div class="browser-settings-row"><span>Cookies and site storage</span>' + button('Remove site data', 'delete_site', site.host) + '</div>' +
68
+ site.origins.map(function (origin) { return '<p class="browser-settings-origin">' + escapeHtml(origin.origin) + '<small>' + origin.localStorage + ' localStorage entries · ' + origin.databases + ' IndexedDB databases</small></p>'; }).join('') +
69
+ site.cookies.map(function (cookie) {
70
+ var info = cookie.domain + cookie.path + ' · ' + (cookie.expires === -1 ? 'Session cookie' : 'Expires ' + new Date(cookie.expires * 1000).toLocaleDateString()) + (cookie.httpOnly ? ' · HttpOnly' : '') + (cookie.secure ? ' · Secure' : '') + (cookie.partitioned ? ' · Partitioned' : '');
71
+ return '<div class="browser-settings-row"><div><span>' + escapeHtml(cookie.name) + '</span><small>' + escapeHtml(info) + '</small></div>' + button('Remove cookie', 'delete_cookie', cookie.id, cookie.name + ' · ' + cookie.domain + cookie.path) + '</div>';
72
+ }).join('') + '</details>';
73
+ }).join('');
74
+ }
75
+ if (!rows.innerHTML) rows.innerHTML = '<p class="browser-settings-muted">' + (s.pending && !s.data ? 'Loading saved data…' : filter ? 'No matching entries.' : s.page === 'history' ? 'No saved browsing history.' : 'No saved cookies or site data.') + '</p>';
76
+ rows.querySelectorAll('button').forEach(function (control) { control.disabled = !!s.pending || !store.get('connected'); });
77
+ }
78
+ export function renderBrowserSettings() {
79
+ var el = root(); if (!el) return;
80
+ var s = state(), panel = el.closest('.shared-browser-panel');
81
+ var browser = store.get('sharedBrowser');
82
+ var trigger = panel.querySelector('[data-action="settings"]');
83
+ trigger.hidden = !(browser && browser.personalCookiesAvailable);
84
+ trigger.disabled = !store.get('connected');
85
+ trigger.setAttribute('aria-expanded', String(!!s.open));
86
+ el.hidden = !s.open;
87
+ panel.classList.toggle('browser-settings-open', !!s.open);
88
+ if (!s.open) return;
89
+ var key = JSON.stringify([s, store.get('connected')]); if (el.dataset.key === key) return; el.dataset.key = key;
90
+ var page = s.page || 'sites';
91
+ el.innerHTML = '<div class="browser-settings-heading">' + button('Back to browser', 'back') + '<h3>Browser settings</h3></div><p class="browser-settings-muted">Personal · Shared across your Mates. Incognito tabs do not save data here.</p>' +
92
+ '<nav aria-label="Browser settings sections">' + button('Cookies & site data', 'sites') + button('History', 'history') + '</nav>' +
93
+ '<p class="browser-settings-muted">' + (page === 'sites' ? 'Cookies, localStorage and IndexedDB are saved for your account. New personal tabs restore saved site storage. Removing data may sign you out. Removals also apply to open personal tabs. Sites may create new data afterwards.' : 'Your latest 500 page visits. Clearing this list leaves open tabs, their Back/Forward navigation and conversation activity unchanged.') + '</p>' +
94
+ '<div class="browser-settings-tools"><input data-settings-filter aria-label="Filter saved browser data" placeholder="' + (page === 'sites' ? 'Find a site' : 'Find a page') + '" value="' + escapeHtml(s.filter || '') + '">' + button('Refresh', 'refresh') + button(page === 'sites' ? 'Clear all site data' : 'Clear history', page === 'sites' ? 'clear_data' : 'clear_history') + '</div>' +
95
+ '<p class="browser-settings-feedback" role="status">' + escapeHtml(s.error || (!store.get('connected') ? 'Disconnected. Reconnect and refresh to see current saved data.' : s.pending ? 'Updating…' : s.notice || '')) + '</p>' +
96
+ (s.review ? '<div class="browser-settings-review" role="group" aria-label="Confirm removal"><strong>' + (s.review.action.includes('history') ? 'Remove browsing history?' : 'Remove saved site data?') + '</strong><p>' + (s.review.action.includes('history') ? 'This removes ' + (s.review.action === 'clear_history' ? 'all saved visits' : 'this saved visit') + ' from your personal history.' : s.review.action === 'delete_cookie' ? 'This removes ' + escapeHtml(s.review.label) + ' across your personal Mate browsers and may sign you out.' : 'This removes ' + (s.review.action === 'clear_data' ? 'all cookies and site storage' : 'cookies and storage for ' + escapeHtml(s.review.target)) + ' across your personal Mate browsers and may sign you out.') + '</p>' + button('Cancel', 'cancel') + button('Remove', 'confirm') + '</div>' : '') +
97
+ '<div class="browser-settings-rows"></div>';
98
+ el.querySelector('[data-settings-action="' + page + '"]').setAttribute('aria-current', 'page');
99
+ el.querySelectorAll('button').forEach(function (control) { control.disabled = control.dataset.settingsAction !== 'back' && (!!s.pending || !store.get('connected')); });
100
+ renderRows();
101
+ }
102
+ export function handleBrowserSettingsMessage(msg) {
103
+ if (!msg.requestId || msg.requestId !== state().requestId) return false;
104
+ if (msg.type === 'shared_browser_settings') {
105
+ var removed = !!state().review;
106
+ set({ data: msg.settings, pending: false, review: null, error: '', notice: removed ? 'Removed from your saved browser data.' : '' });
107
+ } else if (msg.type === 'shared_browser_error') set({ pending: false, error: msg.error });
108
+ else return false;
109
+ renderBrowserSettings();
110
+ if (state().open && removed) root().querySelector('[data-settings-action="refresh"]').focus();
111
+ return true;
112
+ }
@@ -1,10 +1,11 @@
1
+ import { iconHtml, refreshIcons } from './icons.js';
1
2
  import { store } from './store.js';
2
3
 
3
4
  export function renderBrowserTabs(el, select, send) {
4
5
  var bar = el.querySelector('.shared-browser-tabs');
5
6
  var tabs = store.get('sharedBrowsers') || [];
6
7
  var selected = store.get('sharedBrowser');
7
- var key = JSON.stringify([tabs.map(function (tab) { return [tab.id, tab.url, tab.control, tab.phase]; }), selected && selected.id, store.get('connected')]);
8
+ var key = JSON.stringify([tabs.map(function (tab) { return [tab.id, tab.url, tab.control, tab.phase, tab.incognito, tab.personalCookiesAvailable]; }), selected && selected.id, store.get('connected')]);
8
9
  if (bar.dataset.key === key) return;
9
10
  bar.dataset.key = key;
10
11
  bar.replaceChildren();
@@ -14,9 +15,9 @@ export function renderBrowserTabs(el, select, send) {
14
15
  button.setAttribute('aria-selected', String(!!selected && selected.id === tab.id));
15
16
  var title = 'Tab ' + (index + 1);
16
17
  try { if (tab.url) title = new URL(tab.url).hostname; } catch (e) {}
17
- var label = document.createElement('span'); label.textContent = title;
18
+ var label = document.createElement('span'); label.textContent = title + (tab.personalCookiesAvailable && tab.incognito ? ' · Incognito' : '');
18
19
  var owner = document.createElement('small'); owner.textContent = tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'Shared' : 'You only';
19
- button.append(label, owner); button.title = title + ' · ' + (tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'You and Clay can control this tab' : 'Only you can control this tab. Clay is paused.');
20
+ button.append(label, owner); button.title = title + ' · ' + (tab.incognito === false ? 'Personal browser' : 'Incognito') + ' · ' + (tab.phase === 'ended' ? 'Ended' : tab.control === 'agent' ? 'You and Clay can control this tab' : 'Only you can control this tab. Clay is paused.');
20
21
  button.onclick = function () { select(tab.id); };
21
22
  button.onkeydown = function (event) {
22
23
  var next = event.key === 'ArrowRight' ? (index + 1) % tabs.length : event.key === 'ArrowLeft' ? (index + tabs.length - 1) % tabs.length : event.key === 'Home' ? 0 : event.key === 'End' ? tabs.length - 1 : -1;
@@ -28,6 +29,15 @@ export function renderBrowserTabs(el, select, send) {
28
29
  item.append(button, close); bar.appendChild(item);
29
30
  });
30
31
  var add = document.createElement('button'); add.type = 'button'; add.textContent = '+'; add.setAttribute('aria-label', 'New browser tab'); add.disabled = !store.get('connected');
32
+ add.title = selected && selected.personalCookiesAvailable ? 'New tab · Personal browser' : 'New incognito tab';
31
33
  add.onclick = function () { send('open', { newTab: true }); };
32
34
  bar.appendChild(add);
35
+ if (selected && selected.personalCookiesAvailable) {
36
+ var incognito = document.createElement('button'); incognito.type = 'button';
37
+ incognito.innerHTML = iconHtml('glasses');
38
+ incognito.setAttribute('aria-label', 'New incognito tab'); incognito.title = 'New incognito tab · Site data is not saved';
39
+ incognito.disabled = !store.get('connected');
40
+ incognito.onclick = function () { send('open', { newTab: true, incognito: true }); };
41
+ bar.appendChild(incognito); refreshIcons();
42
+ }
33
43
  }
@@ -1,3 +1,6 @@
1
+ import { registerStudioPaint } from './clay-studio-render.js';
2
+ import { browserLinkTarget, initBrowserLinks } from './clay-browser-links.js';
3
+ import { browserSettingsHtml, bindBrowserSettings, renderBrowserSettings, closeBrowserSettings, handleBrowserSettingsMessage } from './shared-browser-settings.js';
1
4
  import { renderBrowserTabs } from './shared-browser-tabs.js';
2
5
  import { store } from './store.js';
3
6
  import { getWs } from './ws-ref.js';
@@ -50,15 +53,15 @@ function ensurePanel() {
50
53
  el.className = 'shared-browser-panel hidden';
51
54
  el.setAttribute('aria-label', 'Shared browser');
52
55
  el.innerHTML = '<header class="shared-browser-header"><span class="shared-browser-title">' + iconHtml('globe') + 'Browser</span><span class="shared-browser-phase" role="status">Ready</span><div class="shared-browser-window">' +
53
- iconButton('wide', 'chevrons-left-right', 'Widen browser panel') + iconButton('fullscreen', 'maximize-2', 'Toggle browser fullscreen') + iconButton('hide', 'x', 'Hide browser panel') + '</div></header>' +
56
+ iconButton('settings', 'settings-2', 'Browser settings') + iconButton('wide', 'chevrons-left-right', 'Widen browser panel') + iconButton('fullscreen', 'maximize-2', 'Toggle browser fullscreen') + iconButton('hide', 'x', 'Hide browser panel') + '</div></header>' +
54
57
  '<div class="shared-browser-tabs" role="tablist" aria-label="Browser tabs"></div><form class="shared-browser-address">' + iconButton('back', 'arrow-left', 'Back') + iconButton('forward', 'arrow-right', 'Forward') + iconButton('reload', 'rotate-cw', 'Reload') +
55
58
  '<input aria-label="Browser address" placeholder="Enter a URL" type="text" autocomplete="off" spellcheck="false"><button type="submit" aria-label="Open address">' + iconHtml('arrow-right') + '</button></form>' +
56
- '<div class="shared-browser-viewport"><div class="shared-browser-monitor"><div class="shared-browser-pointer-layer" aria-hidden="true"><div class="shared-browser-pointer" hidden><svg viewBox="0 0 24 28"><path d="M3 2 L3 22 L8 17 L12 26 L16 24 L12 15 L20 15 Z"/></svg><i></i></div></div><canvas width="1280" height="800" tabindex="0" aria-label="Shared browser page"></canvas>' +
57
- '<div class="shared-browser-empty">' + iconHtml('globe') + '<h3>A browser you can share with your Driver</h3><p>Enter an address to browse together.<br>Localhost connects to the Clay host.</p><p class="shared-browser-private">Cookies last only for this browser session.</p></div>' +
59
+ browserSettingsHtml() + '<div class="shared-browser-viewport"><div class="shared-browser-monitor"><div class="shared-browser-pointer-layer" aria-hidden="true"><div class="shared-browser-pointer" hidden><svg viewBox="0 0 24 28"><path d="M3 2 L3 22 L8 17 L12 26 L16 24 L12 15 L20 15 Z"/></svg><i></i></div></div><canvas width="1280" height="800" tabindex="0" aria-label="Shared browser page"></canvas>' +
60
+ '<div class="shared-browser-empty">' + iconHtml('globe') + '<h3>A browser you can use with Clay</h3><p>Enter an address to browse together.<br>Localhost connects to the Clay host.</p><p class="shared-browser-private">Site data lasts only for this browser session.</p></div>' +
58
61
  '<textarea class="shared-browser-keyboard" aria-label="Type into shared browser" autocomplete="off" autocapitalize="off" spellcheck="false"></textarea><span class="shared-browser-monitor-brand" aria-hidden="true">Clay Studio</span><span class="shared-browser-monitor-detail" aria-hidden="true"></span><span class="shared-browser-monitor-stand" aria-hidden="true"></span></div><div class="shared-browser-caption"><span class="shared-browser-monitor-label"></span>' + activityHtml() + '</div></div>' +
59
62
  '<p class="shared-browser-error hidden" role="status"></p>' +
60
63
  '<footer class="shared-browser-footer"><div class="shared-browser-control"><span class="shared-browser-control-status" role="status" aria-live="polite">You and Clay can control this browser</span><button type="button" data-action="control" aria-pressed="false"></button></div>' +
61
- '<div class="shared-browser-details">' + viewportMenuHtml() + '<button type="button" data-action="end">End browser</button></div></footer>';
64
+ '<div class="shared-browser-details"><span class="shared-browser-cookie-mode"></span>' + viewportMenuHtml() + '<button type="button" data-action="end">End browser</button></div></footer>';
62
65
  root.appendChild(el);
63
66
  el.querySelector('[data-action="hide"]').onclick = hideSharedBrowser;
64
67
  el.querySelector('[data-action="wide"]').onclick = function () { var wide = !(store.get('sharedBrowserUi') || {}).wide; ui({ wide: wide }); render(); };
@@ -69,8 +72,9 @@ function ensurePanel() {
69
72
  var browser = store.get('sharedBrowser');
70
73
  if (browser) send('control', { control: browser.control === 'user' ? 'agent' : 'user' });
71
74
  };
72
- el.querySelector('[data-action="end"]').onclick = function () { var browser = store.get('sharedBrowser'); send(browser && browser.phase === 'ended' ? 'open' : 'end'); };
75
+ el.querySelector('[data-action="end"]').onclick = function () { var browser = store.get('sharedBrowser'); send(browser && browser.phase === 'ended' ? 'open' : 'end', browser && browser.phase === 'ended' ? { incognito: browser.incognito } : undefined); };
73
76
  bindViewportMenu(el);
77
+ bindBrowserSettings(el);
74
78
  var observer = new ResizeObserver(layoutMonitor);
75
79
  observer.observe(el.querySelector('.shared-browser-viewport'));
76
80
  bindBrowserInput(el.querySelector('canvas'), el.querySelector('textarea'));
@@ -141,11 +145,16 @@ function render() {
141
145
  el.querySelector('[data-action="control"]').hidden = !live;
142
146
  el.querySelector('[data-action="end"]').disabled = !browser || !connected;
143
147
  el.querySelector('[data-action="end"]').textContent = browser && browser.phase === 'ended' ? 'New browser' : 'End browser';
148
+ var personal = browser && browser.incognito === false;
149
+ el.querySelector('.shared-browser-cookie-mode').textContent = personal ? 'Personal browser' : 'Incognito';
150
+ el.querySelector('.shared-browser-cookie-mode').title = personal ? 'Cookies and site storage are saved for your account across your Mates.' : 'Cookies and site storage are isolated and discarded when this tab ends.';
151
+ el.querySelector('.shared-browser-private').textContent = personal ? 'Your cookies and site storage are remembered across your Mates and browser restarts.' : 'Site data lasts only for this browser session.';
144
152
  var error = state.error || (browser && browser.error) || '';
145
153
  el.querySelector('.shared-browser-error').textContent = error;
146
154
  el.querySelector('.shared-browser-error').classList.toggle('hidden', !error);
147
155
  el.querySelector('.shared-browser-empty').classList.toggle('hidden', !!(browser && browser.url && state.hasFrame));
148
156
  renderViewportMenu(el, browser, operable);
157
+ renderBrowserSettings();
149
158
  renderBrowserActivity(el, browser, connected);
150
159
  layoutMonitor();
151
160
  }
@@ -163,6 +172,16 @@ function selectBrowserTab(id) {
163
172
  setBrowserTab(browser);
164
173
  send('view', { visible: desktop() && !document.hidden }); render();
165
174
  }
175
+ export function openSharedBrowserAt(value) {
176
+ var url = browserLinkTarget('browser:' + value);
177
+ if (!url) throw new Error('Enter a valid HTTP or HTTPS browser address.');
178
+ if (!desktop()) throw new Error('Clay Browser is available on desktop screens.');
179
+ if (!eligible()) throw new Error('Browser access is unavailable in this conversation.');
180
+ if (!store.get('connected')) throw new Error('Reconnect before opening this browser link.');
181
+ ensurePanel(); closeBrowserSettings(false);
182
+ claimRightWorkbench('browser'); store.set({ sharedBrowserOpen: true });
183
+ ui({ error: '' }); send('open', { url: url }); render();
184
+ }
166
185
  export function openSharedBrowser() {
167
186
  if (!eligible() || !store.get('connected')) return;
168
187
  ensurePanel();
@@ -175,6 +194,7 @@ export function openSharedBrowser() {
175
194
  }
176
195
  export function hideSharedBrowser() {
177
196
  closeViewportMenu();
197
+ closeBrowserSettings();
178
198
  clearBrowserInput();
179
199
  if (store.get('sharedBrowserOpen')) send('view', { visible: false });
180
200
  store.set({ sharedBrowserOpen: false });
@@ -184,6 +204,7 @@ export function hideSharedBrowser() {
184
204
  export function handleSharedBrowserMessage(msg) {
185
205
  if (!msg.type || msg.type.indexOf('shared_browser_') !== 0) return false;
186
206
  if (String(msg.sessionId) !== String(store.get('activeSessionId'))) return true;
207
+ if (handleBrowserSettingsMessage(msg)) return true;
187
208
  if (msg.type === 'shared_browser_state') {
188
209
  var old = store.get('sharedBrowser');
189
210
  var tabs = msg.browsers || (msg.browser ? [msg.browser] : []);
@@ -209,6 +230,7 @@ export function handleSharedBrowserMessage(msg) {
209
230
  var canvas = panel().querySelector('canvas'); canvas.width = image.naturalWidth; canvas.height = image.naturalHeight;
210
231
  canvas.getContext('2d').drawImage(image, 0, 0);
211
232
  ui({ decoding: false, hasFrame: true }); render();
233
+ registerStudioPaint(msg, canvas, null, canvas);
212
234
  }
213
235
  };
214
236
  image.onerror = function () { if (store.get('activeSessionId') === sessionId) ui({ decoding: false }); };
@@ -217,6 +239,7 @@ export function handleSharedBrowserMessage(msg) {
217
239
  return true;
218
240
  }
219
241
  export function initSharedBrowser() {
242
+ initBrowserLinks();
220
243
  var button = document.getElementById('shared-browser-btn');
221
244
  if (button) button.onclick = openSharedBrowser;
222
245
  var toggle = document.getElementById('shared-browser-toggle-btn');
@@ -233,7 +256,7 @@ registerRightWorkbench('browser', hideSharedBrowser);
233
256
  store.subscribe(function (state, previous) {
234
257
  if (state.currentSlug !== previous.currentSlug || state.activeSessionId !== previous.activeSessionId || state.myUserId !== previous.myUserId) {
235
258
  clearBrowserInput(); releaseRightWorkbench('browser');
236
- store.set({ sharedBrowser: null, sharedBrowsers: [], sharedBrowserOpen: false, sharedBrowserUi: {} });
259
+ store.set({ sharedBrowser: null, sharedBrowsers: [], sharedBrowserOpen: false, sharedBrowserUi: {}, sharedBrowserSettings: {} });
237
260
  if (state.connected) send('state_request');
238
261
  render();
239
262
  } else if (state.connected !== previous.connected) {
@@ -1,4 +1,5 @@
1
- import { openMateWorkspace, isMateWorkspace } from './project-mate-navigation.js';
1
+ import { contextualMate } from './contextual-mate-identity.js';
2
+ import { activateContextualMate, isMateWorkspace } from './project-mate-navigation.js';
2
3
  import { appendGithubWork } from './session-github.js';
3
4
  // sidebar-mobile.js - Mobile sheet overlays, tab bar, and mobile-specific rendering
4
5
  // Extracted from sidebar.js (PR-38)
@@ -258,7 +259,7 @@ function renderSheetSessions(listEl) {
258
259
  }
259
260
 
260
261
  var visibleChipMates = getCachedMates().filter(function (m) {
261
- return m && !m.archived;
262
+ return m && !m.archived && contextualMate(m.id);
262
263
  });
263
264
  var sortedChipMates = visibleChipMates.sort(function (a, b) {
264
265
  var aBuiltin = a.builtinKey ? 1 : 0;
@@ -327,7 +328,7 @@ function renderSheetSessions(listEl) {
327
328
  renderMobileSessionsInto(sessionListEl);
328
329
  } else if (type === "mate") {
329
330
  closeMobileSheet();
330
- openMateWorkspace(mateId);
331
+ activateContextualMate(mateId);
331
332
  }
332
333
 
333
334
  refreshIcons();
@@ -822,6 +822,7 @@ function createIconItem(p, currentSlug) {
822
822
  var el = document.createElement("a");
823
823
  var isActive = p.slug === currentSlug && !currentDmUserId;
824
824
  el.className = "icon-strip-item" + (isActive ? " active" : "");
825
+ el.dataset.controlRuntime = p.controlRuntimeId || "";
825
826
  el.href = "/p/" + p.slug + "/";
826
827
  el.dataset.slug = p.slug;
827
828
 
@@ -353,7 +353,7 @@ function renderSection(section, ctx, kind) {
353
353
  body.appendChild(empty);
354
354
  }
355
355
  var view = currentFolderState().view;
356
- var dateGroups = isFavorites ? null : groupUnitsByDate(section.units, view.sort, view.direction);
356
+ var dateGroups = isFavorites || view.showDateHeadings === false ? null : groupUnitsByDate(section.units, view.sort, view.direction);
357
357
  if (dateGroups) {
358
358
  for (var g = 0; g < dateGroups.length; g++) {
359
359
  var ids = groupRootSessionIds(dateGroups[g].units);
@@ -826,6 +826,7 @@ function renderSessionItem(s, options) {
826
826
  el.className = "session-item" + (displaySession.active ? " active" : "") + (isMatch ? " search-match" : "");
827
827
  if (itemOptions.worker) el.classList.add("session-worker-item");
828
828
  el.dataset.sessionId = s.id;
829
+ el.dataset.controlSessionOrigin = s.sessionOriginId || '';
829
830
 
830
831
  var textSpan = document.createElement("span");
831
832
  textSpan.className = "session-item-text";
@@ -0,0 +1,68 @@
1
+ import { store } from './store.js';
2
+ import { getWs } from './ws-ref.js';
3
+ import { getCachedSessions } from './sidebar-sessions.js';
4
+ import { isCurrentProjectSessionReady } from './split-session-boundary.js';
5
+ import { splitPanesMatchProject, reconcileRestoredSplit } from './project-activation.js';
6
+ import { splitGroupMemberIds } from './split-group-helpers.js';
7
+ import { splitPaneForSession } from './split-pane-reconciler.js';
8
+ import { clearProjectSplitState } from './split-session-boundary.js';
9
+
10
+ export function reconcileSplitIdentity(state, previous, host) {
11
+ var ownerChanged = (previous.authIdentityLoaded === true || state.splitIdentityHydrated) && state.myUserId !== previous.myUserId;
12
+ if (state.authIdentityLoaded && !state.splitIdentityHydrated) store.set({ splitIdentityHydrated: true });
13
+ if (state.currentSlug === previous.currentSlug && state.myUserId === previous.myUserId) return false;
14
+ Array.from(host.querySelectorAll('.split-pane-frame')).forEach(function (frame) {
15
+ if (frame.clayPane) frame.clayPane.suspend();
16
+ });
17
+ host.innerHTML = '';
18
+ if (ownerChanged) {
19
+ // This socket was authenticated as the previous owner. Fresh metadata on
20
+ // that connection cannot establish the replacement owner's pane boundary.
21
+ store.set({ splitIdentityBlockedSocket: getWs(), paneBindingSessions: [] });
22
+ clearProjectSplitState();
23
+ } else if (state.splitPanes) store.set({ splitPanes: null });
24
+ return true;
25
+ }
26
+
27
+ // The initial owner response can arrive after history and split metadata.
28
+ // Wait for it so identity cleanup cannot discard panes we just restored.
29
+ export function restoreSplitGroup(openGroup) {
30
+ var state = store.snap();
31
+ if (state.authIdentityLoaded === false || state.isMultiUserMode && !state.myUserId) return;
32
+ if (!isCurrentProjectSessionReady(state, getWs())) return;
33
+ var split = state.splitPanes;
34
+ if (split && !splitPanesMatchProject(split, state.currentSlug)) {
35
+ store.set({ splitPanes: null });
36
+ return;
37
+ }
38
+ if (state.paneMode) return;
39
+ if (split) {
40
+ var reconciliation = reconcileRestoredSplit(split, state.splitGroups);
41
+ if (reconciliation.action === "clear") {
42
+ store.set({ splitPanes: null });
43
+ return;
44
+ }
45
+ if (reconciliation.action === "rebuild") {
46
+ var rebuilt = reconciliation.group;
47
+ if (rebuilt.members.some(function (id) { return !getCachedSessions().some(function (session) { return session.id === id; }); })) {
48
+ store.set({ splitPanes: null });
49
+ return;
50
+ }
51
+ store.set({ splitPanes: {
52
+ groupId: rebuilt.id,
53
+ panes: splitGroupMemberIds(rebuilt).map(function (id) { return splitPaneForSession(id, state.currentSlug, getCachedSessions()); }),
54
+ } });
55
+ }
56
+ return;
57
+ }
58
+ var activeId = store.get('activeSessionId');
59
+ if (!activeId) return;
60
+ var groups = store.get('splitGroups') || [];
61
+ for (var i = 0; i < groups.length; i++) {
62
+ var members = groups[i].members || [];
63
+ if (members.indexOf(activeId) !== -1) {
64
+ openGroup(groups[i]);
65
+ return;
66
+ }
67
+ }
68
+ }
@@ -236,6 +236,7 @@ function sendSetPair(groupId, driverId) {
236
236
 
237
237
  export function syncPairChrome(host, split) {
238
238
  if (!host || !split || !split.groupId) return;
239
+ if (Array.from(host.querySelectorAll('.split-pane-frame')).some(function (frame) { return !!frame.dataset.requestedSessionId; })) return;
239
240
  var groups = store.get('splitGroups') || [];
240
241
  var group = null;
241
242
  for (var i = 0; i < groups.length; i++) {
@@ -2,6 +2,11 @@
2
2
  // (and their iframe browsing contexts) are reused by stable project/session
3
3
  // identity while metadata and visual order are refreshed.
4
4
 
5
+ export function splitPaneForSession(id, slug, sessions) {
6
+ var session = (sessions || []).find(function (item) { return item.id === id; });
7
+ return { slug: slug, sessionId: id, title: session && session.title || ('Session ' + id) };
8
+ }
9
+
5
10
  export function splitPaneIdentity(pane) {
6
11
  return String(pane && pane.slug || "") + "#" + String(pane && pane.sessionId || "");
7
12
  }
@@ -16,9 +21,19 @@ export function reconcileSplitPanes(host, panes, createPane, updatePane) {
16
21
  var pane = desired[pi];
17
22
  var key = splitPaneIdentity(pane);
18
23
  var paneEl = byKey.get(key);
24
+ if (!paneEl) {
25
+ for (var ci = 0; ci < existing.length; ci++) {
26
+ var candidate = existing[ci], frame = candidate.querySelector('.split-pane-frame');
27
+ if (!used.has(candidate) && frame && frame.dataset.projectSlug === pane.slug && frame.clayPane &&
28
+ !desired.some(function (item) { return splitPaneIdentity(item) === candidate.dataset.splitPaneKey; })) {
29
+ paneEl = candidate; break;
30
+ }
31
+ }
32
+ }
19
33
  if (!paneEl) paneEl = createPane(pane, pi);
20
34
  paneEl.dataset.splitPaneKey = key;
21
35
  updatePane(paneEl, pane, pi);
36
+ if (paneEl.style) paneEl.style.order = String(pi);
22
37
  used.add(paneEl);
23
38
  if (!paneEl.parentNode) host.appendChild(paneEl);
24
39
  }
@@ -6,6 +6,8 @@ import { formatTokens } from './app-panels.js';
6
6
  import { VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
7
7
  import { createPermissionControl, bindPermissionControl, renderPermissionControl } from './permission-control.js';
8
8
  import { splitGroupRoles } from './split-group-helpers.js';
9
+ import { paneTarget, livePaneBinding, samePaneTarget } from './pane-binding.js';
10
+ import { syncPairChrome } from './split-pair-ui.js';
9
11
 
10
12
  function sessionById(sessionId) {
11
13
  var sessions = getCachedSessions() || [];
@@ -17,17 +19,31 @@ function paneUrl(pane) {
17
19
  return "/p/" + encodeURIComponent(pane.slug) + "/?pane=1&session=" + encodeURIComponent(pane.sessionId);
18
20
  }
19
21
 
22
+ function headerBindingStamp(frame) {
23
+ var live = frame.clayPane && frame.clayPane.identity();
24
+ return JSON.stringify([frame.dataset.sessionId, frame.dataset.sessionOriginId,
25
+ live && live.binding && live.binding.requestId, live && live.binding && live.binding.generation]);
26
+ }
27
+
20
28
  function startPaneRename(header, titleEl, pane) {
21
29
  if (header.querySelector(".split-pane-rename-input")) return;
22
30
  var input = document.createElement("input");
23
31
  input.type = "text"; input.className = "split-pane-rename-input"; input.value = pane.title;
24
32
  titleEl.style.display = "none"; header.insertBefore(input, titleEl); input.focus(); input.select();
25
33
  var done = false;
34
+ var section = header.parentNode, frame = section.querySelector('.split-pane-frame');
35
+ var origin = frame.dataset.sessionOriginId, binding = frame.clayPane && frame.clayPane.identity().binding, socket = getWs();
36
+ function current() {
37
+ var live = frame.clayPane && frame.clayPane.identity();
38
+ return header.isConnected && !header.inert && socket === getWs() && store.get('connected') &&
39
+ frame.dataset.sessionId === String(pane.sessionId) && frame.dataset.sessionOriginId === origin && !frame.dataset.requestedSessionId &&
40
+ (!frame.clayPane || livePaneBinding(frame) && live.binding === binding);
41
+ }
26
42
  function finish(commit) {
27
43
  if (done) return;
28
44
  done = true;
29
45
  var newTitle = input.value.trim(); input.remove(); titleEl.style.display = "";
30
- if (!commit || !newTitle || newTitle === pane.title) return;
46
+ if (!commit || !current() || !newTitle || newTitle === pane.title) return;
31
47
  pane.title = newTitle; titleEl.textContent = newTitle;
32
48
  var ws = getWs();
33
49
  if (ws && ws.readyState === 1) ws.send(JSON.stringify({ type: "rename_session", id: pane.sessionId, title: newTitle }));
@@ -37,6 +53,7 @@ function startPaneRename(header, titleEl, pane) {
37
53
  if (event.key === "Escape") { event.preventDefault(); finish(false); }
38
54
  });
39
55
  input.addEventListener("blur", function () { finish(true); });
56
+ header.addEventListener('clay-pane-retarget', function cancel() { finish(false); header.removeEventListener('clay-pane-retarget', cancel); });
40
57
  input.addEventListener("click", function (event) { event.stopPropagation(); });
41
58
  }
42
59
 
@@ -73,33 +90,97 @@ export function createSplitPane(pane, closePane) {
73
90
  var vendorIcon = document.createElement("img"); vendorIcon.className = "split-pane-vendor";
74
91
  vendorIcon.src = VENDOR_AVATARS[vendor] || VENDOR_AVATARS.claude; vendorIcon.alt = ""; vendorIcon.title = VENDOR_NAMES[vendor] || vendor; header.appendChild(vendorIcon);
75
92
  var title = document.createElement("span"); title.className = "split-pane-title"; title.textContent = pane.title; title.title = "Rename session";
76
- title.addEventListener("click", function () { startPaneRename(header, title, pane); }); header.appendChild(title);
93
+ title.addEventListener("click", function () { var current = sessionById(Number(paneEl.dataset.sessionId)); if (current) startPaneRename(header, title, { sessionId: current.id, title: current.title }); }); header.appendChild(title);
77
94
  var frame = document.createElement("iframe"); frame.className = "split-pane-frame"; frame.dataset.projectSlug = pane.slug;
78
95
  frame.dataset.sessionId = String(pane.sessionId); frame.src = paneUrl(pane); frame.title = pane.title;
96
+ frame.dataset.sessionOriginId = session && session.sessionOriginId || '';
97
+ header.addEventListener('pointerdown', function () { header.dataset.pointerSessionId = frame.dataset.sessionId; header.dataset.pointerBinding = headerBindingStamp(frame); });
98
+ header.addEventListener('click', function (event) {
99
+ if (frame.clayPane && (!livePaneBinding(frame) || event.detail && header.dataset.pointerBinding !== headerBindingStamp(frame))) {
100
+ event.preventDefault(); event.stopImmediatePropagation();
101
+ }
102
+ }, true);
103
+ ['keydown', 'keyup'].forEach(function (name) {
104
+ header.addEventListener(name, function (event) {
105
+ var stamp = headerBindingStamp(frame);
106
+ if (name === 'keydown' && !event.repeat) header.dataset.keyBinding = stamp;
107
+ if (header.inert || header.dataset.keyBinding !== stamp) { event.preventDefault(); event.stopImmediatePropagation(); }
108
+ }, true);
109
+ });
79
110
  var ctxChip = document.createElement("button"); ctxChip.type = "button"; ctxChip.className = "split-pane-context"; ctxChip.title = "Context usage";
80
111
  ctxChip.innerHTML = '<span class="split-pane-context-bar"><span class="split-pane-context-fill"></span></span><span class="split-pane-context-label"></span>';
81
- ctxChip.addEventListener("click", function () { if (frame.contentWindow) frame.contentWindow.postMessage({ type: "clay-pane-toggle-context" }, window.location.origin); }); header.appendChild(ctxChip);
112
+ ctxChip.addEventListener("click", function () { if (frame.contentWindow && (!frame.clayPane || livePaneBinding(frame))) frame.contentWindow.postMessage({ type: "clay-pane-toggle-context", paneBinding: frame.clayPane && frame.clayPane.identity().binding }, window.location.origin); }); header.appendChild(ctxChip);
82
113
  var fullAccess = createPermissionControl("split-pane-full-access hidden", "Driver session permission mode");
83
- updatePaneFullAccessButton(fullAccess, session); bindPermissionControl(fullAccess, function () { return permissionState(sessionById(pane.sessionId)); }); header.appendChild(fullAccess); header.insertBefore(fullAccess, ctxChip);
114
+ updatePaneFullAccessButton(fullAccess, session); bindPermissionControl(fullAccess, function () { return permissionState(sessionById(Number(paneEl.dataset.sessionId))); }); header.appendChild(fullAccess); header.insertBefore(fullAccess, ctxChip);
84
115
  var close = document.createElement("button"); close.type = "button"; close.className = "split-pane-close"; close.title = "Close pane"; close.setAttribute("aria-label", "Close pane"); close.innerHTML = iconHtml("x");
85
116
  close.dataset.sessionId = String(pane.sessionId); close.addEventListener("click", function () { closePane(Number(this.dataset.sessionId)); }); header.appendChild(close);
117
+ frame.addEventListener('clay-pane-ready', function () {
118
+ var id = Number(frame.dataset.requestedSessionId || frame.dataset.sessionId), current = sessionById(id);
119
+ var live = frame.clayPane && frame.clayPane.identity(), target = paneTarget(store.snap(), getCachedSessions(), id);
120
+ if (!current || !live || !live.ready || !samePaneTarget(target, live.binding) || live.sessionId !== id) return;
121
+ frame.dataset.sessionId = String(id); delete frame.dataset.requestedSessionId;
122
+ frame.dataset.sessionOriginId = live.binding.sessionOriginId;
123
+ updateSplitPaneMetadata(paneEl, { slug: frame.dataset.projectSlug, sessionId: id, title: current.title });
124
+ syncPairChrome(paneEl.parentNode, store.get('splitPanes'));
125
+ });
126
+ frame.addEventListener('clay-pane-activation-failed', function () {
127
+ var id = Number(frame.dataset.requestedSessionId || frame.dataset.sessionId);
128
+ var fallbackTarget = paneTarget(store.snap(), getCachedSessions(), id);
129
+ if (!fallbackTarget) { header.inert = true; return; }
130
+ frame.dataset.sessionOriginId = fallbackTarget.sessionOriginId;
131
+ frame.src = paneUrl({ slug: frame.dataset.projectSlug, sessionId: id });
132
+ frame.dataset.sessionId = String(id); delete frame.dataset.requestedSessionId;
133
+ });
86
134
  paneEl.appendChild(header); paneEl.appendChild(frame); return paneEl;
87
135
  }
88
136
 
89
137
  export function updateSplitPaneMetadata(paneEl, pane) {
90
138
  var session = sessionById(pane.sessionId); var header = paneEl.querySelector(".split-pane-header");
91
139
  var title = paneEl.querySelector(".split-pane-title"); var frame = paneEl.querySelector(".split-pane-frame"); var vendor = paneEl.querySelector(".split-pane-vendor");
140
+ var live = frame && frame.clayPane && frame.clayPane.identity();
141
+ var retarget = frame && (Number(frame.dataset.sessionId) !== pane.sessionId || frame.dataset.sessionOriginId !== (session && session.sessionOriginId || '') || frame.clayPane && (!live || !live.ready));
142
+ if (retarget && header) {
143
+ header.dispatchEvent(new Event('clay-pane-retarget'));
144
+ header.inert = true;
145
+ header.title = 'Loading conversation';
146
+ if (title) { title.style.display = ''; title.textContent = 'Loading conversation'; }
147
+ if (vendor) vendor.hidden = true;
148
+ var permission = paneEl.querySelector('.split-pane-full-access');
149
+ if (permission) permission.classList.add('hidden');
150
+ resetPaneContextChip(paneEl);
151
+ }
152
+ if (frame && frame.clayPane && retarget) {
153
+ var target = paneTarget(store.snap(), getCachedSessions(), pane.sessionId);
154
+ if (target && frame.clayPane.source === frame.contentWindow && frame.clayPane.document === frame.contentDocument && frame.clayPane.activate(pane.sessionId, false, target)) {
155
+ frame.dataset.requestedSessionId = String(pane.sessionId);
156
+ if (header) header.inert = true;
157
+ return;
158
+ }
159
+ frame.src = paneUrl(pane);
160
+ frame.dataset.sessionId = String(pane.sessionId); frame.dataset.projectSlug = pane.slug;
161
+ frame.dataset.sessionOriginId = session && session.sessionOriginId || '';
162
+ }
163
+ if (header) header.inert = false;
92
164
  paneEl.dataset.sessionId = String(pane.sessionId); paneEl.dataset.projectSlug = pane.slug;
93
165
  if (header) header.title = pane.title; if (title && title.style.display !== "none") title.textContent = pane.title; if (frame) frame.title = pane.title;
94
- if (vendor) { var vendorName = session && session.vendor || "claude"; vendor.src = VENDOR_AVATARS[vendorName] || VENDOR_AVATARS.claude; vendor.title = VENDOR_NAMES[vendorName] || vendorName; }
166
+ if (vendor) { vendor.hidden = false; var vendorName = session && session.vendor || "claude"; vendor.src = VENDOR_AVATARS[vendorName] || VENDOR_AVATARS.claude; vendor.title = VENDOR_NAMES[vendorName] || vendorName; }
167
+ updatePaneFullAccessButton(paneEl.querySelector('.split-pane-full-access'), session);
95
168
  var close = paneEl.querySelector(".split-pane-close");
96
169
  if (close) {
97
170
  close.dataset.sessionId = String(pane.sessionId); close.disabled = false; close.title = "Close pane"; close.setAttribute("aria-label", close.title);
98
171
  }
99
172
  }
100
173
 
174
+ function resetPaneContextChip(paneEl) {
175
+ var chip = paneEl.querySelector('.split-pane-context'); if (!chip) return;
176
+ chip.classList.remove('has-data'); chip.title = 'Context usage';
177
+ var fill = chip.querySelector('.split-pane-context-fill'), label = chip.querySelector('.split-pane-context-label');
178
+ if (fill) { fill.style.width = '0%'; fill.className = 'split-pane-context-fill'; }
179
+ if (label) label.textContent = '';
180
+ }
181
+
101
182
  export function updatePaneContextChip(paneEl, msg) {
102
- if (!paneEl) return; var chip = paneEl.querySelector(".split-pane-context"); if (!chip) return; var pct = msg.pct || 0; if (pct <= 0) return;
183
+ if (!paneEl) return; var chip = paneEl.querySelector(".split-pane-context"); if (!chip) return; var pct = msg.pct || 0; if (pct <= 0) { resetPaneContextChip(paneEl); return; }
103
184
  chip.classList.add("has-data"); var fill = chip.querySelector(".split-pane-context-fill"); var label = chip.querySelector(".split-pane-context-label");
104
185
  fill.style.width = Math.min(100, pct).toFixed(1) + "%"; fill.className = "split-pane-context-fill" + (msg.cls || ""); label.textContent = pct.toFixed(0) + "%";
105
186
  var tip = "Context " + pct.toFixed(0) + "% (" + formatTokens(msg.used || 0) + " / " + formatTokens(msg.win || 0) + " tokens)";
@@ -2,7 +2,7 @@ import { store } from './store.js';
2
2
  import { isProjectSessionReady } from './project-activation.js';
3
3
 
4
4
  export function isCurrentProjectSessionReady(state, socket) {
5
- return isProjectSessionReady(state, socket);
5
+ return socket !== state.splitIdentityBlockedSocket && isProjectSessionReady(state, socket);
6
6
  }
7
7
 
8
8
  export function clearProjectSplitState() {