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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (588) hide show
  1. package/lib/account-auth-policy.js +21 -0
  2. package/lib/account-auth-socket.js +30 -0
  3. package/lib/account-auth-throttle.js +44 -0
  4. package/lib/account-auth-transport.js +48 -0
  5. package/lib/account-login-page.js +28 -0
  6. package/lib/account-passkey-challenges.js +31 -0
  7. package/lib/account-passkey-page.js +89 -0
  8. package/lib/account-passkey-policy.js +39 -0
  9. package/lib/account-password-page.js +69 -0
  10. package/lib/account-passwords.js +36 -0
  11. package/lib/account-remembered.js +77 -0
  12. package/lib/account-session-page.js +51 -0
  13. package/lib/account-session-store.js +82 -0
  14. package/lib/builtin-mates.js +19 -16
  15. package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
  16. package/lib/canonical-clay-record-authority.js +15 -0
  17. package/lib/canonical-clay-scheduling-authority.js +19 -0
  18. package/lib/claude-hook-installer.js +1 -239
  19. package/lib/claude-jsonl-watcher.js +1 -204
  20. package/lib/clay-control-presentation-binding.js +96 -0
  21. package/lib/clay-control-presentation.js +128 -0
  22. package/lib/clay-control-target-projection.js +26 -0
  23. package/lib/clay-mate-chat-receipts.js +26 -0
  24. package/lib/clay-mate-chat.js +88 -0
  25. package/lib/clay-mate-knowledge-input.js +26 -0
  26. package/lib/clay-mate-knowledge.js +95 -0
  27. package/lib/clay-mate-lifecycle.js +95 -0
  28. package/lib/clay-product-control-input.js +33 -0
  29. package/lib/clay-product-control-tools.js +51 -0
  30. package/lib/clay-product-control.js +247 -0
  31. package/lib/clay-project-lifecycle.js +154 -0
  32. package/lib/clay-project-record-input.js +44 -0
  33. package/lib/clay-project-records.js +84 -0
  34. package/lib/clay-scheduling-input.js +21 -0
  35. package/lib/clay-scheduling-receipts.js +26 -0
  36. package/lib/clay-scheduling.js +119 -0
  37. package/lib/clay-screen-controls.js +104 -0
  38. package/lib/clay-skill-install.js +1 -33
  39. package/lib/clay-workspace-controls.js +84 -0
  40. package/lib/clay-workspace-input.js +17 -0
  41. package/lib/clay-workspace-receipts.js +26 -0
  42. package/lib/cli-sessions.js +1 -300
  43. package/lib/codex-defaults.js +1 -28
  44. package/lib/context-usage.js +3 -2
  45. package/lib/contextual-screen-snapshot.js +38 -0
  46. package/lib/daemon-project-access.js +11 -0
  47. package/lib/daemon-project-lifecycle-callbacks.js +15 -0
  48. package/lib/daemon-project-lifecycle.js +262 -0
  49. package/lib/daemon-projects.js +1 -1
  50. package/lib/daemon.js +80 -276
  51. package/lib/default-ai-runtime.js +4 -8
  52. package/lib/dm-digest-cursor.js +120 -0
  53. package/lib/email-mcp-server.js +1 -1
  54. package/lib/issues-service.js +29 -15
  55. package/lib/kiro-defaults.js +1 -22
  56. package/lib/knowledge-db-import-validation.js +46 -0
  57. package/lib/knowledge-db-import.js +99 -0
  58. package/lib/knowledge-db-service.js +24 -33
  59. package/lib/knowledge-db-storage-nedb-maintenance.js +99 -0
  60. package/lib/knowledge-db-storage-nedb.js +66 -0
  61. package/lib/knowledge-db-storage.js +72 -0
  62. package/lib/knowledge-db-validation.js +0 -0
  63. package/lib/knowledge-document-index.js +2 -1
  64. package/lib/knowledge-file-store.js +7 -1
  65. package/lib/knowledge-product-operations.js +46 -0
  66. package/lib/mate-avatar-catalog.js +12 -0
  67. package/lib/mate-avatar-migration.js +41 -0
  68. package/lib/mate-context-service.js +138 -0
  69. package/lib/mate-context-tools.js +21 -0
  70. package/lib/mate-creation-mcp-server.js +2 -0
  71. package/lib/mate-knowledge-canonical-access.js +10 -0
  72. package/lib/mate-knowledge-mate-bound.js +53 -0
  73. package/lib/mate-knowledge-mcp-server.js +55 -8
  74. package/lib/mate-knowledge-service.js +16 -34
  75. package/lib/mate-knowledge-text-tools.js +106 -0
  76. package/lib/mate-lifecycle-service.js +94 -0
  77. package/lib/mate-message-delivery.js +43 -0
  78. package/lib/mate-ready-creation.js +9 -1
  79. package/lib/mate-schedule-input.js +29 -0
  80. package/lib/mate-schedule-lifecycle.js +151 -0
  81. package/lib/mate-scheduling.js +103 -0
  82. package/lib/mates.js +18 -6
  83. package/lib/mcp-agent-tools.js +117 -0
  84. package/lib/mcp-connection-store.js +119 -15
  85. package/lib/mcp-import-credentials.js +31 -0
  86. package/lib/mcp-local-transport.js +13 -0
  87. package/lib/mcp-oauth.js +8 -6
  88. package/lib/mcp-proxy.js +2 -32
  89. package/lib/mcp-query-bridge.js +30 -0
  90. package/lib/mcp-remote-connections.js +74 -20
  91. package/lib/mcp-source-adapters.js +1 -0
  92. package/lib/mcp-source-context.js +1 -0
  93. package/lib/mcp-source-discovery.js +1 -0
  94. package/lib/mcp-source-plugins.js +1 -0
  95. package/lib/mcp-source-restrictions.js +1 -0
  96. package/lib/mcp-tool-policy.js +9 -0
  97. package/lib/migrate-single-user.js +3 -23
  98. package/lib/notes-checklist.js +50 -0
  99. package/lib/notes.js +49 -3
  100. package/lib/os-user-diagnostics.js +2 -4
  101. package/lib/os-users.js +24 -70
  102. package/lib/pane-pending-interactions.js +20 -0
  103. package/lib/pane-session-activation.js +114 -0
  104. package/lib/pane-session-transport.js +26 -0
  105. package/lib/project-admin-overview.js +51 -0
  106. package/lib/project-ask-user.js +8 -4
  107. package/lib/project-connection.js +14 -10
  108. package/lib/project-control-git-view.js +12 -0
  109. package/lib/project-debate.js +1 -0
  110. package/lib/project-delegated-follow-up.js +2 -1
  111. package/lib/project-directory-claim.js +65 -0
  112. package/lib/project-file-operations.js +61 -0
  113. package/lib/project-filesystem.js +15 -85
  114. package/lib/project-full-access.js +23 -2
  115. package/lib/project-http.js +7 -4
  116. package/lib/project-knowledge.js +32 -18
  117. package/lib/project-lifecycle-operations.js +98 -0
  118. package/lib/project-lifecycle-process-witness.js +32 -0
  119. package/lib/project-lifecycle-runtime.js +50 -0
  120. package/lib/project-linux-access.js +22 -0
  121. package/lib/project-logs-canonical-clay.js +27 -0
  122. package/lib/project-logs-clay-query.js +16 -0
  123. package/lib/project-logs-schema.js +4 -2
  124. package/lib/project-logs-service.js +8 -7
  125. package/lib/project-logs.js +1 -0
  126. package/lib/project-loop.js +1 -0
  127. package/lib/project-mate-chat-control.js +55 -0
  128. package/lib/project-mate-creation-proposal.js +18 -3
  129. package/lib/project-mate-interaction.js +40 -62
  130. package/lib/project-mcp.js +54 -16
  131. package/lib/project-models.js +14 -31
  132. package/lib/project-notifications.js +76 -17
  133. package/lib/project-ownership.js +77 -0
  134. package/lib/project-pair-result-delivery.js +14 -3
  135. package/lib/project-pair-usage.js +12 -13
  136. package/lib/project-pending-message-queue.js +4 -1
  137. package/lib/project-product-control.js +89 -0
  138. package/lib/project-product-session-queue.js +46 -0
  139. package/lib/project-push-access.js +28 -0
  140. package/lib/project-scheduled-message-queue.js +30 -0
  141. package/lib/project-scheduled-messages.js +67 -68
  142. package/lib/project-scheduled-task-control.js +83 -0
  143. package/lib/project-scheduled-tasks.js +13 -2
  144. package/lib/project-scheduling-access.js +10 -0
  145. package/lib/project-server-settings.js +1 -0
  146. package/lib/project-session-actions.js +65 -0
  147. package/lib/project-session-delete.js +8 -1
  148. package/lib/project-session-document.js +27 -7
  149. package/lib/project-session-github.js +63 -19
  150. package/lib/project-session-history-actions.js +167 -0
  151. package/lib/project-session-linear.js +14 -6
  152. package/lib/project-session-notes.js +7 -3
  153. package/lib/project-session-pair.js +1 -1
  154. package/lib/project-session-runtime-actions.js +64 -0
  155. package/lib/project-session-spawn.js +2 -3
  156. package/lib/project-session-vendor.js +55 -0
  157. package/lib/project-sessions.js +103 -272
  158. package/lib/project-shared-browser.js +78 -17
  159. package/lib/project-studio-presentation.js +58 -0
  160. package/lib/project-user-knowledge.js +2 -1
  161. package/lib/project-user-message.js +67 -1
  162. package/lib/project-vendor-login.js +6 -36
  163. package/lib/project-workspace-operations.js +126 -0
  164. package/lib/project-workspace-query.js +19 -2
  165. package/lib/project.js +178 -45
  166. package/lib/public/app.js +46 -0
  167. package/lib/public/appearance-bootstrap.js +16 -0
  168. package/lib/public/auth/account-login.css +98 -0
  169. package/lib/public/auth/account-login.js +104 -0
  170. package/lib/public/css/clay-tool-activity.css +51 -0
  171. package/lib/public/css/clay-workspace.css +29 -0
  172. package/lib/public/css/command-palette.css +12 -33
  173. package/lib/public/css/contextual-clay.css +240 -0
  174. package/lib/public/css/home-debate-planning.css +2 -0
  175. package/lib/public/css/home-mate-creation.css +5 -0
  176. package/lib/public/css/input.css +6 -0
  177. package/lib/public/css/mate-avatar-gallery.css +12 -0
  178. package/lib/public/css/mate-conversation.css +10 -5
  179. package/lib/public/css/messages.css +6 -2
  180. package/lib/public/css/overlays.css +4 -2
  181. package/lib/public/css/project-admin-overview.css +13 -0
  182. package/lib/public/css/session-folders.css +11 -0
  183. package/lib/public/css/session-github.css +46 -1
  184. package/lib/public/css/shared-browser.css +35 -1
  185. package/lib/public/css/sticky-notes.css +87 -1
  186. package/lib/public/css/user-settings-sessions.css +42 -0
  187. package/lib/public/index.html +28 -10
  188. package/lib/public/mate-avatars/B01.png +0 -0
  189. package/lib/public/mate-avatars/B02.png +0 -0
  190. package/lib/public/mate-avatars/B03.png +0 -0
  191. package/lib/public/mate-avatars/B04.png +0 -0
  192. package/lib/public/mate-avatars/B05.png +0 -0
  193. package/lib/public/mate-avatars/B06.png +0 -0
  194. package/lib/public/mate-avatars/B07.png +0 -0
  195. package/lib/public/mate-avatars/B08.png +0 -0
  196. package/lib/public/mate-avatars/B09.png +0 -0
  197. package/lib/public/mate-avatars/B10.png +0 -0
  198. package/lib/public/mate-avatars/B11.png +0 -0
  199. package/lib/public/mate-avatars/B12.png +0 -0
  200. package/lib/public/mate-avatars/B13.png +0 -0
  201. package/lib/public/mate-avatars/B14.png +0 -0
  202. package/lib/public/mate-avatars/B15.png +0 -0
  203. package/lib/public/mate-avatars/B16.png +0 -0
  204. package/lib/public/mate-avatars/B17.png +0 -0
  205. package/lib/public/mate-avatars/B18.png +0 -0
  206. package/lib/public/mate-avatars/B19.png +0 -0
  207. package/lib/public/mate-avatars/B20.png +0 -0
  208. package/lib/public/mate-avatars/B21.png +0 -0
  209. package/lib/public/mate-avatars/B22.png +0 -0
  210. package/lib/public/mate-avatars/B23.png +0 -0
  211. package/lib/public/mate-avatars/B24.png +0 -0
  212. package/lib/public/mate-avatars/B25.png +0 -0
  213. package/lib/public/mate-avatars/B26.png +0 -0
  214. package/lib/public/mate-avatars/B27.png +0 -0
  215. package/lib/public/mate-avatars/B28.png +0 -0
  216. package/lib/public/mate-avatars/B29.png +0 -0
  217. package/lib/public/mate-avatars/B30.png +0 -0
  218. package/lib/public/mate-avatars/B31.png +0 -0
  219. package/lib/public/mate-avatars/B32.png +0 -0
  220. package/lib/public/mate-avatars/B33.png +0 -0
  221. package/lib/public/mate-avatars/B34.png +0 -0
  222. package/lib/public/mate-avatars/B35.png +0 -0
  223. package/lib/public/mate-avatars/B36.png +0 -0
  224. package/lib/public/mate-avatars/B37.png +0 -0
  225. package/lib/public/mate-avatars/B38.png +0 -0
  226. package/lib/public/mate-avatars/B39.png +0 -0
  227. package/lib/public/mate-avatars/B40.png +0 -0
  228. package/lib/public/mate-avatars/B41.png +0 -0
  229. package/lib/public/mate-avatars/B42.png +0 -0
  230. package/lib/public/mate-avatars/B43.png +0 -0
  231. package/lib/public/mate-avatars/B44.png +0 -0
  232. package/lib/public/mate-avatars/B45.png +0 -0
  233. package/lib/public/mate-avatars/B46.png +0 -0
  234. package/lib/public/mate-avatars/B47.png +0 -0
  235. package/lib/public/mate-avatars/B48.png +0 -0
  236. package/lib/public/mate-avatars/C01.png +0 -0
  237. package/lib/public/mate-avatars/C02.png +0 -0
  238. package/lib/public/mate-avatars/C03.png +0 -0
  239. package/lib/public/mate-avatars/C04.png +0 -0
  240. package/lib/public/mate-avatars/C05.png +0 -0
  241. package/lib/public/mate-avatars/C06.png +0 -0
  242. package/lib/public/mate-avatars/C07.png +0 -0
  243. package/lib/public/mate-avatars/C08.png +0 -0
  244. package/lib/public/mate-avatars/C09.png +0 -0
  245. package/lib/public/mate-avatars/C10.png +0 -0
  246. package/lib/public/mate-avatars/C11.png +0 -0
  247. package/lib/public/mate-avatars/C12.png +0 -0
  248. package/lib/public/mate-avatars/C13.png +0 -0
  249. package/lib/public/mate-avatars/C14.png +0 -0
  250. package/lib/public/mate-avatars/C15.png +0 -0
  251. package/lib/public/mate-avatars/C16.png +0 -0
  252. package/lib/public/mate-avatars/C17.png +0 -0
  253. package/lib/public/mate-avatars/C18.png +0 -0
  254. package/lib/public/mate-avatars/C19.png +0 -0
  255. package/lib/public/mate-avatars/C20.png +0 -0
  256. package/lib/public/mate-avatars/C21.png +0 -0
  257. package/lib/public/mate-avatars/C22.png +0 -0
  258. package/lib/public/mate-avatars/C23.png +0 -0
  259. package/lib/public/mate-avatars/C24.png +0 -0
  260. package/lib/public/mate-avatars/C25.png +0 -0
  261. package/lib/public/mate-avatars/C26.png +0 -0
  262. package/lib/public/mate-avatars/C27.png +0 -0
  263. package/lib/public/mate-avatars/C28.png +0 -0
  264. package/lib/public/mate-avatars/C29.png +0 -0
  265. package/lib/public/mate-avatars/C30.png +0 -0
  266. package/lib/public/mate-avatars/C31.png +0 -0
  267. package/lib/public/mate-avatars/C32.png +0 -0
  268. package/lib/public/mate-avatars/C33.png +0 -0
  269. package/lib/public/mate-avatars/C34.png +0 -0
  270. package/lib/public/mate-avatars/C35.png +0 -0
  271. package/lib/public/mate-avatars/C36.png +0 -0
  272. package/lib/public/mate-avatars/C37.png +0 -0
  273. package/lib/public/mate-avatars/C38.png +0 -0
  274. package/lib/public/mate-avatars/C39.png +0 -0
  275. package/lib/public/mate-avatars/C40.png +0 -0
  276. package/lib/public/mate-avatars/C41.png +0 -0
  277. package/lib/public/mate-avatars/C42.png +0 -0
  278. package/lib/public/mate-avatars/C43.png +0 -0
  279. package/lib/public/mate-avatars/C44.png +0 -0
  280. package/lib/public/mate-avatars/C45.png +0 -0
  281. package/lib/public/mate-avatars/C46.png +0 -0
  282. package/lib/public/mate-avatars/C47.png +0 -0
  283. package/lib/public/mate-avatars/C48.png +0 -0
  284. package/lib/public/mate-avatars/catalog.json +482 -0
  285. package/lib/public/mate-avatars/lead-clay.png +0 -0
  286. package/lib/public/modules/account-auth-settings.js +71 -0
  287. package/lib/public/modules/account-transport-settings.js +51 -0
  288. package/lib/public/modules/admin-settings-projects.js +6 -2
  289. package/lib/public/modules/app-connection.js +11 -1
  290. package/lib/public/modules/app-favicon.js +18 -9
  291. package/lib/public/modules/app-header.js +7 -4
  292. package/lib/public/modules/app-loop-ui.js +2 -0
  293. package/lib/public/modules/app-message-router.js +22 -1
  294. package/lib/public/modules/app-messages.js +119 -17
  295. package/lib/public/modules/app-misc.js +3 -1
  296. package/lib/public/modules/app-notifications.js +11 -5
  297. package/lib/public/modules/app-panels.js +61 -123
  298. package/lib/public/modules/app-projects.js +13 -0
  299. package/lib/public/modules/app-rate-limit.js +7 -27
  300. package/lib/public/modules/app-rendering.js +4 -3
  301. package/lib/public/modules/avatar.js +15 -41
  302. package/lib/public/modules/chat-render-runtime.js +20 -0
  303. package/lib/public/modules/clay-browser-links.js +47 -0
  304. package/lib/public/modules/clay-control-activity.js +214 -0
  305. package/lib/public/modules/clay-control-copy.js +36 -0
  306. package/lib/public/modules/clay-control-detail-targets.js +44 -0
  307. package/lib/public/modules/clay-control-object-targets.js +52 -0
  308. package/lib/public/modules/clay-control-target-visibility.js +12 -0
  309. package/lib/public/modules/clay-control-targets.js +44 -0
  310. package/lib/public/modules/clay-log-links.js +23 -0
  311. package/lib/public/modules/clay-navigation-render.js +52 -0
  312. package/lib/public/modules/clay-owner-navigation.js +33 -0
  313. package/lib/public/modules/clay-session-links.js +31 -0
  314. package/lib/public/modules/clay-studio-bridge.js +20 -0
  315. package/lib/public/modules/clay-studio-document.js +67 -0
  316. package/lib/public/modules/clay-studio-render.js +146 -0
  317. package/lib/public/modules/clay-tool-activity.js +140 -0
  318. package/lib/public/modules/clay-tool-presentation.js +342 -0
  319. package/lib/public/modules/command-palette.js +162 -40
  320. package/lib/public/modules/contextual-ask-session.js +26 -0
  321. package/lib/public/modules/contextual-clay-geometry.js +155 -0
  322. package/lib/public/modules/contextual-clay-session.js +130 -0
  323. package/lib/public/modules/contextual-clay-workspace.js +169 -0
  324. package/lib/public/modules/contextual-clay.js +250 -0
  325. package/lib/public/modules/contextual-composer.js +91 -0
  326. package/lib/public/modules/contextual-mate-context.js +117 -0
  327. package/lib/public/modules/contextual-mate-hint.js +40 -0
  328. package/lib/public/modules/contextual-mate-identity.js +23 -0
  329. package/lib/public/modules/contextual-mate-sessions.js +134 -0
  330. package/lib/public/modules/contextual-search.js +137 -0
  331. package/lib/public/modules/contextual-session-citations.js +58 -0
  332. package/lib/public/modules/debate.js +1 -0
  333. package/lib/public/modules/default-ai.js +11 -3
  334. package/lib/public/modules/elicitation-form.js +5 -0
  335. package/lib/public/modules/filebrowser.js +20 -1
  336. package/lib/public/modules/generation-stop.js +8 -5
  337. package/lib/public/modules/git-panel.js +3 -1
  338. package/lib/public/modules/history-replay-batch.js +13 -1
  339. package/lib/public/modules/home-debate-live.js +2 -0
  340. package/lib/public/modules/home-debate-planning.js +7 -7
  341. package/lib/public/modules/home-mate-avatar-editor.js +127 -208
  342. package/lib/public/modules/home-mate-chat.js +8 -6
  343. package/lib/public/modules/home-mate-creation.js +73 -1
  344. package/lib/public/modules/home-mate-settings.js +19 -12
  345. package/lib/public/modules/icon-strip-tooltip.js +2 -1
  346. package/lib/public/modules/input.js +88 -10
  347. package/lib/public/modules/issues-render.js +3 -2
  348. package/lib/public/modules/knowledge-db-workbench.js +4 -4
  349. package/lib/public/modules/markdown.js +6 -34
  350. package/lib/public/modules/mate-avatar-catalog.js +97 -0
  351. package/lib/public/modules/mate-knowledge-workbench.js +1 -1
  352. package/lib/public/modules/mate-management.js +40 -7
  353. package/lib/public/modules/mcp-connection-view.js +31 -13
  354. package/lib/public/modules/mcp-discovery-view.js +31 -0
  355. package/lib/public/modules/mcp-ui.js +23 -4
  356. package/lib/public/modules/mention.js +3 -0
  357. package/lib/public/modules/message-delivery.js +20 -2
  358. package/lib/public/modules/model-picker.js +2 -0
  359. package/lib/public/modules/pane-activation.js +214 -0
  360. package/lib/public/modules/pane-binding.js +82 -0
  361. package/lib/public/modules/pane-bridge.js +7 -4
  362. package/lib/public/modules/pane-browser-bridge.js +22 -0
  363. package/lib/public/modules/pane-file-bridge.js +4 -0
  364. package/lib/public/modules/pane-issue-bridge.js +4 -1
  365. package/lib/public/modules/passkey-browser.js +69 -0
  366. package/lib/public/modules/passkey-server-settings.js +57 -0
  367. package/lib/public/modules/pending-message-queue.js +1 -0
  368. package/lib/public/modules/permission-control.js +5 -4
  369. package/lib/public/modules/personal-settings-dialog.js +7 -1
  370. package/lib/public/modules/product-review.js +26 -0
  371. package/lib/public/modules/profile.js +1 -238
  372. package/lib/public/modules/project-access-recovery.js +17 -0
  373. package/lib/public/modules/project-admin-overview.js +21 -0
  374. package/lib/public/modules/project-chat-identity.js +13 -4
  375. package/lib/public/modules/project-logs-render.js +6 -2
  376. package/lib/public/modules/project-mate-navigation.js +144 -22
  377. package/lib/public/modules/rewind.js +5 -0
  378. package/lib/public/modules/scheduled-tasks.js +2 -0
  379. package/lib/public/modules/scheduler.js +2 -0
  380. package/lib/public/modules/search-clay-chat.js +5 -440
  381. package/lib/public/modules/server-settings-controls.js +10 -0
  382. package/lib/public/modules/server-settings.js +7 -2
  383. package/lib/public/modules/session-actions.js +5 -2
  384. package/lib/public/modules/session-context-menu.js +5 -0
  385. package/lib/public/modules/session-create-form.js +10 -10
  386. package/lib/public/modules/session-folder-layout.js +1 -1
  387. package/lib/public/modules/session-folder-view-menu.js +9 -0
  388. package/lib/public/modules/session-github.js +85 -14
  389. package/lib/public/modules/session-rich-drafts.js +21 -0
  390. package/lib/public/modules/session-switch-defer.js +67 -0
  391. package/lib/public/modules/session-work-primary.js +51 -0
  392. package/lib/public/modules/settings-defaults.js +27 -28
  393. package/lib/public/modules/shared-browser-settings.js +112 -0
  394. package/lib/public/modules/shared-browser-tabs.js +13 -3
  395. package/lib/public/modules/shared-browser.js +29 -6
  396. package/lib/public/modules/sidebar-mobile.js +4 -3
  397. package/lib/public/modules/sidebar-projects.js +1 -0
  398. package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
  399. package/lib/public/modules/sidebar-sessions.js +1 -0
  400. package/lib/public/modules/split-group-restore.js +68 -0
  401. package/lib/public/modules/split-pair-ui.js +1 -0
  402. package/lib/public/modules/split-pane-reconciler.js +15 -0
  403. package/lib/public/modules/split-pane-renderer.js +87 -6
  404. package/lib/public/modules/split-session-boundary.js +1 -1
  405. package/lib/public/modules/split-view.js +60 -68
  406. package/lib/public/modules/sticky-note-markdown.js +72 -6
  407. package/lib/public/modules/sticky-notes-actions.js +30 -0
  408. package/lib/public/modules/sticky-notes-browser.js +9 -2
  409. package/lib/public/modules/sticky-notes-card.js +23 -7
  410. package/lib/public/modules/sticky-notes-checklist.js +116 -0
  411. package/lib/public/modules/sticky-notes-editor.js +108 -44
  412. package/lib/public/modules/sticky-notes-shared.js +50 -2
  413. package/lib/public/modules/sticky-notes-state.js +66 -0
  414. package/lib/public/modules/sticky-notes.js +34 -51
  415. package/lib/public/modules/stt-controller.js +4 -1
  416. package/lib/public/modules/stt-recording.js +1 -1
  417. package/lib/public/modules/stt.js +7 -2
  418. package/lib/public/modules/terminal.js +9 -0
  419. package/lib/public/modules/theme.js +8 -1
  420. package/lib/public/modules/thinking-lifecycle.js +33 -3
  421. package/lib/public/modules/thinking-view.js +23 -1
  422. package/lib/public/modules/tools.js +60 -11
  423. package/lib/public/modules/tui-grab.js +1 -2
  424. package/lib/public/modules/user-settings-account.js +14 -1
  425. package/lib/public/modules/user-settings-appearance.js +10 -3
  426. package/lib/public/modules/user-settings-editors.js +1 -1
  427. package/lib/public/modules/user-settings-layout.js +11 -2
  428. package/lib/public/modules/user-settings-preferences.js +6 -2
  429. package/lib/public/modules/user-settings-profile.js +12 -2
  430. package/lib/public/modules/user-settings-sessions.js +120 -0
  431. package/lib/public/modules/user-settings.js +6 -2
  432. package/lib/public/modules/vendor-login-browser.js +5 -3
  433. package/lib/public/modules/vendor-login.js +2 -2
  434. package/lib/public/modules/vendor-priority.js +15 -1
  435. package/lib/public/modules/wireframe-workbench.js +5 -2
  436. package/lib/public/modules/you-activity.js +3 -1
  437. package/lib/public/modules/you.js +91 -6
  438. package/lib/public/muse-avatar.svg +4 -0
  439. package/lib/public/style.css +6 -0
  440. package/lib/public/sw.js +3 -1
  441. package/lib/safe-bash-commands.js +3 -45
  442. package/lib/scheduled-task-records.js +3 -1
  443. package/lib/scheduler.js +2 -0
  444. package/lib/sdk-bridge.js +342 -401
  445. package/lib/sdk-foreground-admission.js +16 -0
  446. package/lib/sdk-mcp-descriptors.js +2 -37
  447. package/lib/sdk-message-processor.js +52 -17
  448. package/lib/sdk-quota-snapshot.js +1 -1
  449. package/lib/sdk-response-recovery.js +1 -0
  450. package/lib/sdk-worker.js +2 -677
  451. package/lib/server-account-passkeys.js +186 -0
  452. package/lib/server-account-passwords.js +127 -0
  453. package/lib/server-account-security.js +53 -0
  454. package/lib/server-admin.js +63 -16
  455. package/lib/server-appearance-settings.js +13 -1
  456. package/lib/server-auth.js +107 -79
  457. package/lib/server-contextual-clay-settings.js +40 -0
  458. package/lib/server-contextual-mate-sessions.js +70 -0
  459. package/lib/server-dm.js +2 -1
  460. package/lib/server-global-ws.js +10 -20
  461. package/lib/server-home-chat-events.js +18 -4
  462. package/lib/server-home-chat.js +22 -20
  463. package/lib/server-home-clay-entry.js +23 -4
  464. package/lib/server-home-clay-session-links.js +29 -9
  465. package/lib/server-home-mate-creation.js +1 -0
  466. package/lib/server-home-mcp-consent.js +14 -0
  467. package/lib/server-mates.js +25 -62
  468. package/lib/server-owner-ui.js +118 -0
  469. package/lib/server-path-access.js +38 -0
  470. package/lib/server-project-removal.js +22 -0
  471. package/lib/server-settings.js +8 -2
  472. package/lib/server.js +165 -43
  473. package/lib/session-config-transition.js +45 -0
  474. package/lib/session-folders.js +7 -2
  475. package/lib/session-fork-history.js +21 -0
  476. package/lib/session-github.js +9 -2
  477. package/lib/session-hygiene.js +3 -35
  478. package/lib/session-permission-mode.js +4 -3
  479. package/lib/session-skill-scope.js +11 -0
  480. package/lib/session-visibility.js +5 -2
  481. package/lib/session-work-primary.js +50 -0
  482. package/lib/sessions.js +64 -99
  483. package/lib/shared-browser-cookie-sync.js +32 -0
  484. package/lib/shared-browser-cookies.js +79 -0
  485. package/lib/shared-browser-runtime.js +25 -9
  486. package/lib/shared-browser-storage-sync.js +43 -0
  487. package/lib/shared-browser-storage.js +101 -0
  488. package/lib/shared-browser-tools.js +2 -1
  489. package/lib/shared-browser-worker.js +46 -10
  490. package/lib/terminal-manager.js +65 -6
  491. package/lib/tool-llm.js +1 -1
  492. package/lib/tui-transcript-index.js +1 -132
  493. package/lib/user-knowledge-service.js +23 -1
  494. package/lib/users-auth.js +38 -3
  495. package/lib/users-contextual-clay-preferences.js +31 -0
  496. package/lib/users-create.js +97 -0
  497. package/lib/users-permissions.js +2 -8
  498. package/lib/users-server-pin.js +37 -0
  499. package/lib/users.js +18 -84
  500. package/lib/vendor-login-browser.js +1 -11
  501. package/lib/workspace-assignment-service.js +25 -0
  502. package/lib/workspace-query-access.js +4 -1
  503. package/lib/workspace-query-mcp-server.js +1 -1
  504. package/lib/workspace-query-service.js +13 -2
  505. package/lib/ws-request.js +1 -0
  506. package/lib/ws-schema.js +18 -2
  507. package/lib/yoke/acp-agent-profiles.js +7 -5
  508. package/lib/yoke/adapters/antigravity.js +3 -14
  509. package/lib/yoke/adapters/claude-query-contract.js +9 -0
  510. package/lib/yoke/adapters/claude.js +54 -50
  511. package/lib/yoke/adapters/codex-query-contract.js +24 -0
  512. package/lib/yoke/adapters/codex.js +53 -111
  513. package/lib/yoke/adapters/kiro.js +3 -1
  514. package/lib/yoke/adapters/muse-query-contract.js +7 -0
  515. package/lib/yoke/adapters/muse.js +122 -0
  516. package/lib/yoke/auth-events.js +17 -0
  517. package/lib/yoke/claude-hook-installer.js +271 -0
  518. package/lib/yoke/claude-jsonl-watcher.js +204 -0
  519. package/lib/yoke/claude-maintenance.js +55 -0
  520. package/lib/yoke/claude-permission-patterns.js +53 -0
  521. package/lib/yoke/claude-response-recovery.js +155 -0
  522. package/lib/yoke/claude-transcript-hygiene.js +34 -0
  523. package/lib/yoke/claude-worker-startup.js +28 -0
  524. package/lib/yoke/clay-skill-install.js +33 -0
  525. package/lib/yoke/cli-sessions.js +300 -0
  526. package/lib/yoke/codex-app-server.js +7 -12
  527. package/lib/yoke/codex-idle-recovery.js +81 -1
  528. package/lib/yoke/codex-recovery-admission.js +164 -0
  529. package/lib/yoke/configuration.js +13 -0
  530. package/lib/yoke/discovery.js +70 -0
  531. package/lib/yoke/errors.js +8 -0
  532. package/lib/yoke/host-environment.js +7 -0
  533. package/lib/yoke/index.js +9 -51
  534. package/lib/yoke/interface.js +116 -0
  535. package/lib/yoke/kiro-acp-server.js +5 -5
  536. package/lib/yoke/legacy-sessions.js +89 -0
  537. package/lib/yoke/login-protocol.js +25 -0
  538. package/lib/yoke/maintenance.js +12 -0
  539. package/lib/yoke/mcp-proxy.js +32 -0
  540. package/lib/yoke/mcp-source-adapters.js +91 -0
  541. package/lib/yoke/mcp-source-context.js +42 -0
  542. package/lib/yoke/mcp-source-discovery.js +169 -0
  543. package/lib/yoke/mcp-source-plugins.js +68 -0
  544. package/lib/yoke/mcp-source-restrictions.js +47 -0
  545. package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
  546. package/lib/yoke/model-preferences.js +6 -0
  547. package/lib/yoke/muse-artifacts.js +36 -0
  548. package/lib/yoke/muse-controls.js +50 -0
  549. package/lib/yoke/muse-input.js +64 -0
  550. package/lib/yoke/muse-items.js +157 -0
  551. package/lib/yoke/muse-policy.js +52 -0
  552. package/lib/yoke/muse-query.js +428 -0
  553. package/lib/yoke/muse-runtime.js +211 -0
  554. package/lib/yoke/muse-services.js +79 -0
  555. package/lib/yoke/muse-skills.js +79 -0
  556. package/lib/yoke/muse-turns.js +71 -0
  557. package/lib/yoke/options/acp.js +2 -0
  558. package/lib/yoke/options/antigravity.js +2 -0
  559. package/lib/yoke/options/claude.js +21 -0
  560. package/lib/yoke/options/codex-defaults.js +29 -0
  561. package/lib/yoke/options/codex-settings.js +21 -0
  562. package/lib/yoke/options/codex.js +6 -0
  563. package/lib/yoke/options/kiro-defaults.js +22 -0
  564. package/lib/yoke/options/kiro.js +5 -0
  565. package/lib/yoke/options/muse.js +5 -0
  566. package/lib/yoke/provider-contract.js +5 -0
  567. package/lib/yoke/providers/antigravity-executable.js +8 -0
  568. package/lib/yoke/providers/claude-executable.js +40 -0
  569. package/lib/yoke/providers/claude-model-descriptions.js +14 -0
  570. package/lib/yoke/providers/claude-process.js +97 -0
  571. package/lib/yoke/providers/claude-provision.js +75 -0
  572. package/lib/yoke/providers/codex-errors.js +8 -0
  573. package/lib/yoke/providers/muse-executable.js +17 -0
  574. package/lib/yoke/provisioning.js +6 -0
  575. package/lib/yoke/query-options.js +10 -0
  576. package/lib/yoke/response-recovery.js +41 -0
  577. package/lib/yoke/sdk-mcp-descriptors.js +37 -0
  578. package/lib/yoke/sdk-server-factory.js +7 -0
  579. package/lib/yoke/session-history.js +8 -0
  580. package/lib/yoke/session-tool-transport.js +34 -13
  581. package/lib/yoke/settings.js +23 -0
  582. package/lib/yoke/source-locations.js +4 -0
  583. package/lib/yoke/title-query.js +18 -7
  584. package/lib/yoke/tui-transcript-index.js +132 -0
  585. package/lib/yoke/usage.js +48 -0
  586. package/lib/yoke/user-input.js +13 -0
  587. package/lib/yoke/vendor-registry.js +81 -1
  588. package/package.json +11 -4
@@ -0,0 +1,31 @@
1
+ function requiredNames(row) {
2
+ var names = (row.environmentNames || []).filter(function (name) { return !Object.prototype.hasOwnProperty.call(row.env || {}, name); });
3
+ (row.references || []).forEach(function (reference) {
4
+ var match = /^(?:\$\{?|\{env:)([A-Za-z_][A-Za-z0-9_]*)/.exec(reference);
5
+ var name = match ? match[1] : /^[A-Za-z_][A-Za-z0-9_]*$/.test(reference) ? reference : 'Unsupported reference';
6
+ names.push(name);
7
+ });
8
+ return Array.from(new Set(names));
9
+ }
10
+ function applyCredentials(row, values) {
11
+ var names = requiredNames(row);
12
+ if (names.indexOf('Unsupported reference') >= 0) throw new Error('This source requires a vendor-specific helper or file reference. Configure a direct Clay connection instead.');
13
+ names.forEach(function (name) {
14
+ if (!Object.prototype.hasOwnProperty.call(values, name) || typeof values[name] !== 'string' || !values[name] || values[name].length > 8192 || /[\r\n\0]/.test(values[name])) throw new Error('Enter each required credential value.');
15
+ });
16
+ function expand(value) {
17
+ if (typeof value === 'string') return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-[^}]*)?\}|\$([A-Za-z_][A-Za-z0-9_]*)|\{env:([^}]+)\}/g, function (all, first, second, third) {
18
+ var name = first || second || third; return Object.prototype.hasOwnProperty.call(values, name) ? values[name] : all;
19
+ });
20
+ if (Array.isArray(value)) return value.map(expand);
21
+ if (value && typeof value === 'object') { var next = {}; Object.keys(value).forEach(function (key) { next[key] = expand(value[key]); }); return next; }
22
+ return value;
23
+ }
24
+ var next = {};
25
+ ['command', 'args', 'env', 'headers', 'url'].forEach(function (field) { if (row[field] !== undefined) next[field] = expand(row[field]); });
26
+ next.headers = next.headers || {}; next.env = next.env || {};
27
+ Object.keys(row.envHeaders || {}).forEach(function (name) { next.headers[name] = (name === 'Authorization' && row.bearerTokenEnv === row.envHeaders[name] ? 'Bearer ' : '') + values[row.envHeaders[name]]; });
28
+ (row.environmentNames || []).forEach(function (name) { if (values[name] !== undefined) next.env[name] = values[name]; });
29
+ next.envHeaders = {}; next.references = []; return next;
30
+ }
31
+ module.exports = { requiredNames: requiredNames, applyCredentials: applyCredentials };
@@ -0,0 +1,13 @@
1
+ var StdioClientTransport = require('@modelcontextprotocol/sdk/client/stdio.js').StdioClientTransport;
2
+ var wrapSpawnAsUser = require('./os-users').wrapSpawnAsUser;
3
+ var os = require('os');
4
+ function localTransport(row, identity) {
5
+ if ((row.references || []).length || (row.environmentNames || []).some(function (name) { return !Object.prototype.hasOwnProperty.call(row.env || {}, name); })) throw new Error('Configure required environment values before connecting.');
6
+ var home = identity ? identity.home : os.homedir();
7
+ var env = Object.assign({ HOME: home, USER: identity ? identity.user : os.userInfo().username, LOGNAME: identity ? identity.user : os.userInfo().username, SHELL: identity ? identity.shell || '/bin/sh' : '/bin/sh', PATH: '/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin' }, row.env || {});
8
+ var wrapped = wrapSpawnAsUser(row.command, row.args, identity ? { uid: identity.uid, gid: identity.gid, env: env } : { env: env });
9
+ // The SDK cannot apply uid/gid itself; never fall back to spawning as the daemon.
10
+ if (wrapped.options.uid != null || wrapped.options.gid != null) throw new Error('Install util-linux setpriv to run MCP as the account OS user.');
11
+ return new StdioClientTransport({ command: wrapped.command, args: wrapped.args, env: env, cwd: row.cwd, stderr: 'ignore' });
12
+ }
13
+ module.exports = { localTransport: localTransport };
package/lib/mcp-oauth.js CHANGED
@@ -2,21 +2,21 @@ var crypto = require('crypto');
2
2
  var http = require('http');
3
3
  var assertPublicUrl = require('./mcp-network').assertPublicUrl;
4
4
 
5
- function createOAuthProvider(record, persist, flow) {
5
+ function createOAuthProvider(record, persist, flow, authorize) {
6
6
  record.auth = record.auth || {};
7
7
  var auth = record.auth;
8
- function guard() { if (flow && flow.cancelled) throw new Error('Sign-in expired.'); }
8
+ function guard() { if (flow && flow.cancelled) throw new Error('Sign-in expired.'); if (authorize) authorize(); }
9
9
  function save() { persist(); }
10
10
  return {
11
11
  get redirectUrl() { return flow ? flow.redirectUrl : auth.redirectUrl; },
12
12
  get clientMetadata() { return { client_name: 'Clay', redirect_uris: [flow ? flow.redirectUrl : auth.redirectUrl],
13
13
  grant_types: ['authorization_code', 'refresh_token'], response_types: ['code'], token_endpoint_auth_method: 'none' }; },
14
14
  state: function () { return flow ? flow.state : crypto.randomBytes(32).toString('hex'); },
15
- clientInformation: function () { return auth.client; },
15
+ clientInformation: function () { guard(); return auth.client; },
16
16
  saveClientInformation: function (value) { guard(); auth.client = value; save(); },
17
- tokens: function () { return auth.tokens; },
17
+ tokens: function () { guard(); return auth.tokens; },
18
18
  saveTokens: function (value) { guard(); auth.tokens = value; save(); },
19
- saveCodeVerifier: function (value) { if (flow) flow.verifier = value; },
19
+ saveCodeVerifier: function (value) { guard(); if (flow) flow.verifier = value; },
20
20
  codeVerifier: function () { if (!flow || !flow.verifier) throw new Error('Sign in again.'); return flow.verifier; },
21
21
  redirectToAuthorization: async function (url) {
22
22
  if (!flow) { var required = new Error('Sign in to connect this server.'); required.name = 'UnauthorizedError'; throw required; }
@@ -25,13 +25,15 @@ function createOAuthProvider(record, persist, flow) {
25
25
  if (url.searchParams.get('state') !== flow.state || url.searchParams.get('redirect_uri') !== flow.redirectUrl || !url.searchParams.get('code_challenge')) throw new Error('Invalid sign-in request.');
26
26
  flow.authorizationUrl = url.href;
27
27
  },
28
- discoveryState: function () { return auth.discovery; },
28
+ discoveryState: function () { guard(); return auth.discovery; },
29
29
  saveDiscoveryState: function (value) {
30
+ guard();
30
31
  // Bind client credentials to the discovered issuer.
31
32
  if (auth.discovery && auth.discovery.authorizationServerUrl !== value.authorizationServerUrl) { delete auth.client; delete auth.tokens; }
32
33
  guard(); auth.discovery = value; save();
33
34
  },
34
35
  invalidateCredentials: function (which) {
36
+ guard();
35
37
  if (which === 'all' || which === 'client') delete auth.client;
36
38
  if (which === 'all' || which === 'tokens') delete auth.tokens;
37
39
  if (which === 'all' || which === 'discovery') delete auth.discovery;
package/lib/mcp-proxy.js CHANGED
@@ -1,32 +1,2 @@
1
- // Preserve the server's JSON Schema across SDK and stdio projections.
2
- function validateDefinitions(definitions) {
3
- var z = require('zod');
4
- var names = new Set();
5
- return definitions.map(function (definition) {
6
- if (!definition || !/^[a-zA-Z0-9_.-]{1,128}$/.test(definition.name) || names.has(definition.name) || Object.prototype.hasOwnProperty.call(Object.prototype, definition.name)) throw new Error('Unsupported MCP tool catalog.');
7
- names.add(definition.name);
8
- var parsed = z.fromJSONSchema(definition.inputSchema || { type: 'object', properties: {} });
9
- if (!parsed.shape) throw new Error('MCP tools must accept an object.');
10
- return parsed;
11
- });
12
- }
13
- function createProxy(name, definitions, invoke) {
14
- var sdk = require('@anthropic-ai/claude-agent-sdk');
15
- var schemas = validateDefinitions(definitions);
16
- var tools = definitions.map(function (definition, index) {
17
- return sdk.tool(definition.name, definition.description || definition.name, schemas[index].shape, function (args) { return invoke(definition.name, args); });
18
- });
19
- var server = sdk.createSdkMcpServer({ name: name, version: '1.0.0', tools: tools });
20
- definitions.forEach(function (definition, index) {
21
- var tool = server.instance._registeredTools[definition.name];
22
- tool.inputSchema = schemas[index];
23
- tool._clayInputSchema = definition.inputSchema || { type: 'object', properties: {} };
24
- });
25
- server.instance.server.setRequestHandler(require('@modelcontextprotocol/sdk/types.js').ListToolsRequestSchema, function () {
26
- return { tools: definitions.map(function (definition) {
27
- return { name: definition.name, description: definition.description, inputSchema: definition.inputSchema || { type: 'object', properties: {} } };
28
- }) };
29
- });
30
- return server;
31
- }
32
- module.exports = { createProxy: createProxy, validateDefinitions: validateDefinitions };
1
+ // Compatibility export for the YOKE SDK/stdio tool projection.
2
+ module.exports = require("./yoke/mcp-proxy");
@@ -0,0 +1,30 @@
1
+ var descriptors = require('./yoke/sdk-mcp-descriptors').extractMcpDescriptors;
2
+ function createQueryBridge(ctx) {
3
+ function valid() {
4
+ if (!ctx.valid()) throw new Error('MCP tools require the current authorized query.');
5
+ }
6
+ function list() {
7
+ if (!ctx.valid()) return [];
8
+ var servers = descriptors(ctx.getServers()) || [], tools = [];
9
+ servers.forEach(function (server) {
10
+ server.tools.forEach(function (tool) { tools.push(Object.assign({ server: server.serverName }, tool)); });
11
+ });
12
+ return tools;
13
+ }
14
+ async function call(serverName, toolName, args) {
15
+ valid();
16
+ var server = ctx.getServers()[serverName], tool = server && server.instance && server.instance._registeredTools[toolName];
17
+ if (!tool || typeof (tool.handler || tool.callback) !== 'function') throw new Error('MCP tool is unavailable.');
18
+ var result = await (tool.handler || tool.callback)(args || {});
19
+ valid(); return result;
20
+ }
21
+ function dynamicDefs() {
22
+ return list().map(function (tool) {
23
+ return { name: 'mcp__' + tool.server + '__' + tool.name, permissionName: 'mcp__' + tool.server + '__' + tool.name,
24
+ description: tool.description, inputSchema: tool.inputSchema, queryBound: true,
25
+ handler: function (args) { return call(tool.server, tool.name, args); } };
26
+ });
27
+ }
28
+ return { list: list, call: call, dynamicDefs: dynamicDefs };
29
+ }
30
+ module.exports = { createQueryBridge: createQueryBridge };
@@ -1,5 +1,7 @@
1
1
  var crypto = require('crypto');
2
2
  var Client = require('@modelcontextprotocol/sdk/client/index.js').Client;
3
+ var SSEClientTransport = require('@modelcontextprotocol/sdk/client/sse.js').SSEClientTransport;
4
+ var localTransport = require('./mcp-local-transport').localTransport;
3
5
  var StreamableHTTPClientTransport = require('@modelcontextprotocol/sdk/client/streamableHttp.js').StreamableHTTPClientTransport;
4
6
  var network = require('./mcp-network');
5
7
  var oauth = require('./mcp-oauth');
@@ -9,12 +11,33 @@ function createRemoteConnections(ctx) {
9
11
  var accounts = new Map(), live = new Map(), flows = new Map(), queues = new Map();
10
12
  var remoteFetch = ctx.remoteFetch || network.createRemoteFetch();
11
13
  var closed = false;
14
+ function sameRuntimeConfig(left, right) {
15
+ return left && right && left.url === right.url && left.enabled === right.enabled && left.authMode === right.authMode && left.token === right.token && JSON.stringify(left.auth || null) === JSON.stringify(right.auth || null) && JSON.stringify([left.transport, left.command, left.args, left.env, left.cwd, left.headers, left.envHeaders, left.references, left.disabledTools, left.enabledTools, left.toolPatterns, left.toolPrefix]) === JSON.stringify([right.transport, right.command, right.args, right.env, right.cwd, right.headers, right.envHeaders, right.references, right.disabledTools, right.enabledTools, right.toolPatterns, right.toolPrefix]);
16
+ }
17
+ function invalidate(owner, previous, current) {
18
+ var byId = new Map(current.filter(function (row) { return row.source !== 'computer'; }).map(function (row) { return [row.id, row]; }));
19
+ previous.filter(function (row) { return row.source !== 'computer'; }).forEach(function (row) {
20
+ var next = byId.get(row.id);
21
+ if (!next || !sameRuntimeConfig(row, next)) disconnect(owner, row.id);
22
+ });
23
+ }
12
24
  function records(owner) {
13
25
  ctx.authorize(owner);
14
- if (!accounts.has(owner)) accounts.set(owner, ctx.storage.load(owner));
15
- return accounts.get(owner);
26
+ var account = accounts.get(owner), snapshot = typeof ctx.storage.snapshot === 'function' ? ctx.storage.snapshot(owner) : { records: ctx.storage.load(owner), revision: typeof ctx.storage.revision === 'function' ? ctx.storage.revision(owner) : null };
27
+ var loaded = snapshot.records, revision = snapshot.revision;
28
+ if (!account) accounts.set(owner, account = { records: loaded, revision: revision });
29
+ else if (account.revision !== revision) { invalidate(owner, account.records, loaded); account.records = loaded; account.revision = revision; }
30
+ return account.records;
31
+ }
32
+ function persist(owner) {
33
+ ctx.authorize(owner); if (closed) throw new Error('MCP connections closed.');
34
+ var account = accounts.get(owner);
35
+ if (!account) throw new Error('MCP connection snapshot is unavailable.');
36
+ var revision;
37
+ try { revision = ctx.storage.save(owner, account.records, account.revision); }
38
+ catch (error) { accounts.delete(owner); invalidate(owner, account.records, []); throw error; }
39
+ if (account) account.revision = revision;
16
40
  }
17
- function persist(owner) { ctx.authorize(owner); if (closed) throw new Error('MCP connections closed.'); ctx.storage.save(owner, records(owner)); }
18
41
  function find(owner, id) {
19
42
  var row = records(owner).find(function (item) { return item.id === id; });
20
43
  if (!row) throw new Error('Connection is unavailable.');
@@ -23,14 +46,15 @@ function createRemoteConnections(ctx) {
23
46
  function key(owner, id) { return JSON.stringify([owner, id]); }
24
47
  function check(owner, row) {
25
48
  if (closed || find(owner, row.id) !== row) throw new Error('Connection changed.');
49
+ if (row.source === 'local' && ctx.ownerIdentity) ctx.ownerIdentity(owner);
26
50
  }
27
51
  function changed(owner) { if (!closed) ctx.changed(owner); }
28
52
  function view(owner) {
29
- return records(owner).filter(function (row) { return row.source === 'url'; }).map(function (row) {
53
+ return records(owner).filter(function (row) { return row.source !== 'computer'; }).map(function (row) {
30
54
  var entry = live.get(key(owner, row.id));
31
- return { id: row.id, name: row.id, label: row.label, source: 'url', transport: 'http', url: row.url,
55
+ return { id: row.id, name: row.id, label: row.label, source: row.source, transport: row.transport || 'http', url: row.url ? new URL(row.url).origin + new URL(row.url).pathname : null, provenance: row.provenance, references: require('./mcp-import-credentials').requiredNames(row),
32
56
  projectEnabled: !!row.enabled, extensionEnabled: true, tools: row.tools || [], toolCount: (row.tools || []).length,
33
- status: entry ? entry.status : (row.tools ? 'idle' : 'unavailable'), error: entry ? entry.error : '', authMode: row.authMode || 'auto' };
57
+ status: entry ? entry.status : (row.provenance || row.tools ? 'idle' : 'unavailable'), error: entry ? entry.error : '', authMode: row.authMode || 'auto' };
34
58
  });
35
59
  }
36
60
  async function disconnect(owner, id) {
@@ -39,7 +63,7 @@ function createRemoteConnections(ctx) {
39
63
  if (entry && entry.client) await entry.client.close().catch(function () {});
40
64
  }
41
65
  function provider(owner, row, flow) {
42
- return oauth.createOAuthProvider(row, function () { check(owner, row); persist(owner); }, flow);
66
+ return oauth.createOAuthProvider(row, function () { check(owner, row); persist(owner); }, flow, function () { check(owner, row); });
43
67
  }
44
68
  async function connect(owner, row, flow) {
45
69
  check(owner, row);
@@ -47,17 +71,20 @@ function createRemoteConnections(ctx) {
47
71
  check(owner, row);
48
72
  if (flow && flow.cancelled) throw new Error('Sign-in expired.');
49
73
  var client = new Client({ name: 'clay', version: '1.0.0' }, { capabilities: {} });
50
- var options = { fetch: remoteFetch.fetch };
51
- if (row.authMode === 'token' && row.token) options.requestInit = { headers: { Authorization: 'Bearer ' + row.token } };
74
+ if (row.source !== 'local' && ((row.references || []).length || Object.keys(row.envHeaders || {}).length)) throw new Error('Configure required credentials in Clay before connecting.');
75
+ var options = { fetch: async function (input, init) { check(owner, row); var response = await remoteFetch.fetch(input, init); check(owner, row); return response; }, requestInit: { headers: row.headers || {} } };
76
+ if (row.authMode === 'token' && row.token) options.requestInit = { headers: Object.assign({}, row.headers || {}, { Authorization: 'Bearer ' + row.token }) };
52
77
  else if (flow || (row.auth && row.auth.tokens)) options.authProvider = provider(owner, row, flow);
53
- var transport = new StreamableHTTPClientTransport(new URL(row.url), options);
78
+ var transport = row.source === 'local' ? localTransport(row, ctx.ownerIdentity ? ctx.ownerIdentity(owner) : null) : (row.transport === 'sse' ? new SSEClientTransport(new URL(row.url), options) : new StreamableHTTPClientTransport(new URL(row.url), options));
54
79
  var entry = { client: client, transport: transport, status: 'connecting', error: '' };
55
80
  live.set(key(owner, row.id), entry); changed(owner);
56
81
  try {
57
82
  await client.connect(transport, { timeout: 30000 });
83
+ check(owner, row);
58
84
  var tools = [], cursor, seen = new Set();
59
85
  do {
60
86
  var page = await client.listTools(cursor ? { cursor: cursor } : {}, { timeout: 30000 });
87
+ check(owner, row);
61
88
  tools = tools.concat(page.tools);
62
89
  if (tools.length > 1000 || seen.size >= 100 || (page.nextCursor && seen.has(page.nextCursor))) throw new Error('Tool catalog exceeds the supported limit.');
63
90
  cursor = page.nextCursor; seen.add(cursor);
@@ -65,13 +92,16 @@ function createRemoteConnections(ctx) {
65
92
  if (JSON.stringify(tools).length > 2 * 1024 * 1024) throw new Error('Tool catalog exceeds the supported limit.');
66
93
  check(owner, row);
67
94
  if (live.get(key(owner, row.id)) !== entry || (flow && flow.cancelled)) throw new Error('Connection changed.');
95
+ tools = tools.filter(function (tool) {
96
+ return require('./mcp-tool-policy').permits(row, tool.name);
97
+ });
68
98
  require('./mcp-proxy').validateDefinitions(tools);
69
99
  row.tools = tools; entry.status = 'ready'; persist(owner);
70
100
  return entry;
71
101
  } catch (error) {
72
102
  var requiresAuth = error.code === 401 || error.code === 403 || error.name === 'UnauthorizedError' || (flow && flow.authorizationUrl);
73
103
  entry.status = requiresAuth ? 'auth_required' : 'unavailable';
74
- entry.error = requiresAuth ? 'Sign in or provide an access token to connect.' : 'Could not connect. Check the address and try again.';
104
+ entry.error = requiresAuth ? 'Sign in or provide an access token to connect.' : row.source === 'local' ? 'Could not start the command. Check its dependency and working directory.' : 'Could not connect. Check the address and try again.';
75
105
  if (!flow) await client.close().catch(function () {});
76
106
  return entry;
77
107
  } finally { changed(owner); }
@@ -101,6 +131,7 @@ function createRemoteConnections(ctx) {
101
131
  if (ready.status !== 'ready') throw new Error('Connection failed after sign-in.');
102
132
  setTimeout(function () { if (flows.get(key(owner, row.id)) === flow) { cancelLogin(owner, row.id); changed(owner); } }, 500);
103
133
  });
134
+ try { check(owner, row); } catch (error) { flow.close(); throw error; }
104
135
  flows.set(key(owner, row.id), flow);
105
136
  flow.timer = setTimeout(function () { cancelLogin(owner, row.id); }, 10 * 60 * 1000); flow.timer.unref();
106
137
  row.authMode = 'auto'; delete row.token;
@@ -123,40 +154,61 @@ function createRemoteConnections(ctx) {
123
154
  pending.finally(function () { if (queues.get(owner) === pending) queues.delete(owner); }).catch(function () {});
124
155
  return pending;
125
156
  }
157
+ function commitImport(owner, select, authorize) {
158
+ authorize();
159
+ var imported = select();
160
+ records(owner);
161
+ if (accounts.get(owner).revision !== imported.revision) throw new Error('Connections changed. Scan again.');
162
+ if (records(owner).some(function (item) { return item.importSignature === imported.signature || imported.config.url && item.url === imported.config.url; })) throw new Error('This server is already imported.');
163
+ authorize();
164
+ var row = Object.assign({}, imported.config, { id: 'remote-' + crypto.randomBytes(8).toString('hex'), importSignature: imported.signature, enabled: false });
165
+ records(owner).push(row); persist(owner);
166
+ return row;
167
+ }
168
+ function importConnection(owner, select, authorize) {
169
+ return serial(owner, function () { var row = commitImport(owner, select, authorize); changed(owner); return row.id; });
170
+ }
126
171
  function command(owner, msg, ws) {
127
172
  // Revocation takes effect before any queued network work completes.
128
173
  if (msg.action === 'remove' || (msg.action === 'enable' && msg.enabled !== true)) {
129
174
  try {
130
175
  var revoked = find(owner, msg.id);
131
- if (revoked.source !== 'url') throw new Error('Not a remote connection.');
176
+ if (revoked.source === 'computer') throw new Error('Not a remote connection.');
132
177
  revoked.enabled = false; cancelLogin(owner, revoked.id); persist(owner);
133
178
  disconnect(owner, revoked.id); changed(owner);
134
179
  } catch (error) { return Promise.reject(error); }
135
180
  }
136
181
  return serial(owner, async function () {
137
182
  var row;
138
- if (msg.action === 'add') {
183
+ if (msg.action === 'import') {
184
+ row = commitImport(owner, function () { return ctx.selectImport(owner, ws, msg); }, function () { if (!ctx.canAccess(ws, owner)) throw new Error('MCP account is unavailable.'); });
185
+ } else if (msg.action === 'add') {
139
186
  var url = network.remoteUrl(msg.url).href;
140
- if (records(owner).filter(function (item) { return item.source === 'url'; }).length >= 30) throw new Error('You can add up to 30 remote connections per project.');
187
+ if (records(owner).filter(function (item) { return item.source !== 'computer'; }).length >= 30) throw new Error('You can add up to 30 remote connections per project.');
141
188
  if (records(owner).some(function (item) { return item.url === url; })) throw new Error('This server is already connected. Open it from your connections.');
142
189
  row = { id: 'remote-' + crypto.randomBytes(8).toString('hex'), source: 'url', url: url, label: new URL(url).hostname, enabled: false };
143
190
  records(owner).push(row); persist(owner);
144
191
  await connect(owner, row);
145
192
  } else {
146
193
  row = find(owner, msg.id);
147
- if (row.source !== 'url') throw new Error('Not a remote connection.');
148
- if (msg.action === 'enable') { row.enabled = msg.enabled === true; persist(owner); }
194
+ if (row.source === 'computer') throw new Error('Not a remote connection.');
195
+ if (msg.action === 'enable') { row.enabled = msg.enabled === true; persist(owner); if (row.enabled && row.provenance) { try { await connect(owner, row); } catch (error) { row.enabled = false; persist(owner); throw error; } } }
149
196
  else if (msg.action === 'rename') {
150
197
  if (typeof msg.label !== 'string' || !msg.label.trim() || msg.label.length > 100) throw new Error('Use a name between 1 and 100 characters.');
151
198
  row.label = msg.label.trim(); persist(owner);
152
199
  } else if (msg.action === 'remove') {
153
200
  cancelLogin(owner, row.id); await disconnect(owner, row.id);
154
- accounts.set(owner, records(owner).filter(function (item) { return item !== row; })); persist(owner);
201
+ var account = accounts.get(owner);
202
+ accounts.set(owner, { records: records(owner).filter(function (item) { return item !== row; }), revision: account && account.revision }); persist(owner);
155
203
  } else if (msg.action === 'test') { cancelLogin(owner, row.id); await connect(owner, row); }
156
- else if (msg.action === 'token') {
204
+ else if (msg.action === 'credentials') {
205
+ if (!msg.values || typeof msg.values !== 'object' || Array.isArray(msg.values)) throw new Error('Enter required credential values.');
206
+ var next = require('./mcp-import-credentials').applyCredentials(row, msg.values);
207
+ cancelLogin(owner, row.id); Object.assign(row, next); persist(owner); await disconnect(owner, row.id);
208
+ } else if (msg.action === 'token') {
157
209
  if (typeof msg.token !== 'string' || !msg.token.trim() || msg.token.length > 8192 || /[\r\n]/.test(msg.token)) throw new Error('Enter a valid access token.');
158
210
  cancelLogin(owner, row.id); row.token = msg.token.trim(); row.authMode = 'token'; delete row.auth; persist(owner); await connect(owner, row);
159
- } else if (msg.action === 'signin') await signIn(owner, row, ws);
211
+ } else if (msg.action === 'signin') { if (row.source === 'local') throw new Error('This server uses process environment credentials.'); await signIn(owner, row, ws); }
160
212
  else throw new Error('Unsupported connection action.');
161
213
  }
162
214
  changed(owner);
@@ -174,6 +226,7 @@ function createRemoteConnections(ctx) {
174
226
  return serial(owner, async function () {
175
227
  authorize(); var row = find(owner, id);
176
228
  if (!row.enabled) throw new Error('Connection is disabled.');
229
+ if (!require('./mcp-tool-policy').permits(row, name)) throw new Error('Tool is excluded by the imported vendor policy.');
177
230
  var entry = live.get(key(owner, id));
178
231
  if (!entry || entry.status !== 'ready') entry = await connect(owner, row);
179
232
  authorize(); check(owner, row);
@@ -183,6 +236,7 @@ function createRemoteConnections(ctx) {
183
236
  var result;
184
237
  try { result = await entry.client.callTool({ name: name, arguments: args || {} }, undefined, { timeout: 60000 }); }
185
238
  catch (error) {
239
+ authorize(); check(owner, row);
186
240
  if (live.get(key(owner, id)) === entry) {
187
241
  entry.status = error.code === 401 || error.code === 403 || error.name === 'UnauthorizedError' ? 'auth_required' : 'unavailable';
188
242
  entry.error = entry.status === 'auth_required' ? 'Sign in again to reconnect.' : 'The tool call could not complete. Check the service before retrying.';
@@ -209,7 +263,7 @@ function createRemoteConnections(ctx) {
209
263
  closed = true; live.forEach(function (entry) { entry.client.close().catch(function () {}); }); live.clear();
210
264
  remoteFetch.close();
211
265
  }
212
- return { view: view, command: command, call: call, handleBrowser: handleBrowser, destroy: destroy,
266
+ return { view: view, command: command, importConnection: importConnection, call: call, handleBrowser: handleBrowser, destroy: destroy,
213
267
  computerEnabled: computerEnabled, toggleComputer: toggleComputer };
214
268
  }
215
269
  module.exports = { createRemoteConnections: createRemoteConnections };
@@ -0,0 +1 @@
1
+ module.exports = require("./yoke/mcp-source-adapters");
@@ -0,0 +1 @@
1
+ module.exports = require("./yoke/mcp-source-context");
@@ -0,0 +1 @@
1
+ module.exports = require("./yoke/mcp-source-discovery");
@@ -0,0 +1 @@
1
+ module.exports = require("./yoke/mcp-source-plugins");
@@ -0,0 +1 @@
1
+ module.exports = require("./yoke/mcp-source-restrictions");
@@ -0,0 +1,9 @@
1
+ var normalize = require("./yoke/mcp-tool-policy-normalize").normalize;
2
+ function matches(pattern, name) {
3
+ return new RegExp('^' + pattern.split('').map(function (letter) { return letter === '*' ? '.*' : letter === '?' ? '.' : letter.replace(/[\\^$+.[\]{}()|]/g, '\\$&'); }).join('') + '$').test(name);
4
+ }
5
+ function permits(row, name) {
6
+ if ((row.disabledTools || []).indexOf(name) >= 0 || row.enabledTools && row.enabledTools.indexOf(name) < 0) return false;
7
+ return !(row.toolPatterns || []).some(function (pattern) { return matches(pattern, row.toolPrefix ? row.toolPrefix + name : name); });
8
+ }
9
+ module.exports = { normalize: normalize, permits: permits, matches: matches };
@@ -151,40 +151,20 @@ function migrateSingleUserToMulti() {
151
151
  backupFile(path.join(config.CONFIG_DIR, "users.json"), stamp);
152
152
  backupFile(path.join(config.CONFIG_DIR, "profile.json"), stamp);
153
153
 
154
- // --- Flip to multi-user, then provision the sole admin ---
155
- // Flip first so createUser's built-in mate seeding writes to the per-user
156
- // mates path (CONFIG_DIR/mates/<userId>/), not the flat legacy path.
157
- users.enableMultiUser();
158
-
154
+ // Persist the owner credential and account mode in the same atomic write.
159
155
  var displayName = (profile && profile.name) ? String(profile.name) : "Admin";
160
156
  var created = users.createUserWithoutPin({
161
157
  username: "admin",
162
158
  displayName: displayName,
163
159
  role: "admin",
164
160
  profile: profile || undefined,
165
- });
161
+ }, { pinHash: cfg.pinHash || null });
166
162
  if (!created || !created.user) {
167
163
  console.error("[migrate] Failed to create admin user: " + (created && created.error));
168
- // Roll the flag back so we don't leave a userless multi-user deploy.
169
- try { users.disableMultiUser(); } catch (e) {}
170
164
  return { skipped: "create-failed" };
171
165
  }
172
166
  var userId = created.user.id;
173
167
 
174
- // --- Carry over the PIN hash directly (preserve the existing credential;
175
- // we have the hash, not the raw PIN, so we can't go through updateUserPin) ---
176
- if (hasPin) {
177
- try {
178
- var data = users.loadUsers();
179
- for (var i = 0; i < data.users.length; i++) {
180
- if (data.users[i].id === userId) { data.users[i].pinHash = cfg.pinHash; break; }
181
- }
182
- users.saveUsers(data);
183
- } catch (e) {
184
- console.error("[migrate] PIN carry-over failed (user will have no PIN): " + (e.message || e));
185
- }
186
- }
187
-
188
168
  // --- Carry over settings ---
189
169
  try {
190
170
  if (cfg.chatLayout !== undefined && users.setChatLayout) users.setChatLayout(userId, cfg.chatLayout);
@@ -253,7 +233,7 @@ function ensureMultiUser() {
253
233
  // Try the legacy single-user migration first (handles PIN/settings/mates/
254
234
  // session carry-over for existing deploys).
255
235
  var mig = migrateSingleUserToMulti();
256
- if (mig && mig.migrated) return mig;
236
+ if (mig && (mig.migrated || mig.skipped === "error" || mig.skipped === "create-failed")) return mig;
257
237
 
258
238
  // Fresh or empty deploy: provision a default admin so we're multi-user with
259
239
  // one user. No PIN -> the phase-1 solo auto-login skips the login wall.
@@ -0,0 +1,50 @@
1
+ // Bounded source identities shared by checklist validation and reconciliation.
2
+ function items(text) {
3
+ var lines = (text || '').split('\n').slice(1);
4
+ var occurrences = Object.create(null);
5
+ var out = [];
6
+ var fence = null;
7
+ for (var i = 0; i < lines.length; i++) {
8
+ var line = lines[i];
9
+ var match = line.match(/^\s*(\x60{3,}|~{3,})/);
10
+ if (match) { fence = fence === match[1].charAt(0) ? null : (fence || match[1].charAt(0)); continue; }
11
+ if (fence || !line.trim() || /^\s*#{1,6}\s/.test(line)) continue;
12
+ var occurrence = occurrences[line] || 0;
13
+ occurrences[line] = occurrence + 1;
14
+ var key = line + '\u0000' + occurrence;
15
+ if (i <= 1000 && key.length <= 2000 && encodeURIComponent(key).length <= 2000) out.push({ index: i, key: key });
16
+ }
17
+ return out;
18
+ }
19
+
20
+ function validState(value) {
21
+ if (!Array.isArray(value) && (!value || typeof value !== 'object')) return false;
22
+ var keys = Object.keys(value);
23
+ if (keys.length > 1000) return false;
24
+ for (var i = 0; i < keys.length; i++) {
25
+ if (keys[i].length > 2000 || typeof value[keys[i]] !== 'boolean') return false;
26
+ }
27
+ return true;
28
+ }
29
+
30
+ function normalizeState(value, text) {
31
+ var state = {};
32
+ items(text).forEach(function (item) {
33
+ var checked = value && value[Array.isArray(value) ? item.index : item.key];
34
+ if (typeof checked === 'boolean' && Object.keys(state).length < 1000) state[item.key] = checked;
35
+ });
36
+ return state;
37
+ }
38
+
39
+ function validateChange(note, changes) {
40
+ if (changes.checklistIndex === undefined) return null;
41
+ if (!Number.isInteger(changes.checklistIndex) || changes.checklistIndex < 0 || changes.checklistIndex > 1000) return null;
42
+ if (typeof changes.checklistChecked !== 'boolean' || typeof changes.checklistSource !== 'string' || typeof changes.checklistKey !== 'string') return null;
43
+ if (changes.checklistSource !== note.text || changes.checklistKey.length > 2000 || (changes.text !== undefined && changes.text !== note.text)) return null;
44
+ var item = items(note.text).find(function (item) { return item.index === changes.checklistIndex; });
45
+ var state = normalizeState(note.checklistState, note.text);
46
+ if (item && state[item.key] === undefined && Object.keys(state).length >= 1000) return null;
47
+ try { return item && item.key === decodeURIComponent(changes.checklistKey) ? item.key : null; } catch (error) { return null; }
48
+ }
49
+
50
+ module.exports = { validState: validState, normalizeState: normalizeState, validateChange: validateChange };
package/lib/notes.js CHANGED
@@ -4,6 +4,7 @@ var crypto = require("crypto");
4
4
  var config = require("./config");
5
5
  var utils = require("./utils");
6
6
  var lifecycle = require("./notes-lifecycle");
7
+ var checklist = require("./notes-checklist");
7
8
 
8
9
  function createNotesManager(opts) {
9
10
  var cwd = opts.cwd;
@@ -61,6 +62,8 @@ function createNotesManager(opts) {
61
62
  h: typeof data.h === "number" ? data.h : 180,
62
63
  color: data.color || "purple",
63
64
  opacity: typeof data.opacity === "number" ? data.opacity : 0.64,
65
+ checklistMode: data.checklistMode === true,
66
+ checklistState: checklist.validState(data.checklistState) ? checklist.normalizeState(data.checklistState, data.text || "") : [],
64
67
  minimized: false,
65
68
  // A new note is always an open attention item.
66
69
  state: lifecycle.STATE_OPEN,
@@ -84,13 +87,33 @@ function createNotesManager(opts) {
84
87
  function update(id, changes) {
85
88
  for (var i = 0; i < notes.length; i++) {
86
89
  if (notes[i].id === id) {
87
- var allowed = ["text", "x", "y", "w", "h", "color", "minimized", "zIndex", "opacity"];
90
+ if (changes.checklistConvert === true) {
91
+ if (changes.checklistSource !== notes[i].text || changes.checklistVersion !== notes[i].updatedAt || notes[i].checklistMode === true) return null;
92
+ changes = Object.assign({}, changes, { text: "", checklistState: {}, checklistMode: true });
93
+ }
94
+ if (changes.checklistEdit === true && (notes[i].checklistMode !== true || changes.checklistSource !== notes[i].text || changes.checklistVersion !== notes[i].updatedAt || typeof changes.text !== "string")) return null;
95
+ if (changes.checklistMode !== undefined && typeof changes.checklistMode !== "boolean") return null;
96
+ if (changes.checklistState !== undefined && !checklist.validState(changes.checklistState)) return null;
97
+ var checklistKey = checklist.validateChange(notes[i], changes);
98
+ if (changes.checklistIndex !== undefined && !checklistKey) return null;
99
+ var previous = {};
100
+ var snapshotKeys = ["text", "x", "y", "w", "h", "color", "minimized", "zIndex", "opacity", "checklistMode", "checklistState", "hidden", "state", "closedAt", "closedBy", "updatedAt"];
101
+ for (var s = 0; s < snapshotKeys.length; s++) previous[snapshotKeys[s]] = notes[i][snapshotKeys[s]];
102
+ var allowed = ["text", "x", "y", "w", "h", "color", "minimized", "zIndex", "opacity", "checklistMode", "checklistState"];
88
103
  for (var j = 0; j < allowed.length; j++) {
89
104
  var key = allowed[j];
90
105
  if (changes[key] !== undefined) {
91
106
  notes[i][key] = changes[key];
92
107
  }
93
108
  }
109
+ if (checklistKey) {
110
+ var state = checklist.normalizeState(notes[i].checklistState, notes[i].text);
111
+ state[checklistKey] = changes.checklistChecked === true;
112
+ notes[i].checklistState = state;
113
+ }
114
+ if (changes.text !== undefined || changes.checklistState !== undefined || checklistKey) {
115
+ notes[i].checklistState = checklist.normalizeState(notes[i].checklistState, notes[i].text);
116
+ }
94
117
  // `hidden` is the legacy spelling of the lifecycle. Route it through the
95
118
  // transitions so state, hidden, and the close provenance can never
96
119
  // disagree, and so an old client cannot half-apply a close.
@@ -98,8 +121,11 @@ function createNotesManager(opts) {
98
121
  if (changes.hidden === true) lifecycle.applyClose(notes[i], changes.actor || null, Date.now());
99
122
  else lifecycle.applyReopen(notes[i]);
100
123
  }
101
- notes[i].updatedAt = Date.now();
102
- saveToDisk();
124
+ notes[i].updatedAt = Math.max(Date.now(), (previous.updatedAt || 0) + 1);
125
+ if (!saveToDisk()) {
126
+ for (var p = 0; p < snapshotKeys.length; p++) notes[i][snapshotKeys[p]] = previous[snapshotKeys[p]];
127
+ return null;
128
+ }
103
129
  return notes[i];
104
130
  }
105
131
  }
@@ -120,6 +146,25 @@ function createNotesManager(opts) {
120
146
  return null;
121
147
  }
122
148
 
149
+ // Human close includes the visible draft and an exact canonical snapshot.
150
+ // Recheck it here, then persist draft + lifecycle/removal in one transaction.
151
+ function closeHuman(id, changes, actor) {
152
+ for (var i = 0; i < notes.length; i++) {
153
+ var note = notes[i];
154
+ if (note.id !== id) continue;
155
+ if (note.text !== changes.expectedText || note.updatedAt !== changes.expectedVersion || typeof changes.draftText !== "string") return null;
156
+ if (!changes.draftText.trim()) {
157
+ notes.splice(i, 1);
158
+ if (saveToDisk()) return { removed: note };
159
+ notes.splice(i, 0, note);
160
+ return null;
161
+ }
162
+ var updated = update(id, { text: changes.draftText, hidden: true, actor: actor });
163
+ return updated ? { note: updated } : null;
164
+ }
165
+ return null;
166
+ }
167
+
123
168
  // Reopen a closed note. Idempotent.
124
169
  function reopen(id) {
125
170
  for (var i = 0; i < notes.length; i++) {
@@ -211,6 +256,7 @@ function createNotesManager(opts) {
211
256
  create: create,
212
257
  update: update,
213
258
  close: close,
259
+ closeHuman: closeHuman,
214
260
  reopen: reopen,
215
261
  remove: remove,
216
262
  removeClosed: removeClosed,
@@ -17,12 +17,10 @@ function commandAvailable(command, execFile) {
17
17
 
18
18
  function credentialPaths(home) {
19
19
  if (!home) return [];
20
- return [
21
- home + "/.claude",
22
- home + "/.codex",
20
+ return require("./yoke/maintenance").credentialPaths(home).concat([
23
21
  home + "/.config/gh",
24
22
  home + "/.config/gcloud",
25
- ];
23
+ ]);
26
24
  }
27
25
 
28
26
  function accessStatus(checks) {