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

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 (608) hide show
  1. package/README.md +0 -4
  2. package/lib/account-auth-socket.js +1 -0
  3. package/lib/builtin-mates.js +19 -16
  4. package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
  5. package/lib/canonical-clay-record-authority.js +15 -0
  6. package/lib/canonical-clay-scheduling-authority.js +19 -0
  7. package/lib/claude-hook-installer.js +1 -239
  8. package/lib/claude-jsonl-watcher.js +1 -204
  9. package/lib/clay-control-presentation-binding.js +96 -0
  10. package/lib/clay-control-presentation.js +128 -0
  11. package/lib/clay-control-target-projection.js +26 -0
  12. package/lib/clay-mate-chat-receipts.js +26 -0
  13. package/lib/clay-mate-chat.js +88 -0
  14. package/lib/clay-mate-knowledge-input.js +26 -0
  15. package/lib/clay-mate-knowledge.js +95 -0
  16. package/lib/clay-mate-lifecycle.js +95 -0
  17. package/lib/clay-product-control-input.js +33 -0
  18. package/lib/clay-product-control-tools.js +52 -0
  19. package/lib/clay-product-control.js +250 -0
  20. package/lib/clay-project-lifecycle.js +154 -0
  21. package/lib/clay-project-record-input.js +44 -0
  22. package/lib/clay-project-records.js +84 -0
  23. package/lib/clay-scheduling-input.js +21 -0
  24. package/lib/clay-scheduling-receipts.js +26 -0
  25. package/lib/clay-scheduling.js +119 -0
  26. package/lib/clay-screen-controls.js +104 -0
  27. package/lib/clay-skill-install.js +1 -33
  28. package/lib/clay-vendor-usage.js +44 -0
  29. package/lib/clay-workspace-controls.js +84 -0
  30. package/lib/clay-workspace-input.js +17 -0
  31. package/lib/clay-workspace-receipts.js +26 -0
  32. package/lib/cli-sessions.js +1 -300
  33. package/lib/codex-defaults.js +1 -28
  34. package/lib/context-usage.js +3 -2
  35. package/lib/contextual-screen-snapshot.js +38 -0
  36. package/lib/daemon-project-access.js +11 -0
  37. package/lib/daemon-project-lifecycle-callbacks.js +15 -0
  38. package/lib/daemon-project-lifecycle.js +262 -0
  39. package/lib/daemon-projects.js +1 -1
  40. package/lib/daemon.js +78 -276
  41. package/lib/default-ai-runtime.js +4 -8
  42. package/lib/dm-digest-cursor.js +120 -0
  43. package/lib/email-mcp-server.js +1 -1
  44. package/lib/github-star-count.js +147 -0
  45. package/lib/issues-service.js +29 -15
  46. package/lib/kiro-defaults.js +1 -22
  47. package/lib/knowledge-db-import-validation.js +46 -0
  48. package/lib/knowledge-db-import.js +99 -0
  49. package/lib/knowledge-db-service.js +24 -33
  50. package/lib/knowledge-db-storage-nedb-maintenance.js +99 -0
  51. package/lib/knowledge-db-storage-nedb.js +66 -0
  52. package/lib/knowledge-db-storage.js +72 -0
  53. package/lib/knowledge-db-validation.js +0 -0
  54. package/lib/knowledge-document-index.js +2 -1
  55. package/lib/knowledge-file-store.js +7 -1
  56. package/lib/knowledge-product-operations.js +46 -0
  57. package/lib/mate-avatar-catalog.js +12 -0
  58. package/lib/mate-avatar-migration.js +41 -0
  59. package/lib/mate-context-service.js +138 -0
  60. package/lib/mate-context-tools.js +21 -0
  61. package/lib/mate-creation-mcp-server.js +2 -0
  62. package/lib/mate-knowledge-canonical-access.js +10 -0
  63. package/lib/mate-knowledge-mate-bound.js +53 -0
  64. package/lib/mate-knowledge-mcp-server.js +55 -8
  65. package/lib/mate-knowledge-service.js +16 -34
  66. package/lib/mate-knowledge-text-tools.js +106 -0
  67. package/lib/mate-lifecycle-service.js +94 -0
  68. package/lib/mate-message-delivery.js +43 -0
  69. package/lib/mate-ready-creation.js +9 -1
  70. package/lib/mate-schedule-input.js +29 -0
  71. package/lib/mate-schedule-lifecycle.js +151 -0
  72. package/lib/mate-scheduling.js +103 -0
  73. package/lib/mates.js +18 -6
  74. package/lib/mcp-agent-tools.js +117 -0
  75. package/lib/mcp-connection-store.js +119 -15
  76. package/lib/mcp-import-credentials.js +31 -0
  77. package/lib/mcp-local-transport.js +13 -0
  78. package/lib/mcp-oauth.js +8 -6
  79. package/lib/mcp-proxy.js +2 -32
  80. package/lib/mcp-query-bridge.js +30 -0
  81. package/lib/mcp-remote-connections.js +74 -20
  82. package/lib/mcp-source-adapters.js +1 -0
  83. package/lib/mcp-source-context.js +1 -0
  84. package/lib/mcp-source-discovery.js +1 -0
  85. package/lib/mcp-source-plugins.js +1 -0
  86. package/lib/mcp-source-restrictions.js +1 -0
  87. package/lib/mcp-tool-policy.js +9 -0
  88. package/lib/notes-checklist.js +92 -0
  89. package/lib/notes.js +51 -4
  90. package/lib/os-user-diagnostics.js +2 -4
  91. package/lib/os-users.js +24 -70
  92. package/lib/pane-pending-interactions.js +20 -0
  93. package/lib/pane-session-activation.js +114 -0
  94. package/lib/pane-session-transport.js +26 -0
  95. package/lib/project-admin-overview.js +51 -0
  96. package/lib/project-ask-user.js +8 -4
  97. package/lib/project-connection.js +14 -10
  98. package/lib/project-control-git-view.js +12 -0
  99. package/lib/project-debate.js +1 -0
  100. package/lib/project-delegated-follow-up.js +2 -1
  101. package/lib/project-directory-claim.js +65 -0
  102. package/lib/project-file-operations.js +61 -0
  103. package/lib/project-filesystem.js +15 -85
  104. package/lib/project-full-access.js +23 -2
  105. package/lib/project-http.js +7 -4
  106. package/lib/project-knowledge.js +32 -18
  107. package/lib/project-lifecycle-operations.js +98 -0
  108. package/lib/project-lifecycle-process-witness.js +32 -0
  109. package/lib/project-lifecycle-runtime.js +50 -0
  110. package/lib/project-linux-access.js +22 -0
  111. package/lib/project-logs-canonical-clay.js +27 -0
  112. package/lib/project-logs-clay-query.js +16 -0
  113. package/lib/project-logs-schema.js +4 -2
  114. package/lib/project-logs-service.js +8 -7
  115. package/lib/project-logs.js +1 -0
  116. package/lib/project-loop.js +1 -0
  117. package/lib/project-mate-chat-control.js +55 -0
  118. package/lib/project-mate-creation-proposal.js +18 -3
  119. package/lib/project-mate-interaction.js +40 -62
  120. package/lib/project-mcp.js +54 -16
  121. package/lib/project-models.js +14 -31
  122. package/lib/project-notifications.js +76 -17
  123. package/lib/project-ownership.js +77 -0
  124. package/lib/project-pair-result-delivery.js +14 -3
  125. package/lib/project-pair-usage.js +12 -13
  126. package/lib/project-pending-message-queue.js +4 -1
  127. package/lib/project-product-control.js +89 -0
  128. package/lib/project-product-session-queue.js +46 -0
  129. package/lib/project-push-access.js +28 -0
  130. package/lib/project-scheduled-message-queue.js +30 -0
  131. package/lib/project-scheduled-messages.js +67 -68
  132. package/lib/project-scheduled-task-control.js +83 -0
  133. package/lib/project-scheduled-tasks.js +13 -2
  134. package/lib/project-scheduling-access.js +10 -0
  135. package/lib/project-session-actions.js +65 -0
  136. package/lib/project-session-delete.js +8 -1
  137. package/lib/project-session-document.js +27 -7
  138. package/lib/project-session-github.js +63 -19
  139. package/lib/project-session-history-actions.js +167 -0
  140. package/lib/project-session-linear.js +14 -6
  141. package/lib/project-session-notes.js +40 -11
  142. package/lib/project-session-pair.js +1 -1
  143. package/lib/project-session-runtime-actions.js +64 -0
  144. package/lib/project-session-spawn.js +2 -3
  145. package/lib/project-session-vendor.js +55 -0
  146. package/lib/project-sessions.js +160 -290
  147. package/lib/project-shared-browser.js +78 -17
  148. package/lib/project-start-protocol.js +29 -0
  149. package/lib/project-studio-presentation.js +58 -0
  150. package/lib/project-user-message.js +67 -1
  151. package/lib/project-vendor-login.js +8 -36
  152. package/lib/project-workspace-operations.js +126 -0
  153. package/lib/project-workspace-query.js +19 -2
  154. package/lib/project.js +181 -45
  155. package/lib/public/app.js +71 -17
  156. package/lib/public/appearance-bootstrap.js +16 -0
  157. package/lib/public/css/clay-tool-activity.css +51 -0
  158. package/lib/public/css/clay-workspace.css +29 -0
  159. package/lib/public/css/command-palette.css +12 -33
  160. package/lib/public/css/contextual-clay.css +240 -0
  161. package/lib/public/css/filebrowser.css +1 -1
  162. package/lib/public/css/home-debate-planning.css +2 -0
  163. package/lib/public/css/home-mate-creation.css +5 -0
  164. package/lib/public/css/input.css +6 -0
  165. package/lib/public/css/mate-avatar-gallery.css +12 -0
  166. package/lib/public/css/mate-conversation.css +10 -5
  167. package/lib/public/css/mate-loading-scene.css +21 -0
  168. package/lib/public/css/messages.css +6 -2
  169. package/lib/public/css/overlays.css +68 -258
  170. package/lib/public/css/project-admin-overview.css +13 -0
  171. package/lib/public/css/project-mate-creation.css +5 -6
  172. package/lib/public/css/project-start.css +108 -0
  173. package/lib/public/css/projects-hub.css +53 -14
  174. package/lib/public/css/session-folders.css +11 -0
  175. package/lib/public/css/session-github.css +46 -1
  176. package/lib/public/css/settings-shell.css +103 -0
  177. package/lib/public/css/shared-browser.css +35 -1
  178. package/lib/public/css/sidebar.css +7 -0
  179. package/lib/public/css/sticky-notes.css +87 -1
  180. package/lib/public/css/title-bar.css +79 -0
  181. package/lib/public/index.html +61 -68
  182. package/lib/public/mate-avatars/B01.png +0 -0
  183. package/lib/public/mate-avatars/B02.png +0 -0
  184. package/lib/public/mate-avatars/B03.png +0 -0
  185. package/lib/public/mate-avatars/B04.png +0 -0
  186. package/lib/public/mate-avatars/B05.png +0 -0
  187. package/lib/public/mate-avatars/B06.png +0 -0
  188. package/lib/public/mate-avatars/B07.png +0 -0
  189. package/lib/public/mate-avatars/B08.png +0 -0
  190. package/lib/public/mate-avatars/B09.png +0 -0
  191. package/lib/public/mate-avatars/B10.png +0 -0
  192. package/lib/public/mate-avatars/B11.png +0 -0
  193. package/lib/public/mate-avatars/B12.png +0 -0
  194. package/lib/public/mate-avatars/B13.png +0 -0
  195. package/lib/public/mate-avatars/B14.png +0 -0
  196. package/lib/public/mate-avatars/B15.png +0 -0
  197. package/lib/public/mate-avatars/B16.png +0 -0
  198. package/lib/public/mate-avatars/B17.png +0 -0
  199. package/lib/public/mate-avatars/B18.png +0 -0
  200. package/lib/public/mate-avatars/B19.png +0 -0
  201. package/lib/public/mate-avatars/B20.png +0 -0
  202. package/lib/public/mate-avatars/B21.png +0 -0
  203. package/lib/public/mate-avatars/B22.png +0 -0
  204. package/lib/public/mate-avatars/B23.png +0 -0
  205. package/lib/public/mate-avatars/B24.png +0 -0
  206. package/lib/public/mate-avatars/B25.png +0 -0
  207. package/lib/public/mate-avatars/B26.png +0 -0
  208. package/lib/public/mate-avatars/B27.png +0 -0
  209. package/lib/public/mate-avatars/B28.png +0 -0
  210. package/lib/public/mate-avatars/B29.png +0 -0
  211. package/lib/public/mate-avatars/B30.png +0 -0
  212. package/lib/public/mate-avatars/B31.png +0 -0
  213. package/lib/public/mate-avatars/B32.png +0 -0
  214. package/lib/public/mate-avatars/B33.png +0 -0
  215. package/lib/public/mate-avatars/B34.png +0 -0
  216. package/lib/public/mate-avatars/B35.png +0 -0
  217. package/lib/public/mate-avatars/B36.png +0 -0
  218. package/lib/public/mate-avatars/B37.png +0 -0
  219. package/lib/public/mate-avatars/B38.png +0 -0
  220. package/lib/public/mate-avatars/B39.png +0 -0
  221. package/lib/public/mate-avatars/B40.png +0 -0
  222. package/lib/public/mate-avatars/B41.png +0 -0
  223. package/lib/public/mate-avatars/B42.png +0 -0
  224. package/lib/public/mate-avatars/B43.png +0 -0
  225. package/lib/public/mate-avatars/B44.png +0 -0
  226. package/lib/public/mate-avatars/B45.png +0 -0
  227. package/lib/public/mate-avatars/B46.png +0 -0
  228. package/lib/public/mate-avatars/B47.png +0 -0
  229. package/lib/public/mate-avatars/B48.png +0 -0
  230. package/lib/public/mate-avatars/C01.png +0 -0
  231. package/lib/public/mate-avatars/C02.png +0 -0
  232. package/lib/public/mate-avatars/C03.png +0 -0
  233. package/lib/public/mate-avatars/C04.png +0 -0
  234. package/lib/public/mate-avatars/C05.png +0 -0
  235. package/lib/public/mate-avatars/C06.png +0 -0
  236. package/lib/public/mate-avatars/C07.png +0 -0
  237. package/lib/public/mate-avatars/C08.png +0 -0
  238. package/lib/public/mate-avatars/C09.png +0 -0
  239. package/lib/public/mate-avatars/C10.png +0 -0
  240. package/lib/public/mate-avatars/C11.png +0 -0
  241. package/lib/public/mate-avatars/C12.png +0 -0
  242. package/lib/public/mate-avatars/C13.png +0 -0
  243. package/lib/public/mate-avatars/C14.png +0 -0
  244. package/lib/public/mate-avatars/C15.png +0 -0
  245. package/lib/public/mate-avatars/C16.png +0 -0
  246. package/lib/public/mate-avatars/C17.png +0 -0
  247. package/lib/public/mate-avatars/C18.png +0 -0
  248. package/lib/public/mate-avatars/C19.png +0 -0
  249. package/lib/public/mate-avatars/C20.png +0 -0
  250. package/lib/public/mate-avatars/C21.png +0 -0
  251. package/lib/public/mate-avatars/C22.png +0 -0
  252. package/lib/public/mate-avatars/C23.png +0 -0
  253. package/lib/public/mate-avatars/C24.png +0 -0
  254. package/lib/public/mate-avatars/C25.png +0 -0
  255. package/lib/public/mate-avatars/C26.png +0 -0
  256. package/lib/public/mate-avatars/C27.png +0 -0
  257. package/lib/public/mate-avatars/C28.png +0 -0
  258. package/lib/public/mate-avatars/C29.png +0 -0
  259. package/lib/public/mate-avatars/C30.png +0 -0
  260. package/lib/public/mate-avatars/C31.png +0 -0
  261. package/lib/public/mate-avatars/C32.png +0 -0
  262. package/lib/public/mate-avatars/C33.png +0 -0
  263. package/lib/public/mate-avatars/C34.png +0 -0
  264. package/lib/public/mate-avatars/C35.png +0 -0
  265. package/lib/public/mate-avatars/C36.png +0 -0
  266. package/lib/public/mate-avatars/C37.png +0 -0
  267. package/lib/public/mate-avatars/C38.png +0 -0
  268. package/lib/public/mate-avatars/C39.png +0 -0
  269. package/lib/public/mate-avatars/C40.png +0 -0
  270. package/lib/public/mate-avatars/C41.png +0 -0
  271. package/lib/public/mate-avatars/C42.png +0 -0
  272. package/lib/public/mate-avatars/C43.png +0 -0
  273. package/lib/public/mate-avatars/C44.png +0 -0
  274. package/lib/public/mate-avatars/C45.png +0 -0
  275. package/lib/public/mate-avatars/C46.png +0 -0
  276. package/lib/public/mate-avatars/C47.png +0 -0
  277. package/lib/public/mate-avatars/C48.png +0 -0
  278. package/lib/public/mate-avatars/catalog.json +482 -0
  279. package/lib/public/mate-avatars/lead-clay.png +0 -0
  280. package/lib/public/modules/admin-settings-invitations.js +2 -2
  281. package/lib/public/modules/admin-settings-projects.js +8 -4
  282. package/lib/public/modules/admin-settings-ui.js +20 -4
  283. package/lib/public/modules/admin-settings-users.js +4 -4
  284. package/lib/public/modules/app-connection.js +11 -1
  285. package/lib/public/modules/app-favicon.js +18 -9
  286. package/lib/public/modules/app-header.js +7 -4
  287. package/lib/public/modules/app-home-hub.js +2 -1
  288. package/lib/public/modules/app-loop-ui.js +2 -0
  289. package/lib/public/modules/app-message-router.js +22 -1
  290. package/lib/public/modules/app-messages.js +125 -19
  291. package/lib/public/modules/app-misc.js +3 -1
  292. package/lib/public/modules/app-notifications.js +11 -5
  293. package/lib/public/modules/app-panels.js +61 -123
  294. package/lib/public/modules/app-projects.js +14 -407
  295. package/lib/public/modules/app-rate-limit.js +19 -28
  296. package/lib/public/modules/app-rendering.js +4 -3
  297. package/lib/public/modules/avatar.js +15 -41
  298. package/lib/public/modules/chat-render-runtime.js +20 -0
  299. package/lib/public/modules/clay-browser-links.js +47 -0
  300. package/lib/public/modules/clay-control-activity.js +214 -0
  301. package/lib/public/modules/clay-control-copy.js +36 -0
  302. package/lib/public/modules/clay-control-detail-targets.js +44 -0
  303. package/lib/public/modules/clay-control-object-targets.js +52 -0
  304. package/lib/public/modules/clay-control-target-visibility.js +12 -0
  305. package/lib/public/modules/clay-control-targets.js +44 -0
  306. package/lib/public/modules/clay-log-links.js +23 -0
  307. package/lib/public/modules/clay-navigation-render.js +52 -0
  308. package/lib/public/modules/clay-owner-navigation.js +33 -0
  309. package/lib/public/modules/clay-session-links.js +31 -0
  310. package/lib/public/modules/clay-studio-bridge.js +20 -0
  311. package/lib/public/modules/clay-studio-document.js +67 -0
  312. package/lib/public/modules/clay-studio-render.js +146 -0
  313. package/lib/public/modules/clay-tool-activity.js +140 -0
  314. package/lib/public/modules/clay-tool-presentation.js +343 -0
  315. package/lib/public/modules/command-palette.js +162 -40
  316. package/lib/public/modules/contextual-ask-session.js +26 -0
  317. package/lib/public/modules/contextual-clay-geometry.js +155 -0
  318. package/lib/public/modules/contextual-clay-session.js +130 -0
  319. package/lib/public/modules/contextual-clay-workspace.js +169 -0
  320. package/lib/public/modules/contextual-clay.js +252 -0
  321. package/lib/public/modules/contextual-composer.js +91 -0
  322. package/lib/public/modules/contextual-mate-context.js +117 -0
  323. package/lib/public/modules/contextual-mate-hint.js +40 -0
  324. package/lib/public/modules/contextual-mate-identity.js +23 -0
  325. package/lib/public/modules/contextual-mate-sessions.js +134 -0
  326. package/lib/public/modules/contextual-search.js +137 -0
  327. package/lib/public/modules/contextual-session-citations.js +58 -0
  328. package/lib/public/modules/debate.js +1 -0
  329. package/lib/public/modules/default-ai.js +11 -3
  330. package/lib/public/modules/elicitation-form.js +5 -0
  331. package/lib/public/modules/filebrowser.js +20 -1
  332. package/lib/public/modules/generation-stop.js +8 -5
  333. package/lib/public/modules/git-panel.js +3 -1
  334. package/lib/public/modules/github-star.js +66 -0
  335. package/lib/public/modules/history-replay-batch.js +13 -1
  336. package/lib/public/modules/home-debate-live.js +2 -0
  337. package/lib/public/modules/home-debate-planning.js +7 -7
  338. package/lib/public/modules/home-mate-avatar-editor.js +127 -208
  339. package/lib/public/modules/home-mate-chat.js +8 -6
  340. package/lib/public/modules/home-mate-creation.js +73 -1
  341. package/lib/public/modules/home-mate-settings.js +19 -12
  342. package/lib/public/modules/icon-strip-tooltip.js +2 -1
  343. package/lib/public/modules/input.js +88 -10
  344. package/lib/public/modules/issues-render.js +3 -2
  345. package/lib/public/modules/knowledge-db-workbench.js +4 -4
  346. package/lib/public/modules/markdown.js +6 -34
  347. package/lib/public/modules/mate-avatar-catalog.js +97 -0
  348. package/lib/public/modules/mate-knowledge-workbench.js +1 -1
  349. package/lib/public/modules/mate-loading-scene.js +17 -0
  350. package/lib/public/modules/mate-management.js +40 -7
  351. package/lib/public/modules/mcp-connection-view.js +31 -13
  352. package/lib/public/modules/mcp-discovery-view.js +31 -0
  353. package/lib/public/modules/mcp-ui.js +23 -4
  354. package/lib/public/modules/mention.js +3 -0
  355. package/lib/public/modules/message-delivery.js +20 -2
  356. package/lib/public/modules/model-picker.js +2 -0
  357. package/lib/public/modules/pane-activation.js +214 -0
  358. package/lib/public/modules/pane-binding.js +82 -0
  359. package/lib/public/modules/pane-bridge.js +7 -4
  360. package/lib/public/modules/pane-browser-bridge.js +22 -0
  361. package/lib/public/modules/pane-file-bridge.js +4 -0
  362. package/lib/public/modules/pane-issue-bridge.js +4 -1
  363. package/lib/public/modules/pending-message-queue.js +1 -0
  364. package/lib/public/modules/permission-control.js +5 -4
  365. package/lib/public/modules/personal-settings-dialog.js +7 -1
  366. package/lib/public/modules/product-review.js +26 -0
  367. package/lib/public/modules/profile.js +12 -241
  368. package/lib/public/modules/project-access-recovery.js +17 -0
  369. package/lib/public/modules/project-admin-overview.js +21 -0
  370. package/lib/public/modules/project-chat-identity.js +13 -4
  371. package/lib/public/modules/project-logs-render.js +3 -0
  372. package/lib/public/modules/project-mate-creation-workspace.js +13 -4
  373. package/lib/public/modules/project-mate-navigation.js +144 -22
  374. package/lib/public/modules/project-session-visibility-settings.js +19 -16
  375. package/lib/public/modules/project-settings.js +119 -129
  376. package/lib/public/modules/project-start-dialog.js +130 -0
  377. package/lib/public/modules/project-start-folder-state.js +78 -0
  378. package/lib/public/modules/project-start-folder-view.js +190 -0
  379. package/lib/public/modules/project-start-forms.js +66 -0
  380. package/lib/public/modules/project-start-path.js +60 -0
  381. package/lib/public/modules/project-start-state.js +54 -0
  382. package/lib/public/modules/project-start-submit.js +67 -0
  383. package/lib/public/modules/projects-hub-view.js +33 -14
  384. package/lib/public/modules/projects-hub.js +10 -6
  385. package/lib/public/modules/rewind.js +5 -0
  386. package/lib/public/modules/scheduled-tasks.js +2 -0
  387. package/lib/public/modules/scheduler.js +2 -0
  388. package/lib/public/modules/search-clay-chat.js +5 -440
  389. package/lib/public/modules/server-settings.js +36 -91
  390. package/lib/public/modules/session-actions.js +5 -2
  391. package/lib/public/modules/session-context-menu.js +5 -0
  392. package/lib/public/modules/session-create-form.js +10 -10
  393. package/lib/public/modules/session-folder-layout.js +1 -1
  394. package/lib/public/modules/session-folder-view-menu.js +9 -0
  395. package/lib/public/modules/session-github.js +85 -14
  396. package/lib/public/modules/session-rich-drafts.js +21 -0
  397. package/lib/public/modules/session-switch-defer.js +67 -0
  398. package/lib/public/modules/session-work-primary.js +51 -0
  399. package/lib/public/modules/settings-defaults.js +27 -28
  400. package/lib/public/modules/settings-project-target.js +56 -0
  401. package/lib/public/modules/settings-select.js +1 -1
  402. package/lib/public/modules/settings-shell-registry.js +88 -0
  403. package/lib/public/modules/settings-shell-view.js +104 -0
  404. package/lib/public/modules/settings-shell.js +342 -0
  405. package/lib/public/modules/shared-browser-settings.js +112 -0
  406. package/lib/public/modules/shared-browser-tabs.js +13 -3
  407. package/lib/public/modules/shared-browser.js +29 -6
  408. package/lib/public/modules/sidebar-mobile.js +12 -33
  409. package/lib/public/modules/sidebar-projects.js +3 -1
  410. package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
  411. package/lib/public/modules/sidebar-sessions.js +1 -0
  412. package/lib/public/modules/split-group-restore.js +68 -0
  413. package/lib/public/modules/split-pair-ui.js +1 -0
  414. package/lib/public/modules/split-pane-reconciler.js +15 -0
  415. package/lib/public/modules/split-pane-renderer.js +87 -6
  416. package/lib/public/modules/split-session-boundary.js +1 -1
  417. package/lib/public/modules/split-view.js +60 -68
  418. package/lib/public/modules/sticky-note-markdown.js +72 -6
  419. package/lib/public/modules/sticky-notes-actions.js +30 -0
  420. package/lib/public/modules/sticky-notes-browser.js +9 -2
  421. package/lib/public/modules/sticky-notes-card.js +23 -7
  422. package/lib/public/modules/sticky-notes-checklist.js +116 -0
  423. package/lib/public/modules/sticky-notes-editor.js +108 -44
  424. package/lib/public/modules/sticky-notes-shared.js +50 -2
  425. package/lib/public/modules/sticky-notes-state.js +66 -0
  426. package/lib/public/modules/sticky-notes.js +34 -51
  427. package/lib/public/modules/stt-controller.js +4 -1
  428. package/lib/public/modules/stt-recording.js +1 -1
  429. package/lib/public/modules/stt.js +7 -2
  430. package/lib/public/modules/terminal.js +9 -0
  431. package/lib/public/modules/theme.js +18 -3
  432. package/lib/public/modules/thinking-lifecycle.js +33 -3
  433. package/lib/public/modules/thinking-view.js +23 -1
  434. package/lib/public/modules/tools.js +60 -11
  435. package/lib/public/modules/tui-grab.js +1 -2
  436. package/lib/public/modules/user-settings-appearance.js +10 -3
  437. package/lib/public/modules/user-settings-editors.js +1 -1
  438. package/lib/public/modules/user-settings-layout.js +14 -30
  439. package/lib/public/modules/user-settings-preferences.js +6 -2
  440. package/lib/public/modules/user-settings-profile.js +13 -3
  441. package/lib/public/modules/user-settings.js +18 -84
  442. package/lib/public/modules/vendor-login-browser.js +5 -3
  443. package/lib/public/modules/vendor-login.js +2 -2
  444. package/lib/public/modules/vendor-priority.js +15 -1
  445. package/lib/public/modules/vendor-usage-format.js +93 -0
  446. package/lib/public/modules/vendor-usage-list.js +45 -0
  447. package/lib/public/modules/vendor-usage-model.js +215 -0
  448. package/lib/public/modules/vendor-usage-overview.js +312 -0
  449. package/lib/public/modules/wireframe-workbench.js +5 -2
  450. package/lib/public/muse-avatar.svg +4 -0
  451. package/lib/public/style.css +14 -6
  452. package/lib/public/sw.js +3 -1
  453. package/lib/public/welcome-art/conversation-desk.png +0 -0
  454. package/lib/public/welcome-art/mate-clay.png +0 -0
  455. package/lib/public/welcome-art/project-clay.png +0 -0
  456. package/lib/safe-bash-commands.js +3 -45
  457. package/lib/scheduled-task-records.js +3 -1
  458. package/lib/scheduler.js +2 -0
  459. package/lib/sdk-bridge.js +348 -402
  460. package/lib/sdk-foreground-admission.js +16 -0
  461. package/lib/sdk-mcp-descriptors.js +2 -37
  462. package/lib/sdk-message-processor.js +61 -18
  463. package/lib/sdk-quota-snapshot.js +21 -3
  464. package/lib/sdk-response-recovery.js +1 -0
  465. package/lib/sdk-worker.js +2 -677
  466. package/lib/server-admin.js +63 -16
  467. package/lib/server-appearance-settings.js +13 -1
  468. package/lib/server-contextual-clay-settings.js +40 -0
  469. package/lib/server-contextual-mate-sessions.js +70 -0
  470. package/lib/server-dm.js +2 -1
  471. package/lib/server-github-stars.js +39 -0
  472. package/lib/server-global-ws.js +26 -32
  473. package/lib/server-home-chat-events.js +18 -4
  474. package/lib/server-home-chat.js +22 -20
  475. package/lib/server-home-clay-entry.js +23 -4
  476. package/lib/server-home-clay-session-links.js +29 -9
  477. package/lib/server-home-mate-creation.js +1 -0
  478. package/lib/server-home-mcp-consent.js +14 -0
  479. package/lib/server-mates.js +25 -62
  480. package/lib/server-owner-ui.js +118 -0
  481. package/lib/server-path-access.js +38 -0
  482. package/lib/server-project-removal.js +22 -0
  483. package/lib/server-settings.js +6 -1
  484. package/lib/server.js +167 -43
  485. package/lib/session-config-transition.js +45 -0
  486. package/lib/session-folders.js +7 -2
  487. package/lib/session-fork-history.js +21 -0
  488. package/lib/session-github.js +9 -2
  489. package/lib/session-hygiene.js +3 -35
  490. package/lib/session-notes-mcp-server.js +26 -4
  491. package/lib/session-notes-writes.js +88 -0
  492. package/lib/session-permission-mode.js +4 -3
  493. package/lib/session-skill-scope.js +11 -0
  494. package/lib/session-visibility.js +25 -10
  495. package/lib/session-work-primary.js +50 -0
  496. package/lib/sessions.js +66 -99
  497. package/lib/shared-browser-cookie-sync.js +32 -0
  498. package/lib/shared-browser-cookies.js +79 -0
  499. package/lib/shared-browser-runtime.js +25 -9
  500. package/lib/shared-browser-storage-sync.js +43 -0
  501. package/lib/shared-browser-storage.js +101 -0
  502. package/lib/shared-browser-tools.js +2 -1
  503. package/lib/shared-browser-worker.js +46 -10
  504. package/lib/terminal-manager.js +65 -6
  505. package/lib/tool-llm.js +1 -1
  506. package/lib/tui-transcript-index.js +1 -132
  507. package/lib/users-contextual-clay-preferences.js +31 -0
  508. package/lib/users-permissions.js +2 -8
  509. package/lib/users.js +7 -0
  510. package/lib/vendor-login-browser.js +1 -11
  511. package/lib/vendor-usage-acp-readers.js +97 -0
  512. package/lib/vendor-usage-capabilities.js +88 -0
  513. package/lib/vendor-usage-http-readers.js +214 -0
  514. package/lib/vendor-usage-metrics.js +47 -0
  515. package/lib/vendor-usage-native-readers.js +106 -0
  516. package/lib/vendor-usage-overview.js +406 -0
  517. package/lib/vendor-usage-service.js +281 -0
  518. package/lib/workspace-assignment-service.js +25 -0
  519. package/lib/workspace-query-access.js +4 -1
  520. package/lib/workspace-query-mcp-server.js +1 -1
  521. package/lib/workspace-query-service.js +13 -2
  522. package/lib/ws-request.js +1 -0
  523. package/lib/ws-schema.js +22 -4
  524. package/lib/yoke/acp-agent-profiles.js +7 -5
  525. package/lib/yoke/adapters/antigravity.js +3 -14
  526. package/lib/yoke/adapters/claude-query-contract.js +9 -0
  527. package/lib/yoke/adapters/claude.js +66 -50
  528. package/lib/yoke/adapters/codex-query-contract.js +25 -0
  529. package/lib/yoke/adapters/codex.js +98 -123
  530. package/lib/yoke/adapters/kiro.js +3 -1
  531. package/lib/yoke/adapters/muse-query-contract.js +7 -0
  532. package/lib/yoke/adapters/muse.js +122 -0
  533. package/lib/yoke/auth-events.js +17 -0
  534. package/lib/yoke/claude-hook-installer.js +272 -0
  535. package/lib/yoke/claude-jsonl-watcher.js +204 -0
  536. package/lib/yoke/claude-maintenance.js +55 -0
  537. package/lib/yoke/claude-permission-patterns.js +53 -0
  538. package/lib/yoke/claude-response-recovery.js +155 -0
  539. package/lib/yoke/claude-transcript-hygiene.js +34 -0
  540. package/lib/yoke/claude-worker-startup.js +28 -0
  541. package/lib/yoke/clay-skill-install.js +33 -0
  542. package/lib/yoke/cli-sessions.js +300 -0
  543. package/lib/yoke/codex-app-server.js +7 -12
  544. package/lib/yoke/codex-dynamic-tool-names.js +80 -0
  545. package/lib/yoke/codex-idle-recovery.js +81 -1
  546. package/lib/yoke/codex-model-catalog.js +37 -3
  547. package/lib/yoke/codex-recovery-admission.js +164 -0
  548. package/lib/yoke/configuration.js +13 -0
  549. package/lib/yoke/discovery.js +70 -0
  550. package/lib/yoke/errors.js +8 -0
  551. package/lib/yoke/host-environment.js +7 -0
  552. package/lib/yoke/index.js +9 -51
  553. package/lib/yoke/interface.js +116 -0
  554. package/lib/yoke/kiro-acp-server.js +5 -5
  555. package/lib/yoke/legacy-sessions.js +89 -0
  556. package/lib/yoke/login-protocol.js +25 -0
  557. package/lib/yoke/maintenance.js +12 -0
  558. package/lib/yoke/mcp-proxy.js +32 -0
  559. package/lib/yoke/mcp-source-adapters.js +91 -0
  560. package/lib/yoke/mcp-source-context.js +42 -0
  561. package/lib/yoke/mcp-source-discovery.js +169 -0
  562. package/lib/yoke/mcp-source-plugins.js +68 -0
  563. package/lib/yoke/mcp-source-restrictions.js +47 -0
  564. package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
  565. package/lib/yoke/model-preferences.js +6 -0
  566. package/lib/yoke/muse-artifacts.js +36 -0
  567. package/lib/yoke/muse-controls.js +50 -0
  568. package/lib/yoke/muse-input.js +64 -0
  569. package/lib/yoke/muse-items.js +157 -0
  570. package/lib/yoke/muse-policy.js +52 -0
  571. package/lib/yoke/muse-query.js +428 -0
  572. package/lib/yoke/muse-runtime.js +211 -0
  573. package/lib/yoke/muse-services.js +92 -0
  574. package/lib/yoke/muse-skills.js +79 -0
  575. package/lib/yoke/muse-turns.js +71 -0
  576. package/lib/yoke/options/acp.js +2 -0
  577. package/lib/yoke/options/antigravity.js +2 -0
  578. package/lib/yoke/options/claude.js +21 -0
  579. package/lib/yoke/options/codex-defaults.js +29 -0
  580. package/lib/yoke/options/codex-settings.js +21 -0
  581. package/lib/yoke/options/codex.js +6 -0
  582. package/lib/yoke/options/kiro-defaults.js +22 -0
  583. package/lib/yoke/options/kiro.js +5 -0
  584. package/lib/yoke/options/muse.js +5 -0
  585. package/lib/yoke/provider-contract.js +5 -0
  586. package/lib/yoke/providers/antigravity-executable.js +8 -0
  587. package/lib/yoke/providers/claude-executable.js +40 -0
  588. package/lib/yoke/providers/claude-model-descriptions.js +34 -0
  589. package/lib/yoke/providers/claude-process.js +97 -0
  590. package/lib/yoke/providers/claude-provision.js +75 -0
  591. package/lib/yoke/providers/codex-errors.js +8 -0
  592. package/lib/yoke/providers/muse-executable.js +17 -0
  593. package/lib/yoke/provisioning.js +6 -0
  594. package/lib/yoke/query-options.js +10 -0
  595. package/lib/yoke/response-recovery.js +41 -0
  596. package/lib/yoke/sdk-mcp-descriptors.js +37 -0
  597. package/lib/yoke/sdk-server-factory.js +7 -0
  598. package/lib/yoke/session-history.js +8 -0
  599. package/lib/yoke/session-tool-transport.js +34 -13
  600. package/lib/yoke/settings.js +23 -0
  601. package/lib/yoke/source-locations.js +4 -0
  602. package/lib/yoke/title-query.js +18 -7
  603. package/lib/yoke/tui-transcript-index.js +132 -0
  604. package/lib/yoke/usage.js +48 -0
  605. package/lib/yoke/user-input.js +13 -0
  606. package/lib/yoke/vendor-registry.js +87 -3
  607. package/package.json +11 -4
  608. package/lib/public/modules/server-settings-navigation.js +0 -39
@@ -0,0 +1,116 @@
1
+ // Plain task controls use Markdown only as the internal persistence format.
2
+ import { iconHtml, refreshIcons } from './icons.js';
3
+ import { getChecklistItems } from './sticky-note-markdown.js';
4
+ import { getNoteUiState, setNoteUiState } from './sticky-notes-shared.js';
5
+ import { mutateChecklist } from './sticky-notes-state.js';
6
+
7
+ export function checklistDraftText(ui) {
8
+ var fields = ui.checklistInputs || {};
9
+ var lines = (ui.text || '').split('\n');
10
+ if (fields.title !== undefined) lines[0] = fields.title;
11
+ getChecklistItems(ui.text).forEach(function (item) {
12
+ if (fields[item.key] !== undefined) {
13
+ var marker = item.text.match(/^\s*(?:[-*+]\s+)?\[([ xX])\]/);
14
+ var checked = ui.checklistState[item.key];
15
+ if (checked === undefined) checked = marker && marker[1].toLowerCase() === 'x';
16
+ lines[item.index + 1] = '- [' + (checked ? 'x' : ' ') + '] ' + fields[item.key];
17
+ }
18
+ });
19
+ if (fields.entry && fields.entry.trim()) {
20
+ if (!lines[0].trim()) lines[0] = 'Checklist';
21
+ lines.push('- [ ] ' + fields.entry.trim());
22
+ }
23
+ return lines.join('\n');
24
+ }
25
+
26
+ export function renderTaskControls(root, id) {
27
+ var ui = getNoteUiState(id);
28
+ var fields = ui.checklistInputs || {};
29
+ var busy = ui.pending.length > 0;
30
+ var active = document.activeElement;
31
+ var focusField = active && root.contains(active) ? active.dataset.taskField : undefined;
32
+ var selection = focusField !== undefined ? [active.selectionStart, active.selectionEnd] : null;
33
+ root.replaceChildren();
34
+ var form = document.createElement('form'); form.className = 'sn-task-form';
35
+ form.setAttribute('aria-label', 'Checklist');
36
+ form.setAttribute('aria-busy', busy ? 'true' : 'false');
37
+ var feedback = document.createElement('span'); feedback.className = 'sn-task-feedback';
38
+ feedback.setAttribute('role', 'status');
39
+ var saveButton = document.createElement('button');
40
+ function updateFeedback() {
41
+ var current = getNoteUiState(id);
42
+ var dirty = checklistDraftText(current) !== current.text;
43
+ feedback.textContent = busy ? 'Saving…' : current.error ? (dirty ? 'Draft kept. ' : 'Not saved. ') + current.error : dirty ? 'Unsaved changes' : 'All changes saved';
44
+ saveButton.disabled = busy || !dirty;
45
+ }
46
+ function input(label, value, key) {
47
+ var control = document.createElement('textarea'); control.rows = 1; control.value = fields[key] !== undefined ? fields[key] : value;
48
+ control.setAttribute('aria-label', label); control.placeholder = label; control.maxLength = 400;
49
+ control.readOnly = busy;
50
+ control.dataset.taskField = key;
51
+ control.onkeydown = function (event) {
52
+ if (event.key === 'Enter' && !event.isComposing) { event.preventDefault(); form.requestSubmit(); }
53
+ };
54
+ control.oninput = function () {
55
+ var current = getNoteUiState(id);
56
+ // A task remains one persisted line; visual wrapping does not split tasks.
57
+ control.value = control.value.replace(/[\r\n]+/g, ' ');
58
+ var draft = Object.assign({}, current.checklistInputs || {}); draft[key] = control.value;
59
+ setNoteUiState(id, { checklistInputs: draft });
60
+ updateFeedback();
61
+ };
62
+ return control;
63
+ }
64
+ var title = input('Checklist title', (ui.text || '').split('\n')[0], 'title'); title.className = 'sn-task-title'; form.appendChild(title);
65
+ var items = getChecklistItems(ui.text);
66
+ var completed = 0;
67
+ var summary = document.createElement('div'); summary.className = 'sn-task-summary';
68
+ form.appendChild(summary);
69
+ items.forEach(function (item, position) {
70
+ var row = document.createElement('div'); row.className = 'sn-task-row';
71
+ var marker = item.text.match(/^\s*(?:[-*+]\s+)?\[([ xX])\]\s*(.*)$/);
72
+ var check = document.createElement('button'); check.type = 'button'; check.className = 'sn-check';
73
+ var checked = ui.checklistState[item.key];
74
+ if (checked === undefined) checked = marker && marker[1].toLowerCase() === 'x';
75
+ check.classList.toggle('checked', !!checked);
76
+ check.innerHTML = '<span class="sn-task-box" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none"><path d="m3.5 8 3 3 6-6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg></span>';
77
+ row.classList.toggle('is-complete', !!checked);
78
+ if (checked) completed++;
79
+ check.setAttribute('role', 'checkbox'); check.setAttribute('aria-checked', checked ? 'true' : 'false'); check.setAttribute('aria-label', 'Complete task ' + (position + 1));
80
+ check.dataset.checklistIndex = item.index; check.dataset.checklistKey = encodeURIComponent(item.key);
81
+ check.disabled = busy;
82
+ var label = input('Task ' + (position + 1), marker ? marker[2] : item.text, item.key);
83
+ var remove = document.createElement('button'); remove.type = 'button'; remove.className = 'sn-task-remove'; remove.innerHTML = iconHtml('x'); remove.setAttribute('aria-label', 'Remove task ' + (position + 1)); remove.disabled = busy;
84
+ remove.onclick = function () {
85
+ var current = getNoteUiState(id); var lines = checklistDraftText(current).split('\n'); lines.splice(item.index + 1, 1);
86
+ save(lines.join('\n'));
87
+ };
88
+ row.append(check, label, remove); form.appendChild(row);
89
+ });
90
+ summary.textContent = items.length ? completed + ' of ' + items.length + ' complete' : 'A little space for what’s next';
91
+ var addRow = document.createElement('div'); addRow.className = 'sn-task-add';
92
+ var plus = document.createElement('span'); plus.className = 'sn-task-plus'; plus.innerHTML = iconHtml('plus'); plus.setAttribute('aria-hidden', 'true');
93
+ var entry = input('New task', '', 'entry'); entry.className = 'sn-task-entry'; entry.placeholder = 'Add a task…';
94
+ addRow.append(plus, entry); form.appendChild(addRow);
95
+ var footer = document.createElement('div'); footer.className = 'sn-task-footer';
96
+ saveButton.type = 'submit'; saveButton.className = 'sn-task-save'; saveButton.textContent = 'Save tasks';
97
+ footer.append(feedback, saveButton); form.appendChild(footer);
98
+ updateFeedback();
99
+ function save(text) {
100
+ var current = getNoteUiState(id);
101
+ if (current.pending.length) return;
102
+ mutateChecklist(id, { checklistEdit: true, checklistSource: current.canonical.text, checklistVersion: current.canonical.updatedAt, text: text });
103
+ }
104
+ form.onsubmit = function (event) { event.preventDefault(); save(checklistDraftText(getNoteUiState(id))); };
105
+ root.appendChild(form); refreshIcons(root);
106
+ if (focusField !== undefined) {
107
+ var controls = form.querySelectorAll('[data-task-field]');
108
+ for (var i = 0; i < controls.length; i++) {
109
+ if (controls[i].dataset.taskField === focusField) {
110
+ controls[i].focus({ preventScroll: true });
111
+ controls[i].setSelectionRange(selection[0], selection[1]);
112
+ break;
113
+ }
114
+ }
115
+ }
116
+ }
@@ -8,7 +8,11 @@
8
8
  import { refreshIcons, iconHtml } from './icons.js';
9
9
  import { extractMarkdown, renderMiniMarkdown } from './sticky-note-markdown.js';
10
10
  import { enhanceClayLogLinks } from './clay-log-links.js';
11
- import { debouncedTextUpdate, syncTitle } from './sticky-notes-shared.js';
11
+ import { debouncedTextUpdate, syncTitle, getNoteUiState, setNoteUiState, subscribeNoteUiState } from './sticky-notes-shared.js';
12
+
13
+ import { renderTaskControls } from './sticky-notes-checklist.js';
14
+ import { requestChecklistMode } from './sticky-notes-actions.js';
15
+ import { mutateChecklist } from './sticky-notes-state.js';
12
16
 
13
17
  var formatToolbarEl = null;
14
18
 
@@ -145,51 +149,112 @@ function positionToolbarAtRange(toolbar, range) {
145
149
  });
146
150
  }
147
151
 
148
- export function setupTextEdit(textarea, rendered, noteId, mdBtn) {
152
+ export function setupTextEdit(textarea, rendered, noteId, mdBtn, checklistBtn, noteData) {
149
153
  var noteEl = textarea.closest(".sticky-note");
150
154
  var mdMode = false;
155
+ var disposed = false;
156
+ var ui = getNoteUiState(noteId, noteData);
157
+ var checklistMode = ui.checklistMode === true;
158
+ var checklistState = ui.checklistState || {};
159
+ var renderedDirty = false;
160
+ var sourceText = ui.text !== undefined ? ui.text : textarea.value;
161
+ textarea.value = sourceText;
162
+
163
+ function renderChecklist() {
164
+ var active = document.activeElement;
165
+ var focusKey = active && rendered.contains(active) && active.dataset ? active.dataset.checklistKey : undefined;
166
+ if (checklistMode) renderTaskControls(rendered, noteId);
167
+ else rendered.innerHTML = renderMiniMarkdown(sourceText, { checklistMode: checklistMode, checklistState: checklistState });
168
+ if (sourceText.trim()) enhanceClayLogLinks(rendered);
169
+ rendered.classList.toggle("is-empty", !checklistMode && !sourceText.trim());
170
+ rendered.contentEditable = checklistMode || getNoteUiState(noteId).pending.length ? "false" : "true";
171
+ if (focusKey !== undefined) {
172
+ var checks = rendered.querySelectorAll("[data-checklist-key]");
173
+ for (var i = 0; i < checks.length; i++) {
174
+ if (checks[i].dataset.checklistKey === focusKey) { checks[i].focus({ preventScroll: true }); break; }
175
+ }
176
+ }
177
+ }
151
178
 
152
179
  function saveRenderedMarkdown() {
153
- var markdown = extractMarkdown(rendered);
154
- textarea.value = markdown;
155
- debouncedTextUpdate(noteId, markdown);
156
- syncTitle(noteEl, markdown);
157
- rendered.classList.toggle("is-empty", !markdown.trim());
180
+ if (checklistMode) return;
181
+ renderedDirty = true;
182
+ sourceText = extractMarkdown(rendered);
183
+ textarea.value = sourceText;
184
+ setNoteUiState(noteId, { text: sourceText, draft: true });
185
+ debouncedTextUpdate(noteId, sourceText);
186
+ syncTitle(noteEl, sourceText);
187
+ rendered.classList.toggle("is-empty", !checklistMode && !sourceText.trim());
158
188
  }
159
189
 
160
190
  function toggleChecklistItem(check) {
161
- var checked = !check.classList.contains("checked");
162
- check.classList.toggle("checked", checked);
163
- check.textContent = checked ? "✓" : "☐";
164
- check.setAttribute("aria-checked", checked ? "true" : "false");
191
+ if (checklistMode && check.dataset.checklistIndex !== undefined) {
192
+ var index = parseInt(check.dataset.checklistIndex, 10);
193
+ var checked = !check.classList.contains("checked");
194
+ mutateChecklist(noteId, { checklistIndex: index, checklistKey: check.dataset.checklistKey || "", checklistSource: sourceText, checklistChecked: checked });
195
+ return;
196
+ }
197
+ var normalChecked = !check.classList.contains("checked");
198
+ check.classList.toggle("checked", normalChecked);
199
+ check.textContent = normalChecked ? "✓" : "☐";
200
+ check.setAttribute("aria-checked", normalChecked ? "true" : "false");
165
201
  saveRenderedMarkdown();
166
202
  }
167
203
 
168
- // MD button: toggle between contenteditable rendered view and raw textarea
204
+ var unsubscribeUiState = subscribeNoteUiState(function (all) {
205
+ var next = all[noteId];
206
+ if (!next) return;
207
+ var changed = next.checklistMode !== checklistMode ||
208
+ (next.text !== undefined && next.text !== sourceText) ||
209
+ next.pending.length !== ui.pending.length ||
210
+ next.checklistInputs !== ui.checklistInputs && !next.checklistInputs ||
211
+ JSON.stringify(next.checklistState || {}) !== JSON.stringify(checklistState || {});
212
+ ui = next;
213
+ checklistMode = next.checklistMode === true;
214
+ checklistState = next.checklistState || {};
215
+ if (next.text !== undefined && next.text !== sourceText) {
216
+ sourceText = next.text;
217
+ textarea.value = sourceText;
218
+ }
219
+ mdBtn.hidden = checklistMode;
220
+ mdBtn.disabled = checklistMode;
221
+ if (checklistMode && mdMode) {
222
+ mdMode = false; textarea.style.display = 'none'; rendered.style.display = ''; mdBtn.classList.remove('active');
223
+ }
224
+ checklistBtn.classList.toggle("active", checklistMode);
225
+ checklistBtn.title = checklistMode ? "Show note" : "Show checklist";
226
+ checklistBtn.setAttribute("aria-label", checklistBtn.title);
227
+ checklistBtn.setAttribute("aria-pressed", checklistMode ? "true" : "false");
228
+ var status = noteEl.querySelector(".sticky-note-save-status");
229
+ if (status) status.textContent = next.error || (next.pending && next.pending.length ? "Saving…" : "");
230
+ if (changed && !mdMode) { renderChecklist(); syncTitle(noteEl, sourceText); }
231
+ });
232
+ noteEl._stickyNoteDispose = function () {
233
+ disposed = true;
234
+ closeFormatToolbar();
235
+ unsubscribeUiState();
236
+ };
237
+
238
+ checklistBtn.addEventListener("click", function (e) {
239
+ e.stopPropagation();
240
+ requestChecklistMode(noteId);
241
+ });
242
+
169
243
  mdBtn.addEventListener("click", function (e) {
170
244
  e.stopPropagation();
245
+ if (checklistMode) return;
171
246
  mdMode = !mdMode;
172
247
  if (mdMode) {
173
- // Switch to raw markdown editing
174
- var md = extractMarkdown(rendered);
175
- textarea.value = md;
248
+ textarea.value = sourceText;
176
249
  textarea.style.display = "";
177
250
  rendered.style.display = "none";
178
251
  mdBtn.classList.add("active");
179
252
  textarea.focus();
180
253
  } else {
181
- // Switch back to contenteditable rendered view
182
- var md = textarea.value;
183
- debouncedTextUpdate(noteId, md);
184
- syncTitle(noteEl, md);
185
- if (md.trim()) {
186
- rendered.innerHTML = renderMiniMarkdown(md);
187
- enhanceClayLogLinks(rendered);
188
- rendered.classList.remove("is-empty");
189
- } else {
190
- rendered.innerHTML = "";
191
- rendered.classList.add("is-empty");
192
- }
254
+ sourceText = textarea.value;
255
+ if (getNoteUiState(noteId).draft) debouncedTextUpdate(noteId, sourceText);
256
+ syncTitle(noteEl, sourceText);
257
+ renderChecklist();
193
258
  textarea.style.display = "none";
194
259
  rendered.style.display = "";
195
260
  mdBtn.classList.remove("active");
@@ -197,11 +262,7 @@ export function setupTextEdit(textarea, rendered, noteId, mdBtn) {
197
262
  }
198
263
  });
199
264
 
200
- // Sync contenteditable changes to textarea (data store) and save
201
- rendered.addEventListener("input", function () {
202
- saveRenderedMarkdown();
203
- });
204
-
265
+ rendered.addEventListener("input", saveRenderedMarkdown);
205
266
  rendered.addEventListener("click", function (e) {
206
267
  var check = e.target.closest && e.target.closest(".sn-check");
207
268
  if (!check || !rendered.contains(check)) return;
@@ -210,27 +271,23 @@ export function setupTextEdit(textarea, rendered, noteId, mdBtn) {
210
271
  toggleChecklistItem(check);
211
272
  });
212
273
 
213
- // On blur, re-render to normalize HTML structure
214
274
  rendered.addEventListener("blur", function (e) {
215
- // Don't re-render if clicking format toolbar (it prevents default, but just in case)
275
+ if (checklistMode || !renderedDirty) return;
276
+ renderedDirty = false;
216
277
  if (e.relatedTarget && e.relatedTarget.closest && e.relatedTarget.closest(".sn-format-toolbar")) return;
217
278
  closeFormatToolbar();
218
279
  var md = extractMarkdown(rendered);
280
+ sourceText = md;
219
281
  textarea.value = md;
220
- if (md.trim()) {
221
- rendered.innerHTML = renderMiniMarkdown(md);
222
- enhanceClayLogLinks(rendered);
223
- rendered.classList.remove("is-empty");
224
- } else {
225
- rendered.innerHTML = "";
226
- rendered.classList.add("is-empty");
227
- }
282
+ setNoteUiState(noteId, { text: sourceText, draft: true });
283
+ renderChecklist();
228
284
  });
229
285
 
230
286
  // Show format toolbar when selecting text
231
287
  rendered.addEventListener("mouseup", function (e) {
232
288
  if (e.target.tagName === "A") return;
233
289
  setTimeout(function () {
290
+ if (disposed) return;
234
291
  var sel = window.getSelection();
235
292
  if (sel && !sel.isCollapsed && sel.toString().trim()) {
236
293
  showFormatToolbar(rendered);
@@ -260,6 +317,7 @@ export function setupTextEdit(textarea, rendered, noteId, mdBtn) {
260
317
  toggleChecklistItem(e.target);
261
318
  return;
262
319
  }
320
+ if (checklistMode) return;
263
321
  if (e.key === "Enter" && !e.shiftKey) {
264
322
  e.preventDefault();
265
323
  document.execCommand("insertLineBreak");
@@ -268,6 +326,7 @@ export function setupTextEdit(textarea, rendered, noteId, mdBtn) {
268
326
 
269
327
  // Paste as plain text to avoid importing HTML formatting
270
328
  rendered.addEventListener("paste", function (e) {
329
+ if (checklistMode) return;
271
330
  e.preventDefault();
272
331
  var text = (e.clipboardData || window.clipboardData).getData("text/plain");
273
332
  document.execCommand("insertText", false, text);
@@ -281,10 +340,15 @@ export function setupTextEdit(textarea, rendered, noteId, mdBtn) {
281
340
  // Sync textarea edits when in MD mode
282
341
  textarea.addEventListener("input", function () {
283
342
  if (!mdMode) return;
284
- debouncedTextUpdate(noteId, textarea.value);
285
- syncTitle(noteEl, textarea.value);
343
+ sourceText = textarea.value;
344
+ setNoteUiState(noteId, { text: sourceText, draft: true });
345
+ debouncedTextUpdate(noteId, sourceText);
346
+ syncTitle(noteEl, sourceText);
286
347
  });
287
348
 
349
+ mdBtn.hidden = checklistMode; mdBtn.disabled = checklistMode;
350
+ renderChecklist();
351
+
288
352
  textarea.addEventListener("mousedown", function (e) {
289
353
  e.stopPropagation();
290
354
  });
@@ -55,8 +55,51 @@ export function clampSize(x, y, w, h) {
55
55
 
56
56
  export function send(obj) {
57
57
  var ws = getWs();
58
- if (!ws || !store.get('connected')) return;
59
- ws.send(JSON.stringify(obj));
58
+ if (!ws || !store.get('connected')) return false;
59
+ try { ws.send(JSON.stringify(obj)); return true; } catch (error) { return false; }
60
+ }
61
+
62
+ export function getNoteUiState(id, fallback) {
63
+ var all = store.get("stickyNoteUiState") || {};
64
+ if (!all[id]) {
65
+ var initial = {
66
+ canonical: Object.assign({}, fallback),
67
+ canonicalRevision: 0,
68
+ draft: false,
69
+ text: fallback && fallback.text ? fallback.text : "",
70
+ checklistMode: fallback && fallback.checklistMode === true,
71
+ checklistState: fallback && fallback.checklistState ? fallback.checklistState : {},
72
+ pending: [],
73
+ };
74
+ var next = Object.assign({}, all);
75
+ next[id] = initial;
76
+ store.set({ stickyNoteUiState: next });
77
+ return initial;
78
+ }
79
+ return all[id];
80
+ }
81
+
82
+ export function setNoteUiState(id, changes) {
83
+ var all = store.get("stickyNoteUiState") || {};
84
+ var current = all[id] || {};
85
+ var next = Object.assign({}, all);
86
+ next[id] = Object.assign({}, current, changes || {});
87
+ store.set({ stickyNoteUiState: next });
88
+ return next[id];
89
+ }
90
+
91
+ export function deleteNoteUiState(id) {
92
+ var all = store.get("stickyNoteUiState") || {};
93
+ if (!all[id]) return;
94
+ var next = Object.assign({}, all);
95
+ delete next[id];
96
+ store.set({ stickyNoteUiState: next });
97
+ }
98
+
99
+ export function subscribeNoteUiState(listener) {
100
+ return store.subscribe(function (next, previous) {
101
+ if (next.stickyNoteUiState !== previous.stickyNoteUiState) listener(next.stickyNoteUiState || {});
102
+ });
60
103
  }
61
104
 
62
105
  export function debouncedUpdate(id, changes, delay) {
@@ -82,6 +125,11 @@ export function syncTitle(noteEl, text) {
82
125
 
83
126
 
84
127
  // Drop any pending writes for a note this client no longer has.
128
+ export function clearNoteTextTimer(id) {
129
+ clearTimeout(textTimers[id]);
130
+ delete textTimers[id];
131
+ }
132
+
85
133
  export function clearNoteTimers(id) {
86
134
  clearTimeout(updateTimers[id]);
87
135
  clearTimeout(textTimers[id]);
@@ -0,0 +1,66 @@
1
+ // Reconcile canonical broadcasts with optimistic checklist actions and text drafts.
2
+ import { store } from './store.js';
3
+ import { getNoteUiState, setNoteUiState, send } from './sticky-notes-shared.js';
4
+
5
+ function project(ui, pending, error) {
6
+ var canonical = ui.canonical || {};
7
+ var text = ui.draft ? ui.text : canonical.text || "";
8
+ var mode = canonical.checklistMode === true;
9
+ var state = Object.assign({}, canonical.checklistState || {});
10
+ pending.forEach(function (request) {
11
+ var changes = request.changes;
12
+ if (changes.text !== undefined) text = changes.text;
13
+ if (changes.checklistMode !== undefined) mode = changes.checklistMode;
14
+ if (changes.checklistKey) state[decodeURIComponent(changes.checklistKey)] = changes.checklistChecked;
15
+ });
16
+ return setNoteUiState(canonical.id, {
17
+ text: text,
18
+ checklistMode: mode, checklistState: state, pending: pending, error: error || '',
19
+ });
20
+ }
21
+
22
+ export function reconcileNote(data) {
23
+ var ui = getNoteUiState(data.id, data);
24
+ var draft = ui.draft && ui.text !== (data.text || '');
25
+ ui = setNoteUiState(data.id, { canonical: data, canonicalRevision: (ui.canonicalRevision || 0) + 1, draft: draft });
26
+ project(ui, ui.pending || [], ui.error);
27
+ }
28
+
29
+ export function mutateChecklist(id, changes) {
30
+ var ui = getNoteUiState(id);
31
+ var requestId = 'note-update-' + Date.now() + '-' + Math.random().toString(36).slice(2);
32
+ var pending = (ui.pending || []).concat([{ requestId: requestId, changes: changes, revision: ui.canonicalRevision, draftText: ui.text }]);
33
+ project(ui, pending, '');
34
+ if (!send(Object.assign({}, changes, { type: changes.humanClose ? 'note_close' : 'note_update', id: id, requestId: requestId }))) {
35
+ project(getNoteUiState(id), pending.slice(0, -1), 'Connection unavailable');
36
+ }
37
+ }
38
+
39
+ export function reconcileNoteResult(msg) {
40
+ var ui = getNoteUiState(msg.noteId);
41
+ var request = (ui.pending || []).find(function (item) { return item.requestId === msg.requestId; });
42
+ if (!request) return;
43
+ // The server broadcasts before acknowledgement. Use the returned note when
44
+ // that broadcast was absent, but never replace a newer remote canonical note.
45
+ if (msg.ok && msg.note && ui.canonicalRevision === request.revision) {
46
+ reconcileNote(msg.note);
47
+ ui = getNoteUiState(msg.noteId);
48
+ }
49
+ if (msg.ok && request.changes.checklistConvert && ui.text === request.draftText) {
50
+ ui = setNoteUiState(msg.noteId, { draft: false, text: ui.canonical.text || '' });
51
+ }
52
+ if (msg.ok && (request.changes.checklistEdit || request.changes.checklistConvert || request.changes.humanClose)) {
53
+ ui = setNoteUiState(msg.noteId, { checklistInputs: null });
54
+ }
55
+ var remaining = ui.pending.filter(function (item) { return item.requestId !== msg.requestId; });
56
+ project(ui, remaining, msg.ok ? '' : msg.error || 'Could not save checklist change');
57
+ return ui.canonical;
58
+ }
59
+
60
+ store.subscribe(function (next, previous) {
61
+ if (next.connected || next.connected === previous.connected) return;
62
+ var all = next.stickyNoteUiState || {};
63
+ Object.keys(all).forEach(function (id) {
64
+ if (all[id].pending && all[id].pending.length) project(all[id], [], 'Connection unavailable');
65
+ });
66
+ });
@@ -1,24 +1,21 @@
1
1
  // The sticky-note canvas: the board of floating cards over the conversation.
2
- //
3
2
  // This module owns the notes map, visibility, the badges, and the WebSocket
4
3
  // handlers. Card markup and interactions live in sticky-notes-card.js, text
5
- // editing in sticky-notes-editor.js, and the leaf helpers in
4
+ // editing in sticky-notes-editor.js, and leaf helpers in
6
5
  // sticky-notes-shared.js. The browse/index pane is sticky-notes-browser.js.
7
6
 
8
7
  import { refreshIcons, iconHtml } from './icons.js';
9
- import { renderMiniMarkdown } from './sticky-note-markdown.js';
10
- import { enhanceClayLogLinks } from './clay-log-links.js';
11
- import { isClosedNote, send, clampPos, clearNoteTimers, syncTitle } from './sticky-notes-shared.js';
8
+ import { isClosedNote, send, clampPos, clearNoteTimers, deleteNoteUiState } from './sticky-notes-shared.js';
12
9
  import { renderNote, closeColorPicker } from './sticky-notes-card.js';
13
10
  import { closeFormatToolbar, isFormatToolbarOpen } from './sticky-notes-editor.js';
14
11
  import { store } from './store.js';
12
+ import { reconcileNote, reconcileNoteResult } from './sticky-notes-state.js';
15
13
 
16
14
  var notes = new Map(); // id -> { data, el }
17
15
  var notesVisible = false;
18
16
  var notesResizeObserver = null;
19
17
 
20
- // The canvas shows open notes only. Closed notes leave the canvas and live in
21
- // the browser's Closed tab until they are reopened.
18
+ // The canvas shows open notes only. Closed notes live in the browser's Closed tab.
22
19
  function openCount() {
23
20
  var count = 0;
24
21
  notes.forEach(function (entry) {
@@ -259,9 +256,7 @@ export function handleNotesList(msg) {
259
256
  var container = document.getElementById("sticky-notes-container");
260
257
  if (!container) return;
261
258
 
262
- // Keyed reconciliation, never a clear-and-rebuild. A reconnect re-sends this
263
- // list unchanged; tearing every note down and recreating it made all the
264
- // floating cards vanish and reappear, and destroyed any open editor.
259
+ // Reconcile keyed cards in place so reconnects retain the active editor.
265
260
  var list = msg.notes || [];
266
261
  var seen = {};
267
262
  var created = false;
@@ -283,28 +278,27 @@ export function handleNotesList(msg) {
283
278
  created = true;
284
279
  }
285
280
 
286
- // Remove notes the server no longer lists.
281
+ // Remove subscriptions and delayed writes along with stale cards.
287
282
  var staleIds = [];
288
283
  notes.forEach(function (value, id) {
289
284
  if (!seen[id]) staleIds.push(id);
290
285
  });
291
286
  for (i = 0; i < staleIds.length; i++) {
292
287
  var stale = notes.get(staleIds[i]);
288
+ if (stale && stale.el && stale.el._stickyNoteDispose) stale.el._stickyNoteDispose();
293
289
  if (stale && stale.el && stale.el.parentNode) stale.el.parentNode.removeChild(stale.el);
290
+ clearNoteTimers(staleIds[i]);
291
+ deleteNoteUiState(staleIds[i]);
294
292
  notes.delete(staleIds[i]);
295
293
  }
296
294
 
297
- // renderNote already refreshes icons for the nodes it builds; an all-patch
298
- // pass introduces no new Lucide markup and must not trigger a document scan.
295
+ // An all-patch list adds no icon markup and needs no document-wide scan.
299
296
  if (created) refreshIcons();
300
297
 
301
298
  updateBadge();
302
299
  updateSidebarBadge();
303
300
  refreshBrowser();
304
301
 
305
- // Auto-show only when something is actually asking for attention. A board of
306
- // nothing but closed notes must not pop the canvas open. Temporary hiding is
307
- // explicit view state and must survive reconnects and list updates.
308
302
  if (openCount() > 0 && !notesVisible) {
309
303
  notesVisible = true;
310
304
  applyCanvasVisibility();
@@ -337,18 +331,13 @@ export function handleNoteCreated(msg) {
337
331
  syncFlightControls();
338
332
  }
339
333
 
340
- // Patch one existing note element in place from a server payload.
341
- //
342
- // Geometry, z-order, colour, and opacity are plain style writes and are always
343
- // applied. The rendered markdown is only replaced when the text actually
344
- // changed and the note is not being edited, so a geometry-only or z-only
345
- // update never destroys the user's caret, selection, or in-progress draft.
346
- // Returns true when icon markup was replaced, so the caller can decide whether
347
- // a Lucide pass is needed at all.
334
+ // Canonical content reconciles through the store; geometry patches independently
335
+ // so movement and stacking updates preserve the editor and its draft.
336
+ // Return whether the minimize control introduced fresh icon markup.
348
337
  function patchNote(entry, next) {
349
338
  if (!entry || !next) return false;
350
- var previous = entry.data || {};
351
339
  entry.data = next;
340
+ reconcileNote(next);
352
341
  var el = entry.el;
353
342
 
354
343
  el.style.left = next.x + "px";
@@ -358,26 +347,6 @@ function patchNote(entry, next) {
358
347
  el.style.zIndex = 100 + (next.zIndex || 0);
359
348
  el.dataset.color = next.color || "purple";
360
349
 
361
- var textarea = el.querySelector(".sticky-note-text");
362
- var rendered = el.querySelector(".sticky-note-rendered");
363
- var nextText = next.text || "";
364
- var editing = rendered === document.activeElement || textarea === document.activeElement;
365
- // A draft the user typed but has not committed must survive a redraw.
366
- var hasDraft = !!(textarea && textarea.value !== (previous.text || ""));
367
- var textChanged = nextText !== (previous.text || "");
368
- if (rendered && !editing && !hasDraft && textChanged) {
369
- if (textarea) textarea.value = nextText;
370
- if (nextText.trim()) {
371
- rendered.innerHTML = renderMiniMarkdown(nextText);
372
- enhanceClayLogLinks(rendered);
373
- rendered.classList.remove("is-empty");
374
- } else {
375
- rendered.innerHTML = "";
376
- rendered.classList.add("is-empty");
377
- }
378
- syncTitle(el, nextText);
379
- }
380
-
381
350
  if (typeof next.opacity === "number") {
382
351
  el.style.setProperty("--note-opacity", next.opacity);
383
352
  var slider = el.querySelector(".sticky-note-opacity-slider");
@@ -388,8 +357,6 @@ function patchNote(entry, next) {
388
357
  else el.classList.remove("hidden");
389
358
  syncFlightState(el, true);
390
359
 
391
- // The minimize button swaps its icon, which is the only path here that can
392
- // introduce fresh Lucide markup.
393
360
  var iconsReplaced = false;
394
361
  var wasMinimized = el.classList.contains("minimized");
395
362
  var minBtn = el.querySelector(".sticky-note-min-btn");
@@ -419,13 +386,18 @@ export function handleNoteUpdated(msg) {
419
386
  if (patchNote(entry, msg.note)) refreshIcons();
420
387
  reclampAllNotes();
421
388
 
422
- // A close or reopen arrives as an ordinary update, so the canvas count and
423
- // the browser both follow from the same message.
424
389
  updateBadge();
425
390
  updateSidebarBadge();
426
391
  refreshBrowser();
427
392
  }
428
393
 
394
+ export function handleNoteUpdateResult(msg) {
395
+ var entry = notes.get(msg.noteId);
396
+ if (!entry || !msg.requestId) return;
397
+ var canonical = reconcileNoteResult(msg);
398
+ if (canonical) { entry.data = canonical; refreshBrowser(); }
399
+ }
400
+
429
401
  export function handleNoteWritten(msg) {
430
402
  var entry = notes.get(msg.id);
431
403
  if (!entry) return;
@@ -437,11 +409,11 @@ export function handleNoteWritten(msg) {
437
409
  }, 2100);
438
410
  }
439
411
 
440
- // Defensive only. The server no longer deletes notes and never sends this, but
441
- // an older daemon on the other end of the socket still must not corrupt state.
442
412
  export function handleNoteDeleted(msg) {
443
413
  var entry = notes.get(msg.id);
414
+ if (entry && entry.el._stickyNoteDispose) entry.el._stickyNoteDispose();
444
415
  if (entry) entry.el.remove();
416
+ deleteNoteUiState(msg.id);
445
417
  clearNoteTimers(msg.id);
446
418
  notes.delete(msg.id);
447
419
  updateBadge();
@@ -467,3 +439,14 @@ function updateSidebarBadge() {
467
439
  export function isNotesVisible() {
468
440
  return notesVisible;
469
441
  }
442
+
443
+ // Project navigation must cancel writes and detach subscriptions before reuse.
444
+ export function resetStickyNotes() {
445
+ handleNotesList({ notes: [] });
446
+ closeFormatToolbar();
447
+ closeColorPicker();
448
+ }
449
+
450
+ store.subscribe(function (next, previous) {
451
+ if (next.currentSlug !== previous.currentSlug) resetStickyNotes();
452
+ });