clay-server 5.2.0-beta.1 → 5.2.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (552) hide show
  1. package/lib/account-auth-socket.js +1 -0
  2. package/lib/builtin-mates.js +19 -16
  3. package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
  4. package/lib/canonical-clay-record-authority.js +15 -0
  5. package/lib/canonical-clay-scheduling-authority.js +19 -0
  6. package/lib/claude-hook-installer.js +1 -239
  7. package/lib/claude-jsonl-watcher.js +1 -204
  8. package/lib/clay-control-presentation-binding.js +96 -0
  9. package/lib/clay-control-presentation.js +128 -0
  10. package/lib/clay-control-target-projection.js +26 -0
  11. package/lib/clay-mate-chat-receipts.js +26 -0
  12. package/lib/clay-mate-chat.js +88 -0
  13. package/lib/clay-mate-knowledge-input.js +26 -0
  14. package/lib/clay-mate-knowledge.js +95 -0
  15. package/lib/clay-mate-lifecycle.js +95 -0
  16. package/lib/clay-product-control-input.js +33 -0
  17. package/lib/clay-product-control-tools.js +51 -0
  18. package/lib/clay-product-control.js +247 -0
  19. package/lib/clay-project-lifecycle.js +154 -0
  20. package/lib/clay-project-record-input.js +44 -0
  21. package/lib/clay-project-records.js +84 -0
  22. package/lib/clay-scheduling-input.js +21 -0
  23. package/lib/clay-scheduling-receipts.js +26 -0
  24. package/lib/clay-scheduling.js +119 -0
  25. package/lib/clay-screen-controls.js +104 -0
  26. package/lib/clay-skill-install.js +1 -33
  27. package/lib/clay-workspace-controls.js +84 -0
  28. package/lib/clay-workspace-input.js +17 -0
  29. package/lib/clay-workspace-receipts.js +26 -0
  30. package/lib/cli-sessions.js +1 -300
  31. package/lib/codex-defaults.js +1 -28
  32. package/lib/context-usage.js +3 -2
  33. package/lib/contextual-screen-snapshot.js +38 -0
  34. package/lib/daemon-project-access.js +11 -0
  35. package/lib/daemon-project-lifecycle-callbacks.js +15 -0
  36. package/lib/daemon-project-lifecycle.js +262 -0
  37. package/lib/daemon-projects.js +1 -1
  38. package/lib/daemon.js +78 -276
  39. package/lib/default-ai-runtime.js +4 -8
  40. package/lib/dm-digest-cursor.js +120 -0
  41. package/lib/email-mcp-server.js +1 -1
  42. package/lib/issues-service.js +29 -15
  43. package/lib/kiro-defaults.js +1 -22
  44. package/lib/knowledge-db-import-validation.js +46 -0
  45. package/lib/knowledge-db-import.js +99 -0
  46. package/lib/knowledge-db-service.js +24 -33
  47. package/lib/knowledge-db-storage-nedb-maintenance.js +99 -0
  48. package/lib/knowledge-db-storage-nedb.js +66 -0
  49. package/lib/knowledge-db-storage.js +72 -0
  50. package/lib/knowledge-db-validation.js +0 -0
  51. package/lib/knowledge-document-index.js +2 -1
  52. package/lib/knowledge-file-store.js +7 -1
  53. package/lib/knowledge-product-operations.js +46 -0
  54. package/lib/mate-avatar-catalog.js +12 -0
  55. package/lib/mate-avatar-migration.js +41 -0
  56. package/lib/mate-context-service.js +138 -0
  57. package/lib/mate-context-tools.js +21 -0
  58. package/lib/mate-creation-mcp-server.js +2 -0
  59. package/lib/mate-knowledge-canonical-access.js +10 -0
  60. package/lib/mate-knowledge-mate-bound.js +53 -0
  61. package/lib/mate-knowledge-mcp-server.js +55 -8
  62. package/lib/mate-knowledge-service.js +16 -34
  63. package/lib/mate-knowledge-text-tools.js +106 -0
  64. package/lib/mate-lifecycle-service.js +94 -0
  65. package/lib/mate-message-delivery.js +43 -0
  66. package/lib/mate-ready-creation.js +9 -1
  67. package/lib/mate-schedule-input.js +29 -0
  68. package/lib/mate-schedule-lifecycle.js +151 -0
  69. package/lib/mate-scheduling.js +103 -0
  70. package/lib/mates.js +18 -6
  71. package/lib/mcp-agent-tools.js +117 -0
  72. package/lib/mcp-connection-store.js +119 -15
  73. package/lib/mcp-import-credentials.js +31 -0
  74. package/lib/mcp-local-transport.js +13 -0
  75. package/lib/mcp-oauth.js +8 -6
  76. package/lib/mcp-proxy.js +2 -32
  77. package/lib/mcp-query-bridge.js +30 -0
  78. package/lib/mcp-remote-connections.js +74 -20
  79. package/lib/mcp-source-adapters.js +1 -0
  80. package/lib/mcp-source-context.js +1 -0
  81. package/lib/mcp-source-discovery.js +1 -0
  82. package/lib/mcp-source-plugins.js +1 -0
  83. package/lib/mcp-source-restrictions.js +1 -0
  84. package/lib/mcp-tool-policy.js +9 -0
  85. package/lib/notes-checklist.js +50 -0
  86. package/lib/notes.js +49 -3
  87. package/lib/os-user-diagnostics.js +2 -4
  88. package/lib/os-users.js +24 -70
  89. package/lib/pane-pending-interactions.js +20 -0
  90. package/lib/pane-session-activation.js +114 -0
  91. package/lib/pane-session-transport.js +26 -0
  92. package/lib/project-admin-overview.js +51 -0
  93. package/lib/project-ask-user.js +8 -4
  94. package/lib/project-connection.js +14 -10
  95. package/lib/project-control-git-view.js +12 -0
  96. package/lib/project-debate.js +1 -0
  97. package/lib/project-delegated-follow-up.js +2 -1
  98. package/lib/project-directory-claim.js +65 -0
  99. package/lib/project-file-operations.js +61 -0
  100. package/lib/project-filesystem.js +15 -85
  101. package/lib/project-full-access.js +23 -2
  102. package/lib/project-http.js +7 -4
  103. package/lib/project-knowledge.js +32 -18
  104. package/lib/project-lifecycle-operations.js +98 -0
  105. package/lib/project-lifecycle-process-witness.js +32 -0
  106. package/lib/project-lifecycle-runtime.js +50 -0
  107. package/lib/project-linux-access.js +22 -0
  108. package/lib/project-logs-canonical-clay.js +27 -0
  109. package/lib/project-logs-clay-query.js +16 -0
  110. package/lib/project-logs-schema.js +4 -2
  111. package/lib/project-logs-service.js +8 -7
  112. package/lib/project-logs.js +1 -0
  113. package/lib/project-loop.js +1 -0
  114. package/lib/project-mate-chat-control.js +55 -0
  115. package/lib/project-mate-creation-proposal.js +18 -3
  116. package/lib/project-mate-interaction.js +40 -62
  117. package/lib/project-mcp.js +54 -16
  118. package/lib/project-models.js +14 -31
  119. package/lib/project-notifications.js +76 -17
  120. package/lib/project-ownership.js +77 -0
  121. package/lib/project-pair-result-delivery.js +14 -3
  122. package/lib/project-pair-usage.js +12 -13
  123. package/lib/project-pending-message-queue.js +4 -1
  124. package/lib/project-product-control.js +89 -0
  125. package/lib/project-product-session-queue.js +46 -0
  126. package/lib/project-push-access.js +28 -0
  127. package/lib/project-scheduled-message-queue.js +30 -0
  128. package/lib/project-scheduled-messages.js +67 -68
  129. package/lib/project-scheduled-task-control.js +83 -0
  130. package/lib/project-scheduled-tasks.js +13 -2
  131. package/lib/project-scheduling-access.js +10 -0
  132. package/lib/project-session-actions.js +65 -0
  133. package/lib/project-session-delete.js +8 -1
  134. package/lib/project-session-document.js +27 -7
  135. package/lib/project-session-github.js +63 -19
  136. package/lib/project-session-history-actions.js +167 -0
  137. package/lib/project-session-linear.js +14 -6
  138. package/lib/project-session-notes.js +7 -3
  139. package/lib/project-session-pair.js +1 -1
  140. package/lib/project-session-runtime-actions.js +64 -0
  141. package/lib/project-session-spawn.js +2 -3
  142. package/lib/project-session-vendor.js +55 -0
  143. package/lib/project-sessions.js +103 -272
  144. package/lib/project-shared-browser.js +78 -17
  145. package/lib/project-studio-presentation.js +58 -0
  146. package/lib/project-user-message.js +67 -1
  147. package/lib/project-vendor-login.js +6 -36
  148. package/lib/project-workspace-operations.js +126 -0
  149. package/lib/project-workspace-query.js +19 -2
  150. package/lib/project.js +178 -45
  151. package/lib/public/app.js +46 -0
  152. package/lib/public/appearance-bootstrap.js +16 -0
  153. package/lib/public/css/clay-tool-activity.css +51 -0
  154. package/lib/public/css/clay-workspace.css +29 -0
  155. package/lib/public/css/command-palette.css +12 -33
  156. package/lib/public/css/contextual-clay.css +240 -0
  157. package/lib/public/css/home-debate-planning.css +2 -0
  158. package/lib/public/css/home-mate-creation.css +5 -0
  159. package/lib/public/css/input.css +6 -0
  160. package/lib/public/css/mate-avatar-gallery.css +12 -0
  161. package/lib/public/css/mate-conversation.css +10 -5
  162. package/lib/public/css/messages.css +6 -2
  163. package/lib/public/css/overlays.css +4 -2
  164. package/lib/public/css/project-admin-overview.css +13 -0
  165. package/lib/public/css/session-folders.css +11 -0
  166. package/lib/public/css/session-github.css +46 -1
  167. package/lib/public/css/shared-browser.css +35 -1
  168. package/lib/public/css/sticky-notes.css +87 -1
  169. package/lib/public/index.html +11 -5
  170. package/lib/public/mate-avatars/B01.png +0 -0
  171. package/lib/public/mate-avatars/B02.png +0 -0
  172. package/lib/public/mate-avatars/B03.png +0 -0
  173. package/lib/public/mate-avatars/B04.png +0 -0
  174. package/lib/public/mate-avatars/B05.png +0 -0
  175. package/lib/public/mate-avatars/B06.png +0 -0
  176. package/lib/public/mate-avatars/B07.png +0 -0
  177. package/lib/public/mate-avatars/B08.png +0 -0
  178. package/lib/public/mate-avatars/B09.png +0 -0
  179. package/lib/public/mate-avatars/B10.png +0 -0
  180. package/lib/public/mate-avatars/B11.png +0 -0
  181. package/lib/public/mate-avatars/B12.png +0 -0
  182. package/lib/public/mate-avatars/B13.png +0 -0
  183. package/lib/public/mate-avatars/B14.png +0 -0
  184. package/lib/public/mate-avatars/B15.png +0 -0
  185. package/lib/public/mate-avatars/B16.png +0 -0
  186. package/lib/public/mate-avatars/B17.png +0 -0
  187. package/lib/public/mate-avatars/B18.png +0 -0
  188. package/lib/public/mate-avatars/B19.png +0 -0
  189. package/lib/public/mate-avatars/B20.png +0 -0
  190. package/lib/public/mate-avatars/B21.png +0 -0
  191. package/lib/public/mate-avatars/B22.png +0 -0
  192. package/lib/public/mate-avatars/B23.png +0 -0
  193. package/lib/public/mate-avatars/B24.png +0 -0
  194. package/lib/public/mate-avatars/B25.png +0 -0
  195. package/lib/public/mate-avatars/B26.png +0 -0
  196. package/lib/public/mate-avatars/B27.png +0 -0
  197. package/lib/public/mate-avatars/B28.png +0 -0
  198. package/lib/public/mate-avatars/B29.png +0 -0
  199. package/lib/public/mate-avatars/B30.png +0 -0
  200. package/lib/public/mate-avatars/B31.png +0 -0
  201. package/lib/public/mate-avatars/B32.png +0 -0
  202. package/lib/public/mate-avatars/B33.png +0 -0
  203. package/lib/public/mate-avatars/B34.png +0 -0
  204. package/lib/public/mate-avatars/B35.png +0 -0
  205. package/lib/public/mate-avatars/B36.png +0 -0
  206. package/lib/public/mate-avatars/B37.png +0 -0
  207. package/lib/public/mate-avatars/B38.png +0 -0
  208. package/lib/public/mate-avatars/B39.png +0 -0
  209. package/lib/public/mate-avatars/B40.png +0 -0
  210. package/lib/public/mate-avatars/B41.png +0 -0
  211. package/lib/public/mate-avatars/B42.png +0 -0
  212. package/lib/public/mate-avatars/B43.png +0 -0
  213. package/lib/public/mate-avatars/B44.png +0 -0
  214. package/lib/public/mate-avatars/B45.png +0 -0
  215. package/lib/public/mate-avatars/B46.png +0 -0
  216. package/lib/public/mate-avatars/B47.png +0 -0
  217. package/lib/public/mate-avatars/B48.png +0 -0
  218. package/lib/public/mate-avatars/C01.png +0 -0
  219. package/lib/public/mate-avatars/C02.png +0 -0
  220. package/lib/public/mate-avatars/C03.png +0 -0
  221. package/lib/public/mate-avatars/C04.png +0 -0
  222. package/lib/public/mate-avatars/C05.png +0 -0
  223. package/lib/public/mate-avatars/C06.png +0 -0
  224. package/lib/public/mate-avatars/C07.png +0 -0
  225. package/lib/public/mate-avatars/C08.png +0 -0
  226. package/lib/public/mate-avatars/C09.png +0 -0
  227. package/lib/public/mate-avatars/C10.png +0 -0
  228. package/lib/public/mate-avatars/C11.png +0 -0
  229. package/lib/public/mate-avatars/C12.png +0 -0
  230. package/lib/public/mate-avatars/C13.png +0 -0
  231. package/lib/public/mate-avatars/C14.png +0 -0
  232. package/lib/public/mate-avatars/C15.png +0 -0
  233. package/lib/public/mate-avatars/C16.png +0 -0
  234. package/lib/public/mate-avatars/C17.png +0 -0
  235. package/lib/public/mate-avatars/C18.png +0 -0
  236. package/lib/public/mate-avatars/C19.png +0 -0
  237. package/lib/public/mate-avatars/C20.png +0 -0
  238. package/lib/public/mate-avatars/C21.png +0 -0
  239. package/lib/public/mate-avatars/C22.png +0 -0
  240. package/lib/public/mate-avatars/C23.png +0 -0
  241. package/lib/public/mate-avatars/C24.png +0 -0
  242. package/lib/public/mate-avatars/C25.png +0 -0
  243. package/lib/public/mate-avatars/C26.png +0 -0
  244. package/lib/public/mate-avatars/C27.png +0 -0
  245. package/lib/public/mate-avatars/C28.png +0 -0
  246. package/lib/public/mate-avatars/C29.png +0 -0
  247. package/lib/public/mate-avatars/C30.png +0 -0
  248. package/lib/public/mate-avatars/C31.png +0 -0
  249. package/lib/public/mate-avatars/C32.png +0 -0
  250. package/lib/public/mate-avatars/C33.png +0 -0
  251. package/lib/public/mate-avatars/C34.png +0 -0
  252. package/lib/public/mate-avatars/C35.png +0 -0
  253. package/lib/public/mate-avatars/C36.png +0 -0
  254. package/lib/public/mate-avatars/C37.png +0 -0
  255. package/lib/public/mate-avatars/C38.png +0 -0
  256. package/lib/public/mate-avatars/C39.png +0 -0
  257. package/lib/public/mate-avatars/C40.png +0 -0
  258. package/lib/public/mate-avatars/C41.png +0 -0
  259. package/lib/public/mate-avatars/C42.png +0 -0
  260. package/lib/public/mate-avatars/C43.png +0 -0
  261. package/lib/public/mate-avatars/C44.png +0 -0
  262. package/lib/public/mate-avatars/C45.png +0 -0
  263. package/lib/public/mate-avatars/C46.png +0 -0
  264. package/lib/public/mate-avatars/C47.png +0 -0
  265. package/lib/public/mate-avatars/C48.png +0 -0
  266. package/lib/public/mate-avatars/catalog.json +482 -0
  267. package/lib/public/mate-avatars/lead-clay.png +0 -0
  268. package/lib/public/modules/admin-settings-projects.js +6 -2
  269. package/lib/public/modules/app-connection.js +11 -1
  270. package/lib/public/modules/app-favicon.js +18 -9
  271. package/lib/public/modules/app-header.js +7 -4
  272. package/lib/public/modules/app-loop-ui.js +2 -0
  273. package/lib/public/modules/app-message-router.js +22 -1
  274. package/lib/public/modules/app-messages.js +115 -17
  275. package/lib/public/modules/app-misc.js +3 -1
  276. package/lib/public/modules/app-notifications.js +11 -5
  277. package/lib/public/modules/app-panels.js +61 -123
  278. package/lib/public/modules/app-projects.js +13 -0
  279. package/lib/public/modules/app-rate-limit.js +7 -27
  280. package/lib/public/modules/app-rendering.js +4 -3
  281. package/lib/public/modules/avatar.js +15 -41
  282. package/lib/public/modules/chat-render-runtime.js +20 -0
  283. package/lib/public/modules/clay-browser-links.js +47 -0
  284. package/lib/public/modules/clay-control-activity.js +214 -0
  285. package/lib/public/modules/clay-control-copy.js +36 -0
  286. package/lib/public/modules/clay-control-detail-targets.js +44 -0
  287. package/lib/public/modules/clay-control-object-targets.js +52 -0
  288. package/lib/public/modules/clay-control-target-visibility.js +12 -0
  289. package/lib/public/modules/clay-control-targets.js +44 -0
  290. package/lib/public/modules/clay-log-links.js +23 -0
  291. package/lib/public/modules/clay-navigation-render.js +52 -0
  292. package/lib/public/modules/clay-owner-navigation.js +33 -0
  293. package/lib/public/modules/clay-session-links.js +31 -0
  294. package/lib/public/modules/clay-studio-bridge.js +20 -0
  295. package/lib/public/modules/clay-studio-document.js +67 -0
  296. package/lib/public/modules/clay-studio-render.js +146 -0
  297. package/lib/public/modules/clay-tool-activity.js +140 -0
  298. package/lib/public/modules/clay-tool-presentation.js +342 -0
  299. package/lib/public/modules/command-palette.js +162 -40
  300. package/lib/public/modules/contextual-ask-session.js +26 -0
  301. package/lib/public/modules/contextual-clay-geometry.js +155 -0
  302. package/lib/public/modules/contextual-clay-session.js +130 -0
  303. package/lib/public/modules/contextual-clay-workspace.js +169 -0
  304. package/lib/public/modules/contextual-clay.js +250 -0
  305. package/lib/public/modules/contextual-composer.js +91 -0
  306. package/lib/public/modules/contextual-mate-context.js +117 -0
  307. package/lib/public/modules/contextual-mate-hint.js +40 -0
  308. package/lib/public/modules/contextual-mate-identity.js +23 -0
  309. package/lib/public/modules/contextual-mate-sessions.js +134 -0
  310. package/lib/public/modules/contextual-search.js +137 -0
  311. package/lib/public/modules/contextual-session-citations.js +58 -0
  312. package/lib/public/modules/debate.js +1 -0
  313. package/lib/public/modules/default-ai.js +11 -3
  314. package/lib/public/modules/elicitation-form.js +5 -0
  315. package/lib/public/modules/filebrowser.js +20 -1
  316. package/lib/public/modules/generation-stop.js +8 -5
  317. package/lib/public/modules/git-panel.js +3 -1
  318. package/lib/public/modules/history-replay-batch.js +13 -1
  319. package/lib/public/modules/home-debate-live.js +2 -0
  320. package/lib/public/modules/home-debate-planning.js +7 -7
  321. package/lib/public/modules/home-mate-avatar-editor.js +127 -208
  322. package/lib/public/modules/home-mate-chat.js +8 -6
  323. package/lib/public/modules/home-mate-creation.js +73 -1
  324. package/lib/public/modules/home-mate-settings.js +19 -12
  325. package/lib/public/modules/icon-strip-tooltip.js +2 -1
  326. package/lib/public/modules/input.js +88 -10
  327. package/lib/public/modules/issues-render.js +3 -2
  328. package/lib/public/modules/knowledge-db-workbench.js +4 -4
  329. package/lib/public/modules/markdown.js +6 -34
  330. package/lib/public/modules/mate-avatar-catalog.js +97 -0
  331. package/lib/public/modules/mate-knowledge-workbench.js +1 -1
  332. package/lib/public/modules/mate-management.js +40 -7
  333. package/lib/public/modules/mcp-connection-view.js +31 -13
  334. package/lib/public/modules/mcp-discovery-view.js +31 -0
  335. package/lib/public/modules/mcp-ui.js +23 -4
  336. package/lib/public/modules/mention.js +3 -0
  337. package/lib/public/modules/message-delivery.js +20 -2
  338. package/lib/public/modules/model-picker.js +2 -0
  339. package/lib/public/modules/pane-activation.js +214 -0
  340. package/lib/public/modules/pane-binding.js +82 -0
  341. package/lib/public/modules/pane-bridge.js +7 -4
  342. package/lib/public/modules/pane-browser-bridge.js +22 -0
  343. package/lib/public/modules/pane-file-bridge.js +4 -0
  344. package/lib/public/modules/pane-issue-bridge.js +4 -1
  345. package/lib/public/modules/pending-message-queue.js +1 -0
  346. package/lib/public/modules/permission-control.js +5 -4
  347. package/lib/public/modules/personal-settings-dialog.js +7 -1
  348. package/lib/public/modules/product-review.js +26 -0
  349. package/lib/public/modules/profile.js +1 -238
  350. package/lib/public/modules/project-access-recovery.js +17 -0
  351. package/lib/public/modules/project-admin-overview.js +21 -0
  352. package/lib/public/modules/project-chat-identity.js +13 -4
  353. package/lib/public/modules/project-logs-render.js +3 -0
  354. package/lib/public/modules/project-mate-navigation.js +144 -22
  355. package/lib/public/modules/rewind.js +5 -0
  356. package/lib/public/modules/scheduled-tasks.js +2 -0
  357. package/lib/public/modules/scheduler.js +2 -0
  358. package/lib/public/modules/search-clay-chat.js +5 -440
  359. package/lib/public/modules/session-actions.js +5 -2
  360. package/lib/public/modules/session-context-menu.js +5 -0
  361. package/lib/public/modules/session-create-form.js +10 -10
  362. package/lib/public/modules/session-folder-layout.js +1 -1
  363. package/lib/public/modules/session-folder-view-menu.js +9 -0
  364. package/lib/public/modules/session-github.js +85 -14
  365. package/lib/public/modules/session-rich-drafts.js +21 -0
  366. package/lib/public/modules/session-switch-defer.js +67 -0
  367. package/lib/public/modules/session-work-primary.js +51 -0
  368. package/lib/public/modules/settings-defaults.js +27 -28
  369. package/lib/public/modules/shared-browser-settings.js +112 -0
  370. package/lib/public/modules/shared-browser-tabs.js +13 -3
  371. package/lib/public/modules/shared-browser.js +29 -6
  372. package/lib/public/modules/sidebar-mobile.js +4 -3
  373. package/lib/public/modules/sidebar-projects.js +1 -0
  374. package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
  375. package/lib/public/modules/sidebar-sessions.js +1 -0
  376. package/lib/public/modules/split-group-restore.js +68 -0
  377. package/lib/public/modules/split-pair-ui.js +1 -0
  378. package/lib/public/modules/split-pane-reconciler.js +15 -0
  379. package/lib/public/modules/split-pane-renderer.js +87 -6
  380. package/lib/public/modules/split-session-boundary.js +1 -1
  381. package/lib/public/modules/split-view.js +60 -68
  382. package/lib/public/modules/sticky-note-markdown.js +72 -6
  383. package/lib/public/modules/sticky-notes-actions.js +30 -0
  384. package/lib/public/modules/sticky-notes-browser.js +9 -2
  385. package/lib/public/modules/sticky-notes-card.js +23 -7
  386. package/lib/public/modules/sticky-notes-checklist.js +116 -0
  387. package/lib/public/modules/sticky-notes-editor.js +108 -44
  388. package/lib/public/modules/sticky-notes-shared.js +50 -2
  389. package/lib/public/modules/sticky-notes-state.js +66 -0
  390. package/lib/public/modules/sticky-notes.js +34 -51
  391. package/lib/public/modules/stt-controller.js +4 -1
  392. package/lib/public/modules/stt-recording.js +1 -1
  393. package/lib/public/modules/stt.js +7 -2
  394. package/lib/public/modules/terminal.js +9 -0
  395. package/lib/public/modules/theme.js +8 -1
  396. package/lib/public/modules/thinking-lifecycle.js +33 -3
  397. package/lib/public/modules/thinking-view.js +23 -1
  398. package/lib/public/modules/tools.js +60 -11
  399. package/lib/public/modules/tui-grab.js +1 -2
  400. package/lib/public/modules/user-settings-appearance.js +10 -3
  401. package/lib/public/modules/user-settings-editors.js +1 -1
  402. package/lib/public/modules/user-settings-layout.js +11 -2
  403. package/lib/public/modules/user-settings-preferences.js +6 -2
  404. package/lib/public/modules/user-settings-profile.js +12 -2
  405. package/lib/public/modules/user-settings.js +3 -2
  406. package/lib/public/modules/vendor-login-browser.js +5 -3
  407. package/lib/public/modules/vendor-login.js +2 -2
  408. package/lib/public/modules/vendor-priority.js +15 -1
  409. package/lib/public/modules/wireframe-workbench.js +5 -2
  410. package/lib/public/muse-avatar.svg +4 -0
  411. package/lib/public/style.css +5 -0
  412. package/lib/public/sw.js +3 -1
  413. package/lib/safe-bash-commands.js +3 -45
  414. package/lib/scheduled-task-records.js +3 -1
  415. package/lib/scheduler.js +2 -0
  416. package/lib/sdk-bridge.js +342 -401
  417. package/lib/sdk-foreground-admission.js +16 -0
  418. package/lib/sdk-mcp-descriptors.js +2 -37
  419. package/lib/sdk-message-processor.js +52 -17
  420. package/lib/sdk-quota-snapshot.js +1 -1
  421. package/lib/sdk-response-recovery.js +1 -0
  422. package/lib/sdk-worker.js +2 -677
  423. package/lib/server-admin.js +63 -16
  424. package/lib/server-appearance-settings.js +13 -1
  425. package/lib/server-contextual-clay-settings.js +40 -0
  426. package/lib/server-contextual-mate-sessions.js +70 -0
  427. package/lib/server-dm.js +2 -1
  428. package/lib/server-global-ws.js +10 -20
  429. package/lib/server-home-chat-events.js +18 -4
  430. package/lib/server-home-chat.js +22 -20
  431. package/lib/server-home-clay-entry.js +23 -4
  432. package/lib/server-home-clay-session-links.js +29 -9
  433. package/lib/server-home-mate-creation.js +1 -0
  434. package/lib/server-home-mcp-consent.js +14 -0
  435. package/lib/server-mates.js +25 -62
  436. package/lib/server-owner-ui.js +118 -0
  437. package/lib/server-path-access.js +38 -0
  438. package/lib/server-project-removal.js +22 -0
  439. package/lib/server-settings.js +6 -1
  440. package/lib/server.js +163 -43
  441. package/lib/session-config-transition.js +45 -0
  442. package/lib/session-folders.js +7 -2
  443. package/lib/session-fork-history.js +21 -0
  444. package/lib/session-github.js +9 -2
  445. package/lib/session-hygiene.js +3 -35
  446. package/lib/session-permission-mode.js +4 -3
  447. package/lib/session-skill-scope.js +11 -0
  448. package/lib/session-visibility.js +5 -2
  449. package/lib/session-work-primary.js +50 -0
  450. package/lib/sessions.js +64 -99
  451. package/lib/shared-browser-cookie-sync.js +32 -0
  452. package/lib/shared-browser-cookies.js +79 -0
  453. package/lib/shared-browser-runtime.js +25 -9
  454. package/lib/shared-browser-storage-sync.js +43 -0
  455. package/lib/shared-browser-storage.js +101 -0
  456. package/lib/shared-browser-tools.js +2 -1
  457. package/lib/shared-browser-worker.js +46 -10
  458. package/lib/terminal-manager.js +65 -6
  459. package/lib/tool-llm.js +1 -1
  460. package/lib/tui-transcript-index.js +1 -132
  461. package/lib/users-contextual-clay-preferences.js +31 -0
  462. package/lib/users-permissions.js +2 -8
  463. package/lib/users.js +7 -0
  464. package/lib/vendor-login-browser.js +1 -11
  465. package/lib/workspace-assignment-service.js +25 -0
  466. package/lib/workspace-query-access.js +4 -1
  467. package/lib/workspace-query-mcp-server.js +1 -1
  468. package/lib/workspace-query-service.js +13 -2
  469. package/lib/ws-request.js +1 -0
  470. package/lib/ws-schema.js +18 -2
  471. package/lib/yoke/acp-agent-profiles.js +7 -5
  472. package/lib/yoke/adapters/antigravity.js +3 -14
  473. package/lib/yoke/adapters/claude-query-contract.js +9 -0
  474. package/lib/yoke/adapters/claude.js +54 -50
  475. package/lib/yoke/adapters/codex-query-contract.js +24 -0
  476. package/lib/yoke/adapters/codex.js +53 -111
  477. package/lib/yoke/adapters/kiro.js +3 -1
  478. package/lib/yoke/adapters/muse-query-contract.js +7 -0
  479. package/lib/yoke/adapters/muse.js +122 -0
  480. package/lib/yoke/auth-events.js +17 -0
  481. package/lib/yoke/claude-hook-installer.js +271 -0
  482. package/lib/yoke/claude-jsonl-watcher.js +204 -0
  483. package/lib/yoke/claude-maintenance.js +55 -0
  484. package/lib/yoke/claude-permission-patterns.js +53 -0
  485. package/lib/yoke/claude-response-recovery.js +155 -0
  486. package/lib/yoke/claude-transcript-hygiene.js +34 -0
  487. package/lib/yoke/claude-worker-startup.js +28 -0
  488. package/lib/yoke/clay-skill-install.js +33 -0
  489. package/lib/yoke/cli-sessions.js +300 -0
  490. package/lib/yoke/codex-app-server.js +7 -12
  491. package/lib/yoke/codex-idle-recovery.js +81 -1
  492. package/lib/yoke/codex-recovery-admission.js +164 -0
  493. package/lib/yoke/configuration.js +13 -0
  494. package/lib/yoke/discovery.js +70 -0
  495. package/lib/yoke/errors.js +8 -0
  496. package/lib/yoke/host-environment.js +7 -0
  497. package/lib/yoke/index.js +9 -51
  498. package/lib/yoke/interface.js +116 -0
  499. package/lib/yoke/kiro-acp-server.js +5 -5
  500. package/lib/yoke/legacy-sessions.js +89 -0
  501. package/lib/yoke/login-protocol.js +25 -0
  502. package/lib/yoke/maintenance.js +12 -0
  503. package/lib/yoke/mcp-proxy.js +32 -0
  504. package/lib/yoke/mcp-source-adapters.js +91 -0
  505. package/lib/yoke/mcp-source-context.js +42 -0
  506. package/lib/yoke/mcp-source-discovery.js +169 -0
  507. package/lib/yoke/mcp-source-plugins.js +68 -0
  508. package/lib/yoke/mcp-source-restrictions.js +47 -0
  509. package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
  510. package/lib/yoke/model-preferences.js +6 -0
  511. package/lib/yoke/muse-artifacts.js +36 -0
  512. package/lib/yoke/muse-controls.js +50 -0
  513. package/lib/yoke/muse-input.js +64 -0
  514. package/lib/yoke/muse-items.js +157 -0
  515. package/lib/yoke/muse-policy.js +52 -0
  516. package/lib/yoke/muse-query.js +428 -0
  517. package/lib/yoke/muse-runtime.js +211 -0
  518. package/lib/yoke/muse-services.js +79 -0
  519. package/lib/yoke/muse-skills.js +79 -0
  520. package/lib/yoke/muse-turns.js +71 -0
  521. package/lib/yoke/options/acp.js +2 -0
  522. package/lib/yoke/options/antigravity.js +2 -0
  523. package/lib/yoke/options/claude.js +21 -0
  524. package/lib/yoke/options/codex-defaults.js +29 -0
  525. package/lib/yoke/options/codex-settings.js +21 -0
  526. package/lib/yoke/options/codex.js +6 -0
  527. package/lib/yoke/options/kiro-defaults.js +22 -0
  528. package/lib/yoke/options/kiro.js +5 -0
  529. package/lib/yoke/options/muse.js +5 -0
  530. package/lib/yoke/provider-contract.js +5 -0
  531. package/lib/yoke/providers/antigravity-executable.js +8 -0
  532. package/lib/yoke/providers/claude-executable.js +40 -0
  533. package/lib/yoke/providers/claude-model-descriptions.js +14 -0
  534. package/lib/yoke/providers/claude-process.js +97 -0
  535. package/lib/yoke/providers/claude-provision.js +75 -0
  536. package/lib/yoke/providers/codex-errors.js +8 -0
  537. package/lib/yoke/providers/muse-executable.js +17 -0
  538. package/lib/yoke/provisioning.js +6 -0
  539. package/lib/yoke/query-options.js +10 -0
  540. package/lib/yoke/response-recovery.js +41 -0
  541. package/lib/yoke/sdk-mcp-descriptors.js +37 -0
  542. package/lib/yoke/sdk-server-factory.js +7 -0
  543. package/lib/yoke/session-history.js +8 -0
  544. package/lib/yoke/session-tool-transport.js +34 -13
  545. package/lib/yoke/settings.js +23 -0
  546. package/lib/yoke/source-locations.js +4 -0
  547. package/lib/yoke/title-query.js +18 -7
  548. package/lib/yoke/tui-transcript-index.js +132 -0
  549. package/lib/yoke/usage.js +48 -0
  550. package/lib/yoke/user-input.js +13 -0
  551. package/lib/yoke/vendor-registry.js +81 -1
  552. package/package.json +10 -4
@@ -3,6 +3,7 @@ import { getWs } from './ws-ref.js';
3
3
  import { githubLinkTarget } from './github-links.js';
4
4
  import { iconHtml, refreshIcons } from './icons.js';
5
5
  import { escapeHtml as escapeText } from './utils.js';
6
+ import { primaryWorkPopover, handlePrimaryWorkClick } from './session-work-primary.js';
6
7
 
7
8
  function escapeHtml(value) {
8
9
  return escapeText(String(value)).replace(/"/g, '"').replace(/'/g, ''');
@@ -34,13 +35,38 @@ export function orderedGithubWork(session) {
34
35
  var links = safeLinks(session).slice().reverse();
35
36
  var latestIssue = links.find(function (link) { return link.kind === 'issue' || link.provider === 'linear'; });
36
37
  if (latestIssue) links = [latestIssue].concat(links.filter(function (link) { return link !== latestIssue; }));
37
- return links;
38
+ var primary = session && session.workPrimary || {};
39
+ return links.filter(function (link) { return String(primary[link.provider === 'linear' ? 'linear' : link.kind] || '').toLowerCase() === link.url.toLowerCase(); }).concat(
40
+ links.filter(function (link) { return String(primary[link.provider === 'linear' ? 'linear' : link.kind] || '').toLowerCase() !== link.url.toLowerCase(); }));
38
41
  }
39
42
  function compactGithubWork(links, sessionRow) {
40
43
  if (!sessionRow && !links.some(function (link) { return link.provider === 'linear'; })) return links.slice(0, 1);
41
- var latestIssue = links.find(function (link) { return link.kind === 'issue' || link.provider === 'linear'; });
44
+ var latestLinear = links.find(function (link) { return link.provider === 'linear'; });
45
+ var latestIssue = links.find(function (link) { return link.kind === 'issue' && link.provider !== 'linear'; });
42
46
  var latestPr = links.find(function (link) { return link.kind === 'pr'; });
43
- return [latestIssue, latestPr].filter(Boolean);
47
+ return [latestLinear, latestIssue, latestPr].filter(Boolean);
48
+ }
49
+ function personalScope() {
50
+ return String(store.get('currentSlug') || '') + '\u0000' + String(store.get('myUserId') || 'default');
51
+ }
52
+ function ensurePersonalScope() {
53
+ var scope = personalScope();
54
+ if (store.get('githubPersonalReviewScope') !== scope) store.set({ githubPersonalReviewScope: scope, githubPersonalReview: {} });
55
+ return scope;
56
+ }
57
+ function sessionIdentifier(session) {
58
+ return String(session && (session._githubSessionId || session.id || session.localId) || '');
59
+ }
60
+ function personalReviewState(session, link) {
61
+ var scope = ensurePersonalScope();
62
+ var key = scope + '\u0000' + (sessionIdentifier(session) || String(link._githubSessionId || '')) + '\u0000' + String(link.url || '').toLowerCase();
63
+ return (store.get('githubPersonalReview') || {})[key] || link.personalReviewState || '';
64
+ }
65
+ function prReviewStatus(link) {
66
+ if (link.review === 'CHANGES_REQUESTED') return { icon: 'message-square-warning', label: 'Changes requested', className: 'github-review-changes' };
67
+ if (link.personalReviewState === 'requested') return { icon: 'user-round-check', label: 'Review requested from you', className: 'github-review-requested' };
68
+ if (link.review === 'APPROVED') return { icon: 'badge-check', label: 'Approved', className: 'github-review-approved' };
69
+ return null;
44
70
  }
45
71
  export function githubWorkMarkup(session, detailed, expanded, sessionRow) {
46
72
  var links = orderedGithubWork(session);
@@ -52,19 +78,51 @@ export function githubWorkMarkup(session, detailed, expanded, sessionRow) {
52
78
  return anchor(link.url, description, LINEAR_MARK + '<span class="linear-work-id">' + escapeHtml(link.identifier) + '</span><span class="linear-work-title">' + escapeHtml(link.title) + '</span><span class="linear-work-state"><span class="linear-work-state-full">' + escapeHtml(link.stateName) + '</span><span class="linear-work-state-compact" aria-hidden="true">' + escapeHtml(compactLinearState(link.stateName)) + '</span></span>', 'session-github-link session-linear-link');
53
79
  }
54
80
  var state = ['open', 'closed', 'merged', 'draft'].indexOf(link.state) >= 0 ? link.state : 'unknown';
55
- var icon = link.kind === 'pr' ? (state === 'merged' ? 'git-merge' : state === 'closed' ? 'git-pull-request-closed' : state === 'draft' ? 'git-pull-request-draft' : 'git-pull-request') : (state === 'closed' ? 'circle-check' : 'circle-dot');
56
- var description = link.repository + ' · ' + label(link) + ' · ' + link.title + ' · ' + state + (link.checkedAt ? ' · Checked ' + new Date(link.checkedAt).toLocaleString() : '') + (link.stale ? ' (last known status; refresh unavailable)' : '');
57
- var html = anchor(link.url, description, iconHtml('github', 'github-work-brand') + iconHtml(icon, 'github-work-status') + '<span><span class="github-work-kind">' + (link.kind === 'pr' ? 'PR ' : 'Issue ') + '</span>#' + escapeHtml(String(link.number)) + '</span>', 'session-github-link github-kind-' + (link.kind === 'pr' ? 'pr' : 'issue') + ' github-state-' + state);
81
+ var reviewLink = Object.assign({}, link, { personalReviewState: personalReviewState(session, link) });
82
+ var reviewStatus = link.kind === 'pr' && state === 'open' ? prReviewStatus(reviewLink) : null;
83
+ var icon = link.kind === 'pr' ? (state === 'merged' ? 'git-merge' : state === 'closed' ? 'git-pull-request-closed' : state === 'draft' ? 'git-pull-request-draft' : reviewStatus ? reviewStatus.icon : 'git-pull-request') : (state === 'closed' ? 'circle-check' : 'circle-dot');
84
+ var statusLabel = reviewStatus ? reviewStatus.label : (state === 'merged' ? 'Merged' : state === 'closed' ? 'Closed' : state === 'draft' ? 'Draft' : state === 'open' ? 'Open' : 'Unknown');
85
+ var description = link.repository + ' · ' + label(link) + ' · ' + link.title + ' · ' + statusLabel + (link.checkedAt ? ' · Checked ' + new Date(link.checkedAt).toLocaleString() : '') + (link.stale ? ' (last known status; refresh unavailable)' : '');
86
+ var statusMarkup = '<span class="github-work-status' + (reviewStatus ? ' ' + reviewStatus.className : '') + '" title="' + escapeHtml(statusLabel) + '" aria-label="' + escapeHtml(statusLabel) + '">' + iconHtml(icon) + '</span>';
87
+ var html = anchor(link.url, description, iconHtml('github', 'github-work-brand') + statusMarkup + '<span><span class="github-work-kind">' + (link.kind === 'pr' ? 'PR ' : 'Issue ') + '</span>#' + escapeHtml(String(link.number)) + '</span>', 'session-github-link github-kind-' + (link.kind === 'pr' ? 'pr' : 'issue') + ' github-state-' + state);
58
88
  if (expanded) html = '<span class="github-work-entry">' + html + '<span class="github-work-entry-title">' + escapeHtml(link.title || '') + '</span><span class="github-work-entry-meta">' + escapeHtml(link.repository + ' · ' + state + (link.stale ? ' · Last known status' : '')) + '</span></span>';
59
89
  if (detailed && link.kind === 'pr') {
60
- html += anchor(link.url + '/files', 'View PR changes on GitHub', 'Changes', 'github-work-action');
61
- html += anchor(link.url + '#pullrequestreview', 'View PR reviews on GitHub', escapeHtml((link.review || 'Reviews').replace(/_/g, ' ').toLowerCase()), 'github-work-action');
90
+ var actions = anchor(link.url + '/files', 'View PR changes on GitHub', 'Changes', 'github-work-action') +
91
+ anchor(link.url + '#pullrequestreview', 'View PR reviews on GitHub', 'Reviews', 'github-work-action');
92
+ var checks = '';
62
93
  (link.checks || []).forEach(function (check) {
63
- if (/^https:\/\//i.test(check.url)) html += anchor(check.url, check.name + ': ' + check.state, escapeHtml(check.name + ' · ' + check.state.toLowerCase()), 'github-work-action');
94
+ if (/^https:\/\//i.test(check.url)) checks += anchor(check.url, check.name + ': ' + check.state, '<span class="github-work-check-name">' + escapeHtml(check.name) + '</span><span class="github-work-check-state">' + escapeHtml(check.state.toLowerCase()) + '</span>', 'github-work-action github-work-check');
64
95
  });
96
+ return '<span class="github-work-pr-group" data-github-pr="' + escapeHtml(String(link.number)) + '">' +
97
+ '<span class="github-work-pr-header">' + html + '</span>' +
98
+ '<span class="github-work-pr-actions">' + actions + '</span>' +
99
+ (checks ? '<span class="github-work-pr-checks">' + checks + '</span>' : '') +
100
+ '</span>';
65
101
  }
66
102
  return html;
67
- }).join('') + (!detailed && !expanded && links.length > displayed.length ? '<button type="button" class="github-work-more" aria-label="Show all ' + links.length + ' linked ' + (links.some(function (item) { return item.provider === 'linear'; }) ? 'work items' : 'GitHub items') + '" aria-haspopup="dialog" aria-expanded="false" data-github-links="' + escapeHtml(JSON.stringify(safeLinks(session))) + '">+' + (links.length - displayed.length) + '</button>' : '') + '</span>';
103
+ }).join('') + (!detailed && !expanded && links.length > displayed.length ? '<button type="button" class="github-work-more" aria-label="Show all ' + links.length + ' linked ' + (links.some(function (item) { return item.provider === 'linear'; }) ? 'work items' : 'GitHub items') + '" aria-haspopup="dialog" aria-expanded="false" data-work-session="' + escapeHtml(String(session.id || session.localId || '')) + '" data-work-primary="' + escapeHtml(JSON.stringify(session.workPrimary || {})) + '" data-github-links="' + escapeHtml(JSON.stringify(safeLinks(session))) + '">+' + (links.length - displayed.length) + '</button>' : '') + '</span>';
104
+ }
105
+ export function applyGithubPersonalReviewStatus(message) {
106
+ var state = store.snap();
107
+ if (!message || (message.projectSlug && message.projectSlug !== state.currentSlug) || (message.accountId && message.accountId !== state.myUserId)) return;
108
+ var refresh = state.githubWorkRefresh || {};
109
+ if (message.requestId && refresh.requestId && message.requestId !== refresh.requestId) return;
110
+ var updates = message.personalReview || {};
111
+ var scope = ensurePersonalScope();
112
+ var personal = Object.assign({}, store.get('githubPersonalReview') || {});
113
+ var sessionId = String(message.sessionId);
114
+ Object.keys(updates).forEach(function (url) {
115
+ var status = updates[url];
116
+ if (status === 'requested' || status === 'clear') personal[scope + '\u0000' + sessionId + '\u0000' + url.toLowerCase()] = status;
117
+ });
118
+ store.set({ githubPersonalReview: personal });
119
+ var sessions = store.get('githubWorkSessions') || [];
120
+ sessions.forEach(function (session) {
121
+ if (String(session.localId) !== sessionId && String(session.id) !== sessionId) return;
122
+ document.querySelectorAll('[data-github-session-id="' + sessionIdentifier(session) + '"] .session-work-links-slot').forEach(function (slot) { slot.innerHTML = githubWorkMarkup(session, false, false, true); });
123
+ });
124
+ syncGithubSessions(sessions);
125
+ refreshIcons();
68
126
  }
69
127
  export function appendGithubWork(row, session, title) {
70
128
  var html = githubWorkMarkup(session, false, false, true);
@@ -84,6 +142,7 @@ export function appendGithubWork(row, session, title) {
84
142
  }
85
143
  export function syncGithubSessions(sessions) {
86
144
  bindGithubWorkPopover();
145
+ ensurePersonalScope();
87
146
  store.set({ githubWorkSessions: sessions || [], githubWorkProject: store.get('currentSlug') });
88
147
  var active = (sessions || []).find(function (session) { return session.active; });
89
148
  var title = document.getElementById('header-title');
@@ -122,15 +181,16 @@ export function refreshGithubWork() {
122
181
  if (previous.key === key && Date.now() - previous.at < 60000) return;
123
182
  var ws = getWs();
124
183
  if (!ws || ws.readyState !== 1) return;
125
- store.set({ githubWorkRefresh: { key: key, at: Date.now() } });
126
- ws.send(JSON.stringify({ type: 'session_github_refresh', sessionIds: ids }));
184
+ var requestId = 'github-refresh-' + Date.now() + '-' + Math.random().toString(36).slice(2);
185
+ store.set({ githubWorkRefresh: { key: key, at: Date.now(), requestId: requestId } });
186
+ ws.send(JSON.stringify({ type: 'session_github_refresh', sessionIds: ids, requestId: requestId, projectSlug: store.get('currentSlug'), accountId: store.get('myUserId') || null }));
127
187
  var linearIds = ids.filter(function (id) { return (store.get('githubWorkSessions') || []).some(function (item) { return item.id === id && (item.linearLinks || []).length; }); });
128
188
  if (linearIds.length) ws.send(JSON.stringify({ type: 'session_linear_refresh', sessionIds: linearIds }));
129
189
  }
130
190
 
131
191
  export function resetGithubWork() {
132
192
  closeGithubWorkPopover();
133
- store.set({ githubWorkSessions: [], githubWorkProject: null, githubWorkRefresh: null });
193
+ store.set({ githubWorkSessions: [], githubWorkProject: null, githubWorkRefresh: null, githubPersonalReview: {}, workPrimaryPending: null });
134
194
  var header = document.getElementById('header-github-links');
135
195
  if (header) header.remove();
136
196
  }
@@ -184,6 +244,7 @@ function bindGithubWorkPopover() {
184
244
  if (store.get('githubWorkPopoverBound')) return;
185
245
  store.set({ githubWorkPopoverBound: true });
186
246
  document.addEventListener('click', function (event) {
247
+ if (handlePrimaryWorkClick(event)) return;
187
248
  var linear = event.target.closest('.session-linear-link');
188
249
  if (linear && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey) { event.preventDefault(); event.stopPropagation(); closeGithubWorkPopover(); import('./linear-panel.js').then(function (module) { module.openLinear(linear.href); }); return; }
189
250
  var button = event.target.closest('.github-work-more');
@@ -204,7 +265,11 @@ function bindGithubWorkPopover() {
204
265
  popup.setAttribute('role', 'dialog');
205
266
  var workTitle = links.some(function (link) { return link.provider === 'linear'; }) ? 'Linked work' : 'Linked GitHub work';
206
267
  popup.setAttribute('aria-label', workTitle);
207
- popup.innerHTML = '<strong>' + workTitle + '</strong>' + githubWorkMarkup({ githubLinks: links }, false, true);
268
+ popup.dataset.sessionId = button.dataset.workSession || '';
269
+ var primary;
270
+ try { primary = JSON.parse(button.dataset.workPrimary || '{}'); } catch (error) { primary = {}; }
271
+ var popupLinks = links.map(function (link) { return Object.assign({}, link, { _githubSessionId: popup.dataset.sessionId }); });
272
+ popup.innerHTML = '<strong>' + workTitle + '</strong>' + primaryWorkPopover(popupLinks, primary, popup.dataset.sessionId, githubWorkMarkup);
208
273
  document.body.appendChild(popup);
209
274
  mountGithubWorkPopover(popup, button);
210
275
  button.setAttribute('aria-expanded', 'true');
@@ -224,3 +289,9 @@ function bindGithubWorkPopover() {
224
289
  if (state.currentSlug !== previous.currentSlug || state.activeSessionId !== previous.activeSessionId || state.dmMode !== previous.dmMode) closeGithubWorkPopover();
225
290
  });
226
291
  }
292
+ store.subscribe(function (state, previous) {
293
+ if (state.currentSlug !== previous.currentSlug || state.myUserId !== previous.myUserId) {
294
+ var scope = personalScope();
295
+ if (state.githubPersonalReviewScope !== scope) store.set({ githubPersonalReviewScope: scope, githubPersonalReview: {} });
296
+ }
297
+ });
@@ -0,0 +1,21 @@
1
+ import { store } from './store.js';
2
+ import { takeComposerDraft, restoreComposerDraft } from './input.js';
3
+
4
+ function key() { return [store.get('myUserId') || '', store.get('currentSlug') || '', store.get('sessionOriginId') || ''].join(':'); }
5
+ export function checkComposerDeparture() {
6
+ var draft = takeComposerDraft();
7
+ restoreComposerDraft(draft);
8
+ }
9
+ export function saveSessionRichDraft() {
10
+ if (store.get('activeProjectMateId') || !store.get('sessionOriginId') || store.get('panePendingBinding')) return;
11
+ var drafts = Object.assign({}, store.get('sessionRichDrafts') || {});
12
+ var draft = takeComposerDraft();
13
+ drafts[key()] = draft;
14
+ restoreComposerDraft(draft);
15
+ store.set({ sessionRichDrafts: drafts });
16
+ }
17
+ export function restoreSessionRichDraft() {
18
+ if (store.get('activeProjectMateId') || store.get('panePendingBinding')) return;
19
+ var draft = (store.get('sessionRichDrafts') || {})[key()];
20
+ restoreComposerDraft(draft || { text: (store.get('sessionDrafts') || {})[store.get('activeSessionId')] || '', start: 0, end: 0 });
21
+ }
@@ -0,0 +1,67 @@
1
+ import { store } from './store.js';
2
+ import { getWs } from './ws-ref.js';
3
+ import { composerDepartureReason } from './input.js';
4
+ import { processMessage } from './app-message-router.js';
5
+
6
+ function notice(show, message) {
7
+ var element = document.getElementById('session-switch-wait');
8
+ if (!show) { if (element) element.remove(); return; }
9
+ if (element) { if (message) element.textContent = message; return; }
10
+ var area = document.getElementById('input-area');
11
+ if (!area) return;
12
+ element = document.createElement('div'); element.id = 'session-switch-wait';
13
+ element.className = 'session-switch-wait'; element.setAttribute('role', 'status');
14
+ element.textContent = 'Session change waiting. Finish or discard voice input, or wait for attachments. Your draft stays with this conversation.';
15
+ area.prepend(element);
16
+ }
17
+
18
+ // Keep the source composer and its async completions together. The destination
19
+ // replay waits in order; it cannot change identity midway through an upload.
20
+ export function deferSessionSwitch(message) {
21
+ var pending = store.get('deferredSessionSwitch');
22
+ if (pending && pending.draining) return false;
23
+ if (['account_auth_required', 'project_removed', 'project_access_revoked'].indexOf(message.type) >= 0) {
24
+ store.set({ deferredSessionSwitch: null }); notice(false); return false;
25
+ }
26
+ if (!pending && message.type === 'session_switched' && composerDepartureReason()) {
27
+ pending = { socket: getWs(), projectSlug: store.get('currentSlug'), ownerId: store.get('myUserId'),
28
+ sessionId: store.get('activeSessionId'), origin: store.get('sessionOriginId'), processing: store.get('processing'), messages: [] };
29
+ var speech = store.get('speechActive');
30
+ if (speech) speech.autoSend = false;
31
+ store.set({ deferredSessionSwitch: pending }); notice(true);
32
+ }
33
+ if (!pending) return false;
34
+ if (pending.projectSlug === store.get('currentSlug') && pending.ownerId === store.get('myUserId')) pending.socket = getWs();
35
+ if (store.get('connected') && pending.processing && !store.get('processing')) store.set({ processing: true });
36
+ pending.messages.push(message);
37
+ if (message.type === 'session_list' || message.type === 'session_switched') queueMicrotask(drain);
38
+ return true;
39
+ }
40
+
41
+ function drain() {
42
+ var pending = store.get('deferredSessionSwitch');
43
+ if (!pending || pending.draining || composerDepartureReason() || !store.get('connected')) return;
44
+ if (pending.socket !== getWs() || pending.projectSlug !== store.get('currentSlug') || pending.ownerId !== store.get('myUserId')) return;
45
+ var latestSwitch, latestList;
46
+ pending.messages.forEach(function (message) {
47
+ if (message.type === 'session_switched') latestSwitch = message;
48
+ if (message.type === 'session_list') latestList = message;
49
+ });
50
+ if (!latestSwitch || !latestList) return;
51
+ var target = (latestList.sessions || []).find(function (session) { return session.id === latestSwitch.id; });
52
+ if (!target || target.sessionOriginId !== latestSwitch.sessionOriginId) {
53
+ notice(true, 'The conversation changed while your draft was waiting. Your draft is preserved. Choose a conversation to continue.');
54
+ return;
55
+ }
56
+ // Restoring superseded snapshots must not trigger outbound session effects
57
+ // before the final authoritative target is installed.
58
+ pending.draining = true;
59
+ pending.finalSwitch = latestSwitch;
60
+ pending.messages.forEach(processMessage);
61
+ store.set({ deferredSessionSwitch: null }); notice(false);
62
+ }
63
+
64
+ store.subscribe(function (state, previous) {
65
+ if (state.deferredSessionSwitch && (state.composerUploadingCount !== previous.composerUploadingCount ||
66
+ state.speechActive !== previous.speechActive || state.speechRetry !== previous.speechRetry || state.connected !== previous.connected)) queueMicrotask(drain);
67
+ });
@@ -0,0 +1,51 @@
1
+ import { store } from './store.js';
2
+ import { getWs } from './ws-ref.js';
3
+ import { escapeHtml } from './utils.js';
4
+ var PRIMARY_PIN = '<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path class="work-primary-pin-head" d="M16 9V4l1-1V2H7v1l1 1v5l-2 3v2h12v-2z"/><path d="M12 14v8"/></svg>';
5
+ function attr(value) { return escapeHtml(String(value)).replace(/"/g, '&quot;').replace(/'/g, '&#39;'); }
6
+ export function primaryWorkPopover(links, primary, sessionId, render) {
7
+ var html = ['linear', 'pr', 'issue'].map(function (type) {
8
+ var items = links.filter(function (link) { return (link.provider === 'linear' ? 'linear' : link.kind) === type; }).reverse();
9
+ if (!items.length) return '';
10
+ return '<section class="work-primary-group"><h3>' + ({ linear: 'Linear issues', pr: 'Pull requests', issue: 'GitHub issues' })[type] + '</h3>' + items.map(function (link) {
11
+ var selected = String(primary[type] || '').toLowerCase() === link.url.toLowerCase();
12
+ return '<div class="work-primary-row">' + render({ githubLinks: [link] }, false, true) +
13
+ (sessionId ? '<button type="button" class="work-primary-choice" data-primary-url="' + attr(link.url) + '" aria-label="' + attr((selected ? 'Primary: ' : 'Make primary: ') + (link.identifier || (type === 'pr' ? 'PR #' : 'Issue #') + link.number)) + '" title="' + (selected ? 'Primary' : 'Make primary') + '" aria-pressed="' + selected + '"' + (selected ? ' disabled' : '') + '>' + PRIMARY_PIN + '</button>' : '') + '</div>';
14
+ }).join('') + '</section>';
15
+ }).join('');
16
+ return html + '<p class="work-primary-feedback" role="status" aria-live="polite"></p>';
17
+ }
18
+ export function handlePrimaryWorkClick(event) {
19
+ var button = event.target.closest('.work-primary-choice');
20
+ if (!button) return false;
21
+ event.preventDefault(); event.stopPropagation();
22
+ var popup = button.closest('#github-work-popover'), ws = getWs();
23
+ if (!popup) return true;
24
+ var feedback = popup.querySelector('.work-primary-feedback');
25
+ if (!ws || ws.readyState !== 1) { feedback.textContent = 'Reconnect to save your selection.'; return true; }
26
+ var requestId = 'work-primary-' + Date.now() + '-' + Math.random().toString(36).slice(2);
27
+ store.set({ workPrimaryPending: { requestId: requestId, sessionId: Number(popup.dataset.sessionId), projectSlug: store.get('currentSlug') } });
28
+ popup.querySelectorAll('.work-primary-choice').forEach(function (control) { control.disabled = true; });
29
+ feedback.textContent = 'Saving…';
30
+ var projectSlug = store.get('currentSlug');
31
+ setTimeout(function () {
32
+ handlePrimaryWorkResult({ requestId: requestId, projectSlug: projectSlug, error: 'Save confirmation did not arrive. Reopen the list to check, or retry.' });
33
+ }, 15000);
34
+ try { ws.send(JSON.stringify({ type: 'session_work_primary_set', requestId: requestId, sessionId: Number(popup.dataset.sessionId), url: button.dataset.primaryUrl })); }
35
+ catch (error) { handlePrimaryWorkResult({ requestId: requestId, projectSlug: store.get('currentSlug'), error: 'Could not send your selection. Please retry.' }); }
36
+ return true;
37
+ }
38
+ export function handlePrimaryWorkResult(msg) {
39
+ var pending = store.get('workPrimaryPending');
40
+ if (!pending || msg.requestId !== pending.requestId || msg.projectSlug !== pending.projectSlug) return;
41
+ store.set({ workPrimaryPending: null });
42
+ var popup = document.getElementById('github-work-popover');
43
+ if (!popup || Number(popup.dataset.sessionId) !== pending.sessionId || store.get('currentSlug') !== pending.projectSlug) return;
44
+ popup.querySelectorAll('.work-primary-choice').forEach(function (button) {
45
+ var selected = msg.error ? button.getAttribute('aria-pressed') === 'true' : Object.values(msg.workPrimary || {}).some(function (url) { return url.toLowerCase() === button.dataset.primaryUrl.toLowerCase(); });
46
+ button.setAttribute('aria-pressed', String(selected)); button.disabled = selected;
47
+ button.title = selected ? 'Primary' : 'Make primary';
48
+ button.setAttribute('aria-label', (selected ? 'Primary: ' : 'Make primary: ') + button.getAttribute('aria-label').replace(/^(Primary|Make primary): /, ''));
49
+ });
50
+ popup.querySelector('.work-primary-feedback').textContent = msg.error || 'Primary saved.';
51
+ }
@@ -2,9 +2,9 @@
2
2
  // Used by both server-settings.js and project-settings.js
3
3
 
4
4
  export var MODE_OPTIONS = [
5
- { value: "default", label: "Default", desc: "Claude asks for permission before running tools and editing files." },
6
- { value: "plan", label: "Plan", desc: "Claude creates a plan first and asks for approval before making changes." },
7
- { value: "acceptEdits", label: "Auto-accept edits", desc: "File edits are applied automatically. Claude still asks before running commands." },
5
+ { value: "default", label: "Default", desc: "The agent asks for permission before running tools and editing files." },
6
+ { value: "plan", label: "Plan", desc: "The agent creates a plan first and asks for approval before making changes." },
7
+ { value: "acceptEdits", label: "Auto-accept edits", desc: "File edits are applied automatically. The agent still asks before running commands." },
8
8
  ];
9
9
 
10
10
  export var EFFORT_LEVELS = [
@@ -16,29 +16,17 @@ export var EFFORT_LEVELS = [
16
16
 
17
17
  export var THINKING_OPTIONS = [
18
18
  { value: "disabled", label: "Off", desc: "Disable extended thinking." },
19
- { value: "adaptive", label: "Adaptive", desc: "Claude decides when to use extended thinking." },
19
+ { value: "adaptive", label: "Adaptive", desc: "The agent decides when to use extended thinking." },
20
20
  { value: "budget", label: "Budget", desc: "Set a token budget for extended thinking." },
21
21
  ];
22
22
 
23
- export var MODEL_DESCRIPTIONS = {
24
- "default": "Automatically selects the best model for the task.",
25
- "sonnet": "Fast and capable. Great balance of speed and intelligence.",
26
- "haiku": "Fastest model. Best for quick tasks and simple questions.",
27
- "opus": "Most powerful model. Best for complex reasoning and analysis.",
28
- };
29
-
30
23
  export function getModelDesc(model) {
31
- if (!model) return "";
32
- var lower = (model.value || model).toLowerCase();
33
- for (var key in MODEL_DESCRIPTIONS) {
34
- if (lower.indexOf(key) !== -1) return MODEL_DESCRIPTIONS[key];
35
- }
36
- return "";
24
+ return model && typeof model === "object" && typeof model.description === "string" ? model.description : "";
37
25
  }
38
26
 
27
+ // Compatibility name for the retired beta control; model metadata owns support.
39
28
  export function isSonnetModel(model) {
40
- if (!model) return false;
41
- return model.toLowerCase().indexOf("sonnet") !== -1;
29
+ return !!(model && typeof model === "object" && model.supportsBetaContext === true);
42
30
  }
43
31
 
44
32
  // --- Render functions ---
@@ -75,7 +63,7 @@ export function renderModelList(prefix, opts) {
75
63
  nameSpan.textContent = label;
76
64
  item.appendChild(nameSpan);
77
65
 
78
- var desc = getModelDesc(value);
66
+ var desc = getModelDesc(m);
79
67
  if (desc) {
80
68
  var descSpan = document.createElement("span");
81
69
  descSpan.className = "settings-model-desc";
@@ -106,7 +94,9 @@ export function renderModeList(prefix, opts) {
106
94
  var currentMode = opts.currentMode || "default";
107
95
  listEl.innerHTML = "";
108
96
 
109
- for (var i = 0; i < MODE_OPTIONS.length; i++) {
97
+ var modes = (opts.configuration || {}).permissionModes || [];
98
+ if (listEl.parentElement) listEl.parentElement.style.display = modes.length ? "" : "none";
99
+ for (var i = 0; i < modes.length; i++) {
110
100
  (function (opt) {
111
101
  var item = document.createElement("div");
112
102
  item.className = "settings-model-item" + (opt.value === currentMode ? " active" : "");
@@ -129,7 +119,7 @@ export function renderModeList(prefix, opts) {
129
119
  });
130
120
 
131
121
  listEl.appendChild(item);
132
- })(MODE_OPTIONS[i]);
122
+ })(modes[i]);
133
123
  }
134
124
  }
135
125
 
@@ -143,7 +133,12 @@ export function renderEffortBar(prefix, opts) {
143
133
  var currentEffort = opts.currentEffort || "medium";
144
134
  bar.innerHTML = "";
145
135
 
146
- for (var i = 0; i < EFFORT_LEVELS.length; i++) {
136
+ var levels = opts.effortLevels || [];
137
+ var model = (opts.models || []).find(function (item) { return item.value === opts.currentModel; });
138
+ if (model && model.supportsEffort === false) levels = [];
139
+ else if (model && Array.isArray(model.supportedEffortLevels)) levels = model.supportedEffortLevels;
140
+ if (bar.parentElement) bar.parentElement.style.display = levels.length ? "" : "none";
141
+ for (var i = 0; i < levels.length; i++) {
147
142
  (function (lvl) {
148
143
  var btn = document.createElement("button");
149
144
  btn.className = "settings-btn-option" + (lvl.value === currentEffort ? " active" : "");
@@ -156,7 +151,7 @@ export function renderEffortBar(prefix, opts) {
156
151
  btn.classList.add("active");
157
152
  });
158
153
  bar.appendChild(btn);
159
- })(EFFORT_LEVELS[i]);
154
+ })({ value: levels[i], desc: (EFFORT_LEVELS.find(function (item) { return item.value === levels[i]; }) || {}).desc || "" });
160
155
  }
161
156
  }
162
157
 
@@ -173,7 +168,10 @@ export function renderThinkingBar(prefix, opts) {
173
168
  var budgetInput = document.getElementById(prefix + "-thinking-budget");
174
169
  bar.innerHTML = "";
175
170
 
176
- for (var i = 0; i < THINKING_OPTIONS.length; i++) {
171
+ var thinking = (opts.configuration || {}).thinking;
172
+ if (bar.parentElement) bar.parentElement.style.display = thinking ? "" : "none";
173
+ var thinkingOptions = thinking ? THINKING_OPTIONS.filter(function(opt) { return thinking.options.indexOf(opt.value) >= 0; }) : [];
174
+ for (var i = 0; i < thinkingOptions.length; i++) {
177
175
  (function (opt) {
178
176
  var btn = document.createElement("button");
179
177
  btn.className = "settings-btn-option" + (opt.value === currentThinking ? " active" : "");
@@ -191,10 +189,10 @@ export function renderThinkingBar(prefix, opts) {
191
189
  if (budgetRow) budgetRow.style.display = opt.value === "budget" ? "" : "none";
192
190
  });
193
191
  bar.appendChild(btn);
194
- })(THINKING_OPTIONS[i]);
192
+ })(thinkingOptions[i]);
195
193
  }
196
194
 
197
- if (budgetRow) budgetRow.style.display = currentThinking === "budget" ? "" : "none";
195
+ if (budgetRow) budgetRow.style.display = thinking && currentThinking === "budget" ? "" : "none";
198
196
  if (budgetInput) {
199
197
  budgetInput.value = currentBudget;
200
198
  budgetInput.addEventListener("change", function () {
@@ -212,7 +210,8 @@ export function renderBetaCard(prefix, opts) {
212
210
  var model = opts.overrideModel || opts.currentModel || "";
213
211
  var card = document.getElementById(prefix + "-beta-card");
214
212
  if (card) {
215
- card.style.display = isSonnetModel(model) ? "" : "none";
213
+ var descriptor = (opts.models || []).find(function(item) { return item.value === model; });
214
+ card.style.display = isSonnetModel(descriptor) ? "" : "none";
216
215
  }
217
216
 
218
217
  var toggle = document.getElementById(prefix + "-beta-1m");
@@ -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, '&quot;').replace(/'/g, '&#39;'); }
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
  }