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
@@ -0,0 +1,50 @@
1
+ var userInput = require('./yoke/user-input');
2
+ var TYPES = ['linear', 'issue', 'pr'];
3
+ var GUIDANCE = ' Primary work choices belong to the user. Linking and refreshing never replace a saved primary. Only when the user explicitly requests a primary change, call the link tool with primary:true; Clay presents the exact change for human confirmation. Never request a primary change proactively. Unlinking a saved primary is refused; ask the user to choose a replacement first.';
4
+ function kind(link) { return link.provider === 'linear' ? 'linear' : link.kind; }
5
+ function selected(session, type) { return (session.workPrimary || {})[type] || ''; }
6
+ function find(session, url) {
7
+ return (session.githubLinks || []).concat(session.linearLinks || []).find(function (link) { return link.url.toLowerCase() === String(url).toLowerCase(); });
8
+ }
9
+ function guardUnlink(session, url) {
10
+ if (TYPES.some(function (type) { return selected(session, type).toLowerCase() === url.toLowerCase(); })) throw new Error('This is a user-selected primary. Choose a replacement before unlinking it.');
11
+ }
12
+ function setPrimary(sm, session, url) {
13
+ var link = find(session, url);
14
+ if (!link || TYPES.indexOf(kind(link)) < 0) throw new Error('Choose an item already linked to this session.');
15
+ var previous = session.workPrimary;
16
+ session.workPrimary = Object.assign({}, previous);
17
+ session.workPrimary[kind(link)] = link.url;
18
+ try { if (sm.saveSessionFile(session) === false) throw new Error('Could not save primary work item.'); }
19
+ catch (error) { session.workPrimary = previous; throw error; }
20
+ sm.broadcastSessionList();
21
+ return session.workPrimary;
22
+ }
23
+ async function requestPrimary(ctx, session, url, authorize) {
24
+ var link = find(session, url);
25
+ if (!link) throw new Error('Link the work item before choosing it as primary.');
26
+ var type = kind(link), previous = selected(session, type), owner = session.ownerId;
27
+ if (previous.toLowerCase() === link.url.toLowerCase()) return;
28
+ var result = await userInput.dispatchUserInput(ctx.userInput && ctx.userInput(session), { questions: [{
29
+ id: 'primary', header: 'Primary work', question: 'Set ' + link.url + ' as the primary ' + (type === 'linear' ? 'Linear issue' : type === 'pr' ? 'GitHub PR' : 'GitHub issue') + ' for this conversation?',
30
+ options: [{ label: 'Set primary' }, { label: 'Keep current' }], allowOther: false,
31
+ }] }, { source: 'work-primary', signal: session.abortController && session.abortController.signal });
32
+ if (result.status !== 'submitted' || !result.answers.primary || result.answers.primary[0] !== 'Set primary') throw new Error('Primary selection was not changed.');
33
+ authorize(session);
34
+ if (session.taskStopRequested) throw new Error('Primary selection was not changed after Stop.');
35
+ if (owner !== session.ownerId || selected(session, type) !== previous) throw new Error('The owner or primary selection changed. Please retry.');
36
+ setPrimary(ctx.sm, session, url);
37
+ }
38
+ function handleMessage(ctx, ws, msg, authorize) {
39
+ if (msg.type !== 'session_work_primary_set') return false;
40
+ var response = { type: 'session_work_primary_result', requestId: msg.requestId, projectSlug: ctx.projectSlug, sessionId: msg.sessionId };
41
+ try {
42
+ var session = ctx.sm.sessions.get(msg.sessionId);
43
+ if (!ctx.canAccess(ws) || !session || !ctx.canRefresh(ws, session)) throw new Error('Only the session owner can choose primary work.');
44
+ authorize(session);
45
+ response.workPrimary = setPrimary(ctx.sm, session, msg.url);
46
+ } catch (error) { response.error = error.message; }
47
+ ctx.sendTo(ws, response);
48
+ return true;
49
+ }
50
+ module.exports = { GUIDANCE: GUIDANCE, guardUnlink: guardUnlink, requestPrimary: requestPrimary, handleMessage: handleMessage, setPrimary: setPrimary };
package/lib/sessions.js CHANGED
@@ -3,7 +3,7 @@ var path = require("path");
3
3
  var config = require("./config");
4
4
  var utils = require("./utils");
5
5
  var users = require("./users");
6
- var { CODEX_DEFAULTS } = require("./codex-defaults");
6
+ var providerDefaults = require("./yoke/settings").defaults();
7
7
  var hygiene = require("./session-hygiene");
8
8
  var backgroundTaskTiming = require("./background-task-timing");
9
9
  var sessionProvenance = require("./session-provenance");
@@ -39,16 +39,16 @@ function createSessionManager(opts) {
39
39
  var permissionRequestIndex = {}; // requestId -> sessionLocalId (O(1) lookup)
40
40
  var capabilitiesByVendor = null; // set by sdk-bridge after adapter init
41
41
  var defaultVendor = null; // set by sdk-bridge
42
- var codexApproval = CODEX_DEFAULTS.approval;
43
- var codexSandbox = CODEX_DEFAULTS.sandbox;
44
- var codexWebSearch = CODEX_DEFAULTS.webSearch;
42
+ var codexApproval = providerDefaults.codexApproval;
43
+ var codexSandbox = providerDefaults.codexSandbox;
44
+ var codexWebSearch = providerDefaults.codexWebSearch;
45
45
 
46
46
  // --- Session persistence (centralized in ~/.clay/sessions/{encoded-cwd}/) ---
47
47
  var sessionsBase = opts.sessionsBase || path.join(config.CONFIG_DIR, "sessions");
48
48
  var encodedCwd = utils.resolveEncodedDir(sessionsBase, cwd);
49
49
  var sessionsDir = path.join(sessionsBase, encodedCwd);
50
50
  fs.mkdirSync(sessionsDir, { recursive: true });
51
- var cliSessionsDir = opts.cliSessionsDir || path.join(config.REAL_HOME, ".claude", "projects", utils.encodeCwd(cwd));
51
+ var cliSessionsDir = opts.cliSessionsDir || require("./yoke/legacy-sessions").directory(config.REAL_HOME, cwd);
52
52
  var deletedCliSessionsPath = path.join(sessionsDir, "deleted-cli-sessions.json");
53
53
  var deletedCliSessionIds = new Set();
54
54
  try {
@@ -77,29 +77,6 @@ function createSessionManager(opts) {
77
77
  }
78
78
  }
79
79
 
80
- function readCliTranscriptHead(filePath) {
81
- var MAX_READ = 64 * 1024;
82
- try {
83
- var stat = fs.statSync(filePath);
84
- var fd = fs.openSync(filePath, "r");
85
- var bytesToRead = Math.min(stat.size, MAX_READ);
86
- var buf = Buffer.alloc(bytesToRead);
87
- fs.readSync(fd, buf, 0, bytesToRead, 0);
88
- fs.closeSync(fd);
89
- var lines = buf.toString("utf8").split("\n");
90
- var events = [];
91
- for (var i = 0; i < lines.length; i++) {
92
- if (!lines[i]) continue;
93
- try {
94
- var event = JSON.parse(lines[i]);
95
- if (event && typeof event === "object") events.push(event);
96
- } catch (e) {}
97
- }
98
- return events;
99
- } catch (e) {
100
- return null;
101
- }
102
- }
103
80
 
104
81
  // Auto-migrate sessions from legacy locations:
105
82
  // v1: {cwd}/.claude-relay/sessions/
@@ -179,6 +156,7 @@ function createSessionManager(opts) {
179
156
  };
180
157
  if (session.githubLinks) metaObj.githubLinks = session.githubLinks;
181
158
  if (session.linearLinks) metaObj.linearLinks = session.linearLinks;
159
+ if (session.workPrimary) metaObj.workPrimary = session.workPrimary;
182
160
  if (session.ownerId) metaObj.ownerId = session.ownerId;
183
161
  if (session.vendor) metaObj.vendor = session.vendor;
184
162
  if (session.codexDynamicToolCatalogVersion) metaObj.codexDynamicToolCatalogVersion = session.codexDynamicToolCatalogVersion;
@@ -226,10 +204,18 @@ function createSessionManager(opts) {
226
204
  if (session.homeDebatePlanning) metaObj.homeDebatePlanning = true;
227
205
  if (session.homeDebatePhase) metaObj.homeDebatePhase = session.homeDebatePhase;
228
206
  if (session.homeDebateInitialTopic) metaObj.homeDebateInitialTopic = session.homeDebateInitialTopic;
207
+ if (session.mateScheduleDraft) metaObj.mateScheduleDraft = session.mateScheduleDraft;
208
+ if (session.mateSchedules) metaObj.mateSchedules = session.mateSchedules;
209
+ if (session.clayWorkspaceReceipts) metaObj.clayWorkspaceReceipts = session.clayWorkspaceReceipts;
210
+ if (session.clayMateChatReceipts) metaObj.clayMateChatReceipts = session.clayMateChatReceipts;
211
+ if (session.claySchedulingReceipts) metaObj.claySchedulingReceipts = session.claySchedulingReceipts;
229
212
  if (session.mateCreationMode) metaObj.mateCreationMode = true;
230
213
  if (session.homeMateCreationPhase) metaObj.homeMateCreationPhase = session.homeMateCreationPhase;
214
+ if (session.contextualCreationMateStamp) metaObj.contextualCreationMateStamp = session.contextualCreationMateStamp;
215
+ if (session.contextualCreationRequestId) metaObj.contextualCreationRequestId = session.contextualCreationRequestId;
231
216
  if (session.homeClayEntryRequestId) metaObj.homeClayEntryRequestId = session.homeClayEntryRequestId;
232
217
  if (session.homeClayEntryMode) metaObj.homeClayEntryMode = session.homeClayEntryMode;
218
+ if (session.homeClayEntryText) metaObj.homeClayEntryText = session.homeClayEntryText;
233
219
  metaObj.sessionOriginId = provenanceMeta.sessionOriginId;
234
220
  if (provenanceMeta.sessionProvenance) metaObj.sessionProvenance = provenanceMeta.sessionProvenance;
235
221
  if (Array.isArray(session._workerGenerations)) metaObj.workerGenerations = session._workerGenerations;
@@ -356,6 +342,7 @@ function createSessionManager(opts) {
356
342
  titleAutoGenerated: m.titleAutoGenerated === true,
357
343
  githubLinks: Array.isArray(m.githubLinks) ? m.githubLinks.slice(0, 8) : [],
358
344
  linearLinks: Array.isArray(m.linearLinks) ? m.linearLinks.slice(0, 8) : [],
345
+ workPrimary: m.workPrimary || {},
359
346
  titleManuallySet: m.titleManuallySet === true || legacyTitleProtected,
360
347
  createdAt: m.createdAt || Date.now(),
361
348
  lastActivity: loaded[i].mtime || m.createdAt || Date.now(),
@@ -384,10 +371,18 @@ function createSessionManager(opts) {
384
371
  if (m.homeDebatePlanning) session.homeDebatePlanning = true;
385
372
  if (m.homeDebatePhase) session.homeDebatePhase = m.homeDebatePhase;
386
373
  if (m.homeDebateInitialTopic) session.homeDebateInitialTopic = m.homeDebateInitialTopic;
374
+ if (m.mateScheduleDraft) session.mateScheduleDraft = m.mateScheduleDraft;
375
+ if (m.mateSchedules) session.mateSchedules = m.mateSchedules;
376
+ if (Array.isArray(m.clayWorkspaceReceipts)) session.clayWorkspaceReceipts = m.clayWorkspaceReceipts;
377
+ if (Array.isArray(m.clayMateChatReceipts)) session.clayMateChatReceipts = m.clayMateChatReceipts;
378
+ if (Array.isArray(m.claySchedulingReceipts)) session.claySchedulingReceipts = m.claySchedulingReceipts;
387
379
  if (m.mateCreationMode) session.mateCreationMode = true;
388
380
  if (m.homeMateCreationPhase) session.homeMateCreationPhase = m.homeMateCreationPhase;
381
+ if (m.contextualCreationMateStamp) session.contextualCreationMateStamp = m.contextualCreationMateStamp;
382
+ if (m.contextualCreationRequestId) session.contextualCreationRequestId = m.contextualCreationRequestId;
389
383
  if (m.homeClayEntryRequestId) session.homeClayEntryRequestId = m.homeClayEntryRequestId;
390
384
  if (m.homeClayEntryMode) session.homeClayEntryMode = m.homeClayEntryMode;
385
+ if (m.homeClayEntryText) session.homeClayEntryText = m.homeClayEntryText;
391
386
  if (m.ownerId) session.ownerId = m.ownerId;
392
387
  session.sessionOriginId = m.sessionOriginId || null;
393
388
  session._provenanceMigrationNeeded = sessionProvenance.restore(m, session);
@@ -458,9 +453,6 @@ function createSessionManager(opts) {
458
453
  // - Warmup shape: 1 real "hi" prompt, optional automatic interruption,
459
454
  // and 0 assistant messages (covered by daemon cleanup but defensive)
460
455
  function adoptOrphanedCliSessions() {
461
- var files;
462
- try { files = fs.readdirSync(cliSessionsDir); } catch (e) { return; }
463
-
464
456
  // Build set of cliSessionIds Clay already tracks
465
457
  var knownCliIds = new Set();
466
458
  sessions.forEach(function (s) {
@@ -469,56 +461,10 @@ function createSessionManager(opts) {
469
461
 
470
462
  var adopted = 0;
471
463
 
472
- for (var i = 0; i < files.length; i++) {
473
- if (!files[i].endsWith(".jsonl")) continue;
474
- var cliSid = files[i].slice(0, -".jsonl".length);
475
- if (knownCliIds.has(cliSid)) continue;
476
- if (deletedCliSessionIds.has(cliSid)) continue;
477
-
478
- var fp = path.join(cliSessionsDir, files[i]);
479
- var events = readCliTranscriptHead(fp);
480
- if (!events) continue;
481
- var userCount = 0;
482
- var firstUserText = null;
483
- var createdAtIso = null;
484
- for (var li = 0; li < events.length; li++) {
485
- var ev = events[li];
486
- if (ev.type === "user" && ev.message && ev.message.role === "user") {
487
- userCount++;
488
- if (firstUserText == null) {
489
- var c = ev.message.content;
490
- if (typeof c === "string") {
491
- firstUserText = c;
492
- } else if (Array.isArray(c)) {
493
- var parts = [];
494
- for (var ci = 0; ci < c.length; ci++) {
495
- if (c[ci] && c[ci].type === "text" && typeof c[ci].text === "string") parts.push(c[ci].text);
496
- }
497
- firstUserText = parts.join("");
498
- }
499
- if (ev.timestamp && !createdAtIso) createdAtIso = ev.timestamp;
500
- }
501
- }
502
- }
503
-
504
- if (userCount === 0) continue;
505
- // Defensive warmup skip (daemon also cleans these)
506
- if (hygiene.isClaudeWarmupTranscript(events)) continue;
507
-
508
- // Title: first user message trimmed/truncated. Fall back to a
509
- // neutral label so the sidebar entry is identifiable.
510
- var title = (firstUserText || "").trim().replace(/\s+/g, " ");
511
- if (title.length > 60) title = title.slice(0, 57) + "...";
512
- if (!title) title = "Imported CLI session";
513
-
514
- var createdAt = Date.now();
515
- if (createdAtIso) {
516
- var t = Date.parse(createdAtIso);
517
- if (!isNaN(t)) createdAt = t;
518
- }
519
- var lastActivity = createdAt;
520
- try { lastActivity = fs.statSync(fp).mtimeMs; } catch (e) {}
521
-
464
+ var candidates = require("./yoke/legacy-sessions").candidates(cliSessionsDir, knownCliIds, deletedCliSessionIds);
465
+ for (var i = 0; i < candidates.length; i++) {
466
+ var candidate = candidates[i], cliSid = candidate.id;
467
+ var title = candidate.title, createdAt = candidate.createdAt, lastActivity = candidate.lastActivity;
522
468
  var localId = nextLocalId++;
523
469
  var session = {
524
470
  localId: localId,
@@ -536,7 +482,7 @@ function createSessionManager(opts) {
536
482
  history: [],
537
483
  messageUUIDs: [],
538
484
  lastRewindUuid: null,
539
- vendor: "claude",
485
+ vendor: candidate.vendor,
540
486
  mode: "tui",
541
487
  // Adopted from an external `claude` run in this cwd, not started by
542
488
  // Clay. Notification emitters must stay silent for these until the
@@ -568,10 +514,7 @@ function createSessionManager(opts) {
568
514
  var stale = [];
569
515
  sessions.forEach(function (session) {
570
516
  if (!session.adopted || !session.cliSessionId) return;
571
- var transcriptPath = path.join(cliSessionsDir, session.cliSessionId + ".jsonl");
572
- var events = readCliTranscriptHead(transcriptPath);
573
- var missingEmptySource = !fs.existsSync(transcriptPath) && (!session.history || session.history.length === 0);
574
- if (missingEmptySource || (events && hygiene.isClaudeWarmupTranscript(events))) stale.push(session.localId);
517
+ if (require("./yoke/legacy-sessions").obsolete(cliSessionsDir, session)) stale.push(session.localId);
575
518
  });
576
519
  for (var i = 0; i < stale.length; i++) deleteSessionQuiet(stale[i]);
577
520
  if (stale.length > 0) {
@@ -624,11 +567,13 @@ function createSessionManager(opts) {
624
567
  var unreadMap = wsUnread || singleUserUnread;
625
568
  return {
626
569
  id: s.localId,
570
+ sessionOriginId: s.sessionOriginId || null,
627
571
  cliSessionId: s.cliSessionId || null,
628
572
  createdAt: s.createdAt || 0,
629
573
  title: s.title || "New Session",
630
574
  githubLinks: s.githubLinks || [],
631
575
  linearLinks: s.linearLinks || [],
576
+ workPrimary: s.workPrimary || {},
632
577
  active: isActive,
633
578
  isProcessing: s.isProcessing,
634
579
  // Sidebar badge: user work only. Ambient housekeeping is surfaced in the
@@ -833,8 +778,8 @@ function createSessionManager(opts) {
833
778
  }
834
779
 
835
780
  // History entries include tool activity and streamed output, so opening a
836
- // conversation needs a wider window than each incremental scroll-up page.
837
- var INITIAL_HISTORY_SIZE = 500;
781
+ // conversation starts with a 300-entry target, aligned to a complete user turn.
782
+ var INITIAL_HISTORY_SIZE = 300;
838
783
  var HISTORY_PAGE_SIZE = 100;
839
784
 
840
785
  function findTurnBoundary(history, targetIndex) {
@@ -844,8 +789,9 @@ function createSessionManager(opts) {
844
789
  return 0;
845
790
  }
846
791
 
847
- function replayHistory(session, fromIndex, targetWs, transform) {
848
- var _send = (targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send;
792
+ function replayHistory(session, fromIndex, targetWs, transform, snapshotSend) {
793
+ var _send = snapshotSend || ((targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send);
794
+ var sendHistory = snapshotSend && snapshotSend.history || _send;
849
795
  var total = session.history.length;
850
796
  if (typeof fromIndex !== "number") {
851
797
  if (total <= INITIAL_HISTORY_SIZE) {
@@ -855,7 +801,7 @@ function createSessionManager(opts) {
855
801
  }
856
802
  }
857
803
 
858
- _send({ type: "history_meta", total: total, from: fromIndex });
804
+ sendHistory({ type: "history_meta", total: total, from: fromIndex });
859
805
 
860
806
  for (var i = fromIndex; i < total; i++) {
861
807
  var _item = session.history[i];
@@ -864,7 +810,10 @@ function createSessionManager(opts) {
864
810
  if (_item && (_item.type === "mention_user" || _item.type === "mention_response")) {
865
811
  console.log("[DEBUG replayHistory] sending mention at index=" + i + " from=" + fromIndex + " total=" + total + " type=" + _item.type + " mate=" + (_item.mateName || ""));
866
812
  }
867
- _send(transform ? transform(_item) : _item);
813
+ var normalizedItem = require("./yoke/usage").clientEvent(_item, session.vendor || "claude");
814
+ var replayItem = transform ? transform(normalizedItem) : normalizedItem;
815
+ if (replayItem && typeof replayItem === "object") replayItem = Object.assign({}, replayItem, { _historyIndex: i });
816
+ sendHistory(replayItem);
868
817
  }
869
818
 
870
819
  // Find the last result message in the full history for accurate context data
@@ -872,9 +821,11 @@ function createSessionManager(opts) {
872
821
  var lastModelUsage = null;
873
822
  var lastCost = null;
874
823
  var lastStreamInputTokens = null;
824
+ var lastContext = null;
875
825
  for (var j = total - 1; j >= 0; j--) {
876
826
  if (session.history[j].type === "result") {
877
- var r = session.history[j];
827
+ var r = require("./yoke/usage").clientEvent(session.history[j], session.vendor || "claude");
828
+ lastContext = r.context || null;
878
829
  lastUsage = r.usage || null;
879
830
  lastModelUsage = r.modelUsage || null;
880
831
  lastCost = r.cost != null ? r.cost : null;
@@ -883,16 +834,17 @@ function createSessionManager(opts) {
883
834
  }
884
835
  }
885
836
 
886
- _send({ type: "history_done", lastUsage: lastUsage, lastModelUsage: lastModelUsage, lastCost: lastCost, lastStreamInputTokens: lastStreamInputTokens, contextUsage: session.lastContextUsage || null });
837
+ sendHistory({ type: "history_done", controlHistoryRevision: require("./clay-control-target-projection").digest(session.history || []), sessionId: session.localId, sessionOriginId: session.sessionOriginId || null, lastUsage: lastUsage, lastModelUsage: lastModelUsage, lastCost: lastCost, lastStreamInputTokens: lastStreamInputTokens, context: lastContext, contextUsage: require("./yoke/usage").context(session.lastContextUsage, session.vendor || "claude") });
887
838
  for (var vi = 0; vi < sessionViewedListeners.length; vi++) {
888
839
  try { sessionViewedListeners[vi](session, targetWs, _send); } catch (e) {}
889
840
  }
890
841
  }
891
842
 
892
- function switchSession(localId, targetWs, transform) {
843
+ function switchSession(localId, targetWs, transform, snapshotSend, snapshotGuard) {
893
844
  var session = sessions.get(localId);
894
845
  if (!session) return;
895
846
  if (typeof onSessionHydrate === "function") onSessionHydrate(session);
847
+ if (snapshotGuard && !snapshotGuard()) return;
896
848
 
897
849
  // Pane sockets (split-view iframes) pin their session via switch_session
898
850
  // but must not move the project-global active pointer: reloads and
@@ -913,7 +865,7 @@ function createSessionManager(opts) {
913
865
  singleUserUnread[localId] = 0;
914
866
 
915
867
  // In multi-user mode with a specific client, only send to that client
916
- var _send = (targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send;
868
+ var _send = snapshotSend || ((targetWs && sendTo) ? function (obj) { sendTo(targetWs, obj); } : send);
917
869
 
918
870
  var _capsByVendor = capabilitiesByVendor || {};
919
871
  var _sessionVendor = session.vendor || defaultVendor || "claude";
@@ -926,7 +878,7 @@ function createSessionManager(opts) {
926
878
  || [];
927
879
  _send({ type: "slash_commands", commands: _vendorCmds, vendor: _sessionVendor });
928
880
  broadcastSessionList();
929
- replayHistory(session, undefined, targetWs, transform);
881
+ replayHistory(session, undefined, targetWs, transform, snapshotSend);
930
882
 
931
883
  if (session.isProcessing) {
932
884
  _send({ type: "status", status: "processing" });
@@ -944,10 +896,15 @@ function createSessionManager(opts) {
944
896
  toolInput: p.toolInput,
945
897
  toolUseId: p.toolUseId,
946
898
  decisionReason: p.decisionReason,
899
+ defaultToNo: p.defaultToNo,
900
+ suppressAlwaysAllowRule: p.suppressAlwaysAllowRule,
901
+ mateId: p.mateId || undefined,
902
+ vendor: p.vendor || session.vendor || undefined,
947
903
  });
948
904
  }
949
905
 
950
906
  // Re-send active mention indicator so returning clients restore the mate avatar state
907
+ if (snapshotSend) require('./pane-pending-interactions').send(session, _send);
951
908
  if (session._mentionInProgress && session._mentionActiveMateId) {
952
909
  _send({ type: "mention_processing", mateId: session._mentionActiveMateId, active: true });
953
910
  }
@@ -1080,6 +1037,14 @@ function createSessionManager(opts) {
1080
1037
  }
1081
1038
  }
1082
1039
 
1040
+ // An activated pane socket only accepts frames carrying its exact binding;
1041
+ // the transport adds it, or withholds the frame if the binding is stale.
1042
+ function sendLiveToSocket(ws, session, obj, data) {
1043
+ if (!ws._clayPaneActivation) { ws.send(data); return; }
1044
+ var panePayload = require("./pane-session-transport").outbound(ws, obj, session.localId);
1045
+ if (panePayload) ws.send(JSON.stringify(panePayload));
1046
+ }
1047
+
1083
1048
  function doSendToSession(session, obj) {
1084
1049
  // Send to active clients without recording to history/disk (ephemeral data)
1085
1050
  if (sendEach) {
@@ -1088,7 +1053,7 @@ function createSessionManager(opts) {
1088
1053
  if (filterFn && !filterFn(session)) return;
1089
1054
  if (session.homeDebatePlanning === true) return;
1090
1055
  if (ws._clayActiveSession === session.localId && ws.readyState === 1) {
1091
- ws.send(data);
1056
+ sendLiveToSocket(ws, session, obj, data);
1092
1057
  }
1093
1058
  });
1094
1059
  } else if (session.localId === activeSessionId) {
@@ -1120,7 +1085,7 @@ function createSessionManager(opts) {
1120
1085
  if (filterFn && !filterFn(session)) return;
1121
1086
  if (session.homeDebatePlanning === true) return;
1122
1087
  if (ws._clayActiveSession === session.localId) {
1123
- if (ws.readyState === 1) ws.send(data);
1088
+ if (ws.readyState === 1) sendLiveToSocket(ws, session, outgoingObj, data);
1124
1089
  } else if (session.isProcessing && !session._ioThrottle) {
1125
1090
  if (!ioData) ioData = JSON.stringify({ type: "session_io", id: session.localId });
1126
1091
  if (ws.readyState === 1) ws.send(ioData);
@@ -0,0 +1,32 @@
1
+ var cookieKey = require('./shared-browser-cookies').cookieKey;
2
+
3
+ // Only the private worker pipe carries cookies. They never enter browser state or tool output.
4
+ function attachCookieSync(context, initial, send) {
5
+ var pending = null;
6
+ var previous = initial;
7
+ var nextId = 0;
8
+ function receive(message) {
9
+ if (!pending || pending.id !== message.id) return;
10
+ var entry = pending; pending = null; clearTimeout(entry.timer);
11
+ if (message.error) entry.reject(new Error(message.error));
12
+ else entry.resolve(message.cookies);
13
+ }
14
+ async function sync() {
15
+ var current = await context.cookies();
16
+ var cookies = await new Promise(function (resolve, reject) {
17
+ pending = { id: ++nextId, resolve: resolve, reject: reject, timer: setTimeout(function () { pending = null; reject(new Error('Could not synchronize browser cookies')); }, 4000) };
18
+ try { send({ type: 'cookies', id: pending.id, previous: previous, cookies: current }); }
19
+ catch (error) { clearTimeout(pending.timer); pending = null; reject(error); }
20
+ });
21
+ var remote = new Map(cookies.map(function (cookie) { return [cookieKey(cookie), cookie]; }));
22
+ var local = new Map(current.map(function (cookie) { return [cookieKey(cookie), cookie]; }));
23
+ var updates = cookies.filter(function (cookie) { return JSON.stringify(local.get(cookieKey(cookie))) !== JSON.stringify(cookie); });
24
+ current.forEach(function (cookie) {
25
+ if (!remote.has(cookieKey(cookie))) updates.push(Object.assign({}, cookie, { expires: 1 }));
26
+ });
27
+ if (updates.length) await context.addCookies(updates);
28
+ previous = cookies;
29
+ }
30
+ return { start: function () { return context.addCookies(initial); }, sync: sync, receive: receive };
31
+ }
32
+ module.exports = { attachCookieSync: attachCookieSync };
@@ -0,0 +1,79 @@
1
+ var fs = require('fs');
2
+ var path = require('path');
3
+ var crypto = require('crypto');
4
+
5
+ function cookieKey(cookie) {
6
+ return JSON.stringify([cookie.domain, cookie.path, cookie.name, cookie.partitionKey || '']);
7
+ }
8
+ function cookieMap(cookies) {
9
+ if (!Array.isArray(cookies) || cookies.length > 10000 || JSON.stringify(cookies).length > 2 * 1024 * 1024) throw new Error('Browser cookies exceed the storage limit');
10
+ var result = new Map();
11
+ cookies.forEach(function (cookie) {
12
+ if (!cookie || typeof cookie.name !== 'string' || typeof cookie.value !== 'string' || typeof cookie.domain !== 'string' || typeof cookie.path !== 'string') throw new Error('Invalid browser cookie');
13
+ result.set(cookieKey(cookie), cookie);
14
+ });
15
+ return result;
16
+ }
17
+ function same(a, b) { return JSON.stringify(a) === JSON.stringify(b); }
18
+
19
+ // Merge only a tab's changes, so an idle tab cannot overwrite another tab's login or logout.
20
+ function mergeCookies(saved, previous, current) {
21
+ var merged = cookieMap(saved), before = cookieMap(previous), after = cookieMap(current);
22
+ before.forEach(function (cookie, key) {
23
+ if (!after.has(key) && same(merged.get(key), cookie)) merged.delete(key);
24
+ });
25
+ after.forEach(function (cookie, key) {
26
+ if (!same(before.get(key), cookie)) merged.set(key, cookie);
27
+ });
28
+ return Array.from(merged.values()).filter(function (cookie) { return cookie.expires === -1 || cookie.expires > Date.now() / 1000; });
29
+ }
30
+
31
+ function attachEncryptedStore(root, name, empty) {
32
+ var directory = path.join(root, name);
33
+ function ownerKey(owner) {
34
+ if (typeof owner !== 'string' || !owner || owner.length > 256) throw new Error('Browser data owner is required');
35
+ return crypto.createHash('sha256').update(owner).digest('hex');
36
+ }
37
+ function masterKey() {
38
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
39
+ var file = path.join(directory, '.key');
40
+ try { fs.writeFileSync(file, crypto.randomBytes(32), { flag: 'wx', mode: 0o600 }); }
41
+ catch (error) { if (error.code !== 'EEXIST') throw error; }
42
+ return fs.readFileSync(file);
43
+ }
44
+ function read(owner) {
45
+ var id = ownerKey(owner), raw;
46
+ try { raw = fs.readFileSync(path.join(directory, id + '.json'), 'utf8'); }
47
+ catch (error) { if (error.code === 'ENOENT') return empty(); throw new Error('Could not read saved browser data'); }
48
+ try {
49
+ var parts = JSON.parse(raw).map(function (part) { return Buffer.from(part, 'base64'); });
50
+ var cipher = crypto.createDecipheriv('aes-256-gcm', masterKey(), parts[0]);
51
+ cipher.setAAD(Buffer.from(id)); cipher.setAuthTag(parts[1]);
52
+ var cookies = JSON.parse(Buffer.concat([cipher.update(parts[2]), cipher.final()]).toString('utf8'));
53
+ return cookies;
54
+ } catch (error) { throw new Error('Could not decrypt saved browser data'); }
55
+ }
56
+ function write(owner, cookies) {
57
+ var id = ownerKey(owner), iv = crypto.randomBytes(12);
58
+ var cipher = crypto.createCipheriv('aes-256-gcm', masterKey(), iv);
59
+ cipher.setAAD(Buffer.from(id));
60
+ var bytes = Buffer.concat([cipher.update(JSON.stringify(cookies), 'utf8'), cipher.final()]);
61
+ var file = path.join(directory, id + '.json'), temp = file + '.' + crypto.randomBytes(8).toString('hex') + '.tmp';
62
+ try {
63
+ fs.writeFileSync(temp, JSON.stringify([iv, cipher.getAuthTag(), bytes].map(function (part) { return part.toString('base64'); })), { mode: 0o600 });
64
+ fs.renameSync(temp, file);
65
+ } finally { try { fs.unlinkSync(temp); } catch (error) { if (error.code !== 'ENOENT') throw error; } }
66
+ return cookies;
67
+ }
68
+ return { read: read, write: write };
69
+ }
70
+ function attachCookieStore(root) {
71
+ var disk = attachEncryptedStore(root, 'browser-cookies', function () { return []; });
72
+ function read(owner) { return mergeCookies(disk.read(owner), [], []); }
73
+ return { read: read, clear: function (owner) { disk.write(owner, []); }, exchange: function (owner, previous, current) {
74
+ var saved = read(owner), merged = mergeCookies(saved, previous, current);
75
+ if (!same(saved, merged)) disk.write(owner, merged);
76
+ return merged;
77
+ } };
78
+ }
79
+ module.exports = { attachEncryptedStore: attachEncryptedStore, attachCookieStore: attachCookieStore, mergeCookies: mergeCookies, cookieKey: cookieKey };
@@ -5,6 +5,8 @@ var buildUserEnv = require("./build-user-env").buildUserEnv;
5
5
  var wrapSpawnAsUser = require("./os-users").wrapSpawnAsUser;
6
6
 
7
7
  function createRuntime(options) {
8
+ var initialStorage = options.storage ? options.storage.read() : null;
9
+ var initialCookies = options.cookies ? options.cookies.read() : null;
8
10
  var identity = options.identity;
9
11
  var env = buildUserEnv(identity);
10
12
  if (process.platform === "win32" && !identity) {
@@ -14,7 +16,9 @@ function createRuntime(options) {
14
16
  if (identity) { opts.uid = identity.uid; opts.gid = identity.gid; }
15
17
  var spec = wrapSpawnAsUser(process.execPath, [path.join(__dirname, "shared-browser-worker.js")], opts);
16
18
  var child = spawn(spec.command, spec.args, spec.options);
19
+ var exited = new Promise(function (resolve) { child.once("close", resolve); });
17
20
  var closed = false;
21
+ var closing = false;
18
22
  var nextId = 0;
19
23
  var pending = new Map();
20
24
  var buffer = "";
@@ -25,19 +29,30 @@ function createRuntime(options) {
25
29
  function fail(message) {
26
30
  pending.forEach(function (entry) { clearTimeout(entry.timer); entry.reject(new Error(message)); });
27
31
  pending.clear();
28
- if (!closed) options.onEvent({ type: "error", error: message });
32
+ if (!closed && !closing) options.onEvent({ type: "error", error: message });
29
33
  }
30
34
  child.stdin.on("error", function () {});
31
35
  child.stdout.setEncoding("utf8");
32
36
  child.stdout.on("data", function (chunk) {
33
37
  buffer += chunk;
34
- if (buffer.length > 8 * 1024 * 1024) { fail("Browser response too large"); child.kill(); return; }
38
+ if (buffer.length > 32 * 1024 * 1024) { fail("Browser response too large"); child.kill(); return; }
35
39
  var at;
36
40
  while ((at = buffer.indexOf("\n")) >= 0) {
37
41
  var line = buffer.slice(0, at); buffer = buffer.slice(at + 1);
38
42
  try {
39
43
  var message = JSON.parse(line);
40
- if (message.type === "result") {
44
+ if (message.type === "storage") {
45
+ try {
46
+ if (!options.storage) throw new Error("Personal site data is unavailable");
47
+ send({ type: "storage", id: message.id, storage: options.storage.exchange(message.previous, message.storage) });
48
+ } catch (error) { send({ type: "storage", id: message.id, error: "Could not save personal browser site data" }); }
49
+ } else if (message.type === "cookies") {
50
+ try {
51
+ if (!options.cookies) throw new Error("Personal cookies are unavailable");
52
+ var cookies = options.cookies.exchange(message.previous, message.cookies);
53
+ send({ type: "cookies", id: message.id, cookies: cookies });
54
+ } catch (error) { send({ type: "cookies", id: message.id, error: "Could not save personal browser cookies" }); }
55
+ } else if (message.type === "result") {
41
56
  var entry = pending.get(message.id);
42
57
  if (entry) { clearTimeout(entry.timer); pending.delete(message.id); if (message.error) entry.reject(new Error(message.error)); else entry.resolve(message.value); }
43
58
  } else options.onEvent(message);
@@ -45,8 +60,8 @@ function createRuntime(options) {
45
60
  }
46
61
  });
47
62
  child.on("error", function () { fail("Browser process could not start"); });
48
- child.on("exit", function () { fail("Browser process ended"); });
49
- send({ type: "start" });
63
+ child.on("exit", function () { fail("Browser process ended"); closed = true; });
64
+ send({ type: "start", cookies: initialCookies, storage: initialStorage });
50
65
  return {
51
66
  control: function (epoch) {
52
67
  return new Promise(function (resolve, reject) {
@@ -78,13 +93,14 @@ function createRuntime(options) {
78
93
  });
79
94
  },
80
95
  close: function () {
81
- if (closed) return;
82
- closed = true;
96
+ if (closed || closing) return exited;
97
+ closing = true;
83
98
  fail("Browser closed");
84
- child.stdin.end();
85
- var timer = setTimeout(function () { child.kill("SIGKILL"); }, 5000);
99
+ try { send({ type: "close" }); } catch (error) { child.stdin.end(); }
100
+ var timer = setTimeout(function () { child.kill("SIGKILL"); }, 30000);
86
101
  timer.unref();
87
102
  child.once("exit", function () { clearTimeout(timer); });
103
+ return exited;
88
104
  },
89
105
  };
90
106
  }
@@ -0,0 +1,43 @@
1
+ var cookieKey = require('./shared-browser-cookies').cookieKey;
2
+ // Saved website data only crosses the private worker pipe, never the agent tool channel.
3
+ function attachStorageSync(context, initial, send) {
4
+ var previous = initial, pending = null, nextId = 0;
5
+ function receive(message) {
6
+ if (!pending || pending.id !== message.id) return;
7
+ var entry = pending; pending = null; clearTimeout(entry.timer);
8
+ if (message.error) entry.reject(new Error(message.error)); else entry.resolve(message.storage);
9
+ }
10
+ async function sync() {
11
+ var current = await context.storageState({ indexedDB: true });
12
+ var saved = await new Promise(function (resolve, reject) {
13
+ pending = { id: ++nextId, resolve: resolve, reject: reject, timer: setTimeout(function () { pending = null; reject(new Error('Could not synchronize browser site data')); }, 10000) };
14
+ try { send({ type: 'storage', id: pending.id, previous: previous, storage: current }); }
15
+ catch (error) { clearTimeout(pending.timer); pending = null; reject(error); }
16
+ });
17
+ var remote = new Map(saved.cookies.map(function (cookie) { return [cookieKey(cookie), cookie]; }));
18
+ var local = new Map(current.cookies.map(function (cookie) { return [cookieKey(cookie), cookie]; }));
19
+ var updates = saved.cookies.filter(function (cookie) { return JSON.stringify(local.get(cookieKey(cookie))) !== JSON.stringify(cookie); });
20
+ current.cookies.forEach(function (cookie) { if (!remote.has(cookieKey(cookie))) updates.push(Object.assign({}, cookie, { expires: 1 })); });
21
+ if (updates.length) await context.addCookies(updates);
22
+ if (previous.generation !== saved.generation) {
23
+ var deletions = (saved.deletions || []).filter(function (entry) { return entry.generation > previous.generation; });
24
+ var unknown = !deletions.length || deletions[0].generation > previous.generation + 1;
25
+ var removed = current.origins.filter(function (origin) {
26
+ return unknown || deletions.some(function (entry) { return entry.operation === 'clear_data' || (entry.operation === 'delete_site' && new URL(origin.origin).hostname === entry.target); });
27
+ });
28
+ if (removed.length) {
29
+ var page = context.pages()[0] || await context.newPage();
30
+ var cdp = await context.newCDPSession(page);
31
+ try {
32
+ for (var origin of removed) await cdp.send('Storage.clearDataForOrigin', { origin: origin.origin, storageTypes: 'local_storage,indexeddb' });
33
+ } finally { await cdp.detach(); }
34
+ }
35
+ current = await context.storageState({ indexedDB: true });
36
+ }
37
+ // Restore origin storage on new tabs, rather than replacing live IndexedDB connections.
38
+ // Each open tab contributes only its own changes. Human removals also clear live origins.
39
+ previous = { generation: saved.generation, cookies: saved.cookies, origins: current.origins };
40
+ }
41
+ return { start: function () { return context.setStorageState({ cookies: initial.cookies, origins: initial.origins }); }, sync: sync, receive: receive };
42
+ }
43
+ module.exports = { attachStorageSync: attachStorageSync };