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
@@ -1,17 +1,17 @@
1
1
  var crypto = require("crypto");
2
- var fs = require("fs");
3
- var path = require("path");
4
- var Datastore = require("@seald-io/nedb");
5
2
  var validation = require("./knowledge-db-validation");
3
+ var imports = require("./knowledge-db-import");
4
+ var storageModule = require("./knowledge-db-storage");
6
5
 
7
6
  var MAX_HISTORY = 50;
8
7
  var MAX_RECEIPTS = 500;
9
8
  var MAX_PAGE = 100;
10
9
  var MAX_FILTERS = 20;
11
10
  var MAX_SORTS = 10;
12
- var MAX_AGGREGATE_BYTES = 8 * 1024 * 1024;
11
+ // Synthetic imports use 8.36 MB for 8563 narrative rows and exceed 8 MiB at
12
+ // 11400 short rows. Keep finite headroom for the 20000-row envelope and history.
13
+ var MAX_AGGREGATE_BYTES = 16 * 1024 * 1024;
13
14
  var IDEMPOTENCY_WINDOW_MS = 24 * 60 * 60 * 1000;
14
- var STORE_REGISTRY = {};
15
15
 
16
16
  function clone(value) { return JSON.parse(JSON.stringify(value)); }
17
17
  function error(message, code, currentRevision) { return Object.assign(new Error(message), { code: code || "FAILED", currentRevision: currentRevision }); }
@@ -30,7 +30,7 @@ function canonical(value) {
30
30
  if (!value || typeof value !== "object") return value;
31
31
  var out = {}; Object.keys(value).sort().forEach(function (key) { out[key] = canonical(value[key]); }); return out;
32
32
  }
33
- function fingerprint(label, args) { var envelope = Object.assign({}, args); delete envelope.actor; delete envelope.operationId; return crypto.createHash("sha256").update(label + ":" + JSON.stringify(canonical(envelope))).digest("hex"); }
33
+ function fingerprint(label, args) { var envelope = Object.assign({}, args); delete envelope.actor; delete envelope.operationId; delete envelope.revalidate; return crypto.createHash("sha256").update(label + ":" + JSON.stringify(canonical(envelope))).digest("hex"); }
34
34
  function ensureRevision(value, current, label) {
35
35
  if (!Number.isInteger(value) || value < 1) throw error("A valid " + label + " revision is required.", "STALE", current);
36
36
  if (value !== current) throw error("This " + label + " changed since it was opened.", "STALE", current);
@@ -107,49 +107,39 @@ function queryRecords(database, args, databases, settings) {
107
107
  }
108
108
 
109
109
  function createKnowledgeDbService(options) {
110
- var settings = options || {}; var projectDir = path.resolve(settings.projectDir); var projectReal = null; var knowledgeDir = path.join(projectDir, "knowledge"); var dataDir = path.join(knowledgeDir, ".clay-db"); var filename = path.join(dataDir, "databases.db");
110
+ var settings = options || {}; var storage = storageModule.createKnowledgeDbStorage(settings);
111
111
  var aggregateLimit = Number.isInteger(settings.maxAggregateBytes) && settings.maxAggregateBytes > 1024 ? Math.min(MAX_AGGREGATE_BYTES, settings.maxAggregateBytes) : MAX_AGGREGATE_BYTES;
112
- var entry = STORE_REGISTRY[filename];
113
- if (!entry) { entry = { queues: {}, database: null, loading: null, ready: false }; STORE_REGISTRY[filename] = entry; }
114
- function safeDirectory(target, create) {
115
- var stat; try { stat = fs.lstatSync(target); } catch (cause) { if (!create || cause.code !== "ENOENT") throw cause; fs.mkdirSync(target, { recursive: true, mode: 0o700 }); stat = fs.lstatSync(target); }
116
- if (!stat.isDirectory() || stat.isSymbolicLink()) throw error("Knowledge database path is unsafe.", "UNSAFE_PATH");
117
- var real = fs.realpathSync(target); if (real !== projectReal && !real.startsWith(projectReal + path.sep)) throw error("Knowledge database path escapes the Mate project.", "UNSAFE_PATH");
118
- }
119
- function open() {
120
- if (entry.loading) return entry.loading;
121
- entry.loading = Promise.resolve().then(function () { projectReal = fs.realpathSync(projectDir); safeDirectory(knowledgeDir, true); safeDirectory(dataDir, true); var stat; try { stat = fs.lstatSync(filename); } catch (cause) { if (cause.code !== "ENOENT") throw cause; }
122
- if (stat && (!stat.isFile() || stat.isSymbolicLink())) throw error("Knowledge database file is unsafe.", "UNSAFE_PATH"); entry.database = new Datastore({ filename: filename }); return entry.database.loadDatabaseAsync(); }).then(function () { return entry.database.ensureIndexAsync({ fieldName: "_id", unique: true }); }).then(function () { entry.ready = true; return entry.database; }).catch(function (cause) { entry.database = null; entry.loading = null; entry.ready = false; throw cause; });
123
- return entry.loading;
124
- }
125
- function serialize(key, work) { var previous = entry.queues[key] || Promise.resolve(); var next = previous.catch(function () {}).then(work); entry.queues[key] = next.catch(function () {}); return next; }
126
- function load(id) { return open().then(function (store) { return store.findOneAsync({ _id: validation.id(id, "database id") }); }).then(function (found) { if (!found) throw error("Knowledge database not found.", "NOT_FOUND"); return found; }); }
127
- function all() { return open().then(function (store) { return store.findAsync({}); }); }
128
- function listCached(args) { var items = entry.database ? entry.database.getAllData() : []; return { databases: items.filter(function (item) { return args && args.archived === true ? !!item.archivedAt : !item.archivedAt; }).sort(function (a, b) { return b.updatedAt - a.updatedAt || (a._id === b._id ? 0 : a._id < b._id ? -1 : 1); }).map(function (item) { return publicDatabase(item, false); }) }; }
129
- function assertAggregate(next) { if (Buffer.byteLength(JSON.stringify(next), "utf8") > aggregateLimit) throw error("Knowledge database reached its storage limit.", "LIMIT"); }
130
- function replace(current, next) { assertAggregate(next); return entry.database.updateAsync({ _id: current._id, revision: current.revision }, next, {}).then(function (result) { if (result.numAffected !== 1) throw error("This database changed during the operation.", "STALE", current.revision); return next; }); }
112
+ function serialize(key, work) { return storage.serialize(key, work); }
113
+ function load(id) { return storage.get(validation.id(id, "database id")).then(function (found) { if (!found) throw error("Knowledge database not found.", "NOT_FOUND"); return found; }); }
114
+ function all() { return storage.list(); }
115
+ function listCached(args) { var items = storage.getCached(); return { databases: items.filter(function (item) { return args && args.archived === true ? !!item.archivedAt : !item.archivedAt; }).sort(function (a, b) { return b.updatedAt - a.updatedAt || (a._id === b._id ? 0 : a._id < b._id ? -1 : 1); }).map(function (item) { return publicDatabase(item, false); }) }; }
116
+ function assertAggregate(next) { if (Buffer.byteLength(JSON.stringify(next), "utf8") > aggregateLimit) throw error("Knowledge database exceeds the " + aggregateLimit + " byte aggregate storage limit (records, history, mappings and live receipts).", "LIMIT"); }
117
+ function guard(args, current, phase) { if (args && typeof args.revalidate === 'function') args.revalidate(current ? publicDatabase(current, false) : null, phase); }
118
+ function replace(current, next, control) { assertAggregate(next); guard(control, current, 'saving'); return storage.replaceIfRevision(current._id, current.revision, next).then(function (replaced) { if (typeof replaced !== "boolean") throw storageModule.invalid("replaceIfRevision must resolve to a boolean."); if (!replaced) throw Object.assign(error("This database changed during the operation.", "STALE", current.revision), { persisted: false }); guard(control, null, "saved"); return next; }); }
131
119
  function projectionContent(value) { return JSON.stringify({ schemaVersion: 1, namespace: "knowledge-database-summary", databaseId: value._id, name: value.name, archived: !!value.archivedAt, revision: value.revision, fields: value.schema.filter(function (field) { return !field.archived; }).map(function (field) { return { id: field.id, name: field.name, type: field.type }; }), views: (value.views || []).filter(function (view) { return !view.archived; }).map(function (view) { return { id: view.id, name: view.name, type: "table" }; }), recordCount: value.records.filter(function (record) { return !record.archivedAt; }).length }); }
132
120
  function project(value, actorValue) {
133
121
  if (typeof settings.projectSummary !== "function") return Promise.resolve({ pending: false });
134
122
  return Promise.resolve().then(function () { return settings.projectSummary({ databaseId: value._id, name: value.name, revision: value.revision, archived: !!value.archivedAt, content: projectionContent(value), actor: actorValue }); }).then(function () {
135
- var clean = clone(value); clean.projectionPending = false; clean.projectionError = null; return entry.database.updateAsync({ _id: value._id, revision: value.revision }, clean, {}).then(function (result) { if (result.numAffected !== 1) return { pending: true, error: "A newer database revision still needs summary projection." }; return { pending: false }; });
136
- }).catch(function (cause) { var message = cause.message || "Knowledge database summary projection failed."; var failed = clone(value); failed.projectionPending = true; failed.projectionError = message; return entry.database.updateAsync({ _id: value._id, revision: value.revision }, failed, {}).then(function () { return { pending: true, error: message }; }, function () { return { pending: true, error: message }; }); });
123
+ var clean = clone(value); clean.projectionPending = false; clean.projectionError = null; return replace(value, clean).then(function () { return { pending: false }; });
124
+ }).catch(function (cause) { var message = cause.message || "Knowledge database summary projection failed."; var failed = clone(value); failed.projectionPending = true; failed.projectionError = message; return replace(value, failed).then(function () { return { pending: true, error: message }; }, function () { return { pending: true, error: message }; }); });
137
125
  }
138
126
  function finish(value, result, actorValue) { return project(value, actorValue).then(function (projection) { return Object.assign({}, result, { projectionPending: projection.pending, projectionError: projection.error || null }); }); }
139
127
  function mutate(databaseId, args, label, fn) {
140
128
  var operationId = mutationId(args.operationId); var operationFingerprint = fingerprint(label, args); return serialize(databaseId, function () { return load(databaseId).then(function (current) {
129
+ guard(args, current);
141
130
  var duplicate = receipt(current, operationId, operationFingerprint); if (duplicate) return Object.assign({}, duplicate, { projectionPending: current.projectionPending === true, projectionError: current.projectionError || null });
142
131
  if (current.archivedAt && label !== "database") throw error("Knowledge database is archived.", "ARCHIVED", current.revision);
143
- var next = clone(current); var result = fn(next, current); next.projectionPending = true; next.projectionError = null; remember(next, operationId, operationFingerprint, result); return replace(current, next).then(function () { return finish(next, result, actor(args.actor)); });
132
+ var next = clone(current); var result = fn(next, current); next.projectionPending = true; next.projectionError = null; remember(next, operationId, operationFingerprint, result); return replace(current, next, args).then(function () { return finish(next, result, actor(args.actor)); });
144
133
  }); });
145
134
  }
146
135
  function create(args) {
147
136
  var input = args || {}; var operationId = mutationId(input.operationId); var operationFingerprint = fingerprint("create", input); return serialize("create:" + operationId, function () { return all().then(function (items) {
137
+ guard(input);
148
138
  var duplicate; var duplicateDatabase; items.some(function (item) { duplicate = receipt(item, operationId, operationFingerprint); if (duplicate) duplicateDatabase = item; return !!duplicate; }); if (duplicate) return Object.assign({}, duplicate, { projectionPending: duplicateDatabase.projectionPending === true, projectionError: duplicateDatabase.projectionError || null });
149
139
  var at = now(); var who = actor(input.actor); var titleId = newId("fld"); var schema = input.schema ? validation.normalizeSchema(input.schema) : validation.normalizeSchema([{ id: titleId, name: "Name", type: "title", required: true }]);
150
140
  var viewId = newId("view"); var item = { _id: newId("db"), name: validation.text(input.name, "Database name", 120, false), revision: 1, archivedAt: null, schema: schema,
151
141
  views: [{ id: viewId, name: "Table", type: "table", columns: schema.filter(function (field) { return !field.archived; }).map(function (field) { return field.id; }), filters: [], sorts: [], archived: false }], records: [], recordHistory: {}, databaseHistory: [], receipts: [], createdAt: at, updatedAt: at, createdBy: who, updatedBy: who, projectionPending: true, projectionError: null };
152
- var result = { database: publicDatabase(item, false) }; remember(item, operationId, operationFingerprint, result); assertAggregate(item); return open().then(function (store) { return store.insertAsync(item); }).then(function () { return finish(item, result, who); });
142
+ var result = { database: publicDatabase(item, false) }; remember(item, operationId, operationFingerprint, result); assertAggregate(item); guard(input, null, "saving"); return storage.insert(item).then(function () { guard(input, null, "saved"); return finish(item, result, who); });
153
143
  }); });
154
144
  }
155
145
  function list(args) { return all().then(function (items) { return { databases: items.filter(function (item) { return args && args.archived === true ? !!item.archivedAt : !item.archivedAt; }).sort(function (a, b) { return b.updatedAt - a.updatedAt || (a._id === b._id ? 0 : a._id < b._id ? -1 : 1); }).map(function (item) { return publicDatabase(item, false); }) }; }); }
@@ -163,13 +153,14 @@ function createKnowledgeDbService(options) {
163
153
  function updateSchema(args) { return mutate(args.databaseId, args, "schema", function (next, current) { ensureRevision(args.expectedRevision, current.revision, "database"); var schema = validation.normalizeSchema(args.schema); validation.assertCompatibleSchema(current.schema, schema, current.records); next.databaseHistory = next.databaseHistory.concat([{ revision: current.revision, at: now(), actor: actor(args.actor), action: "schema", schema: current.schema }]).slice(-MAX_HISTORY); next.schema = schema; next.views = reconcileViews(next.views, schema); next.revision++; next.updatedAt = now(); next.updatedBy = actor(args.actor); return { database: publicDatabase(next, false) }; }); }
164
154
  function saveView(args) { return mutate(args.databaseId, args, "view", function (next, current) { ensureRevision(args.expectedRevision, current.revision, "database"); var view = validation.normalizeView(args.view, current.schema); var index = next.views.findIndex(function (entry) { return entry.id === view.id; }); if (index === -1 && next.views.length >= validation.MAX_VIEWS) throw error("Database has too many views.", "LIMIT"); if (index === -1) next.views.push(view); else next.views[index] = view; next.revision++; next.updatedAt = now(); next.updatedBy = actor(args.actor); return { database: publicDatabase(next, false), view: clone(view) }; }); }
165
155
  function referenceContext(databases, current) { return { authorizeReference: function (reference) { if (reference.type === "text") return typeof settings.authorizeTextReference === "function" && settings.authorizeTextReference(reference.id) === true; var target = databases.filter(function (item) { return item._id === reference.databaseId; })[0]; return !!(target && target.records.some(function (record) { return record.id === reference.id; })); } }; }
166
- function createRecord(args) { return all().then(function (databases) { return mutate(args.databaseId, args, "record", function (next, current) { ensureRevision(args.expectedDatabaseRevision, current.revision, "database"); if (next.records.length >= validation.MAX_RECORDS) throw error("Database reached the record limit.", "LIMIT"); var at = now(); var who = actor(args.actor); var record = { id: newId("rec"), revision: 1, values: validation.normalizeValues(args.values || {}, current.schema, referenceContext(databases, current), null), archivedAt: null, createdAt: at, updatedAt: at, createdBy: who, updatedBy: who }; next.records.push(record); next.recordHistory[record.id] = []; next.revision++; next.updatedAt = at; next.updatedBy = who; return { databaseRevision: next.revision, record: publicRecord(record) }; }); }); }
156
+ function createRecord(args) { return all().then(function (databases) { return mutate(args.databaseId, args, "record", function (next, current) { ensureRevision(args.expectedDatabaseRevision, current.revision, "database"); if (next.records.length >= validation.MAX_RECORDS) throw error("Database exceeds the " + validation.MAX_RECORDS + " record limit (including archived records).", "LIMIT"); var at = now(); var who = actor(args.actor); var record = { id: newId("rec"), revision: 1, values: validation.normalizeValues(args.values || {}, current.schema, referenceContext(databases, current), null), archivedAt: null, createdAt: at, updatedAt: at, createdBy: who, updatedBy: who }; next.records.push(record); next.recordHistory[record.id] = []; next.revision++; next.updatedAt = at; next.updatedBy = who; return { databaseRevision: next.revision, record: publicRecord(record) }; }); }); }
167
157
  function updateRecord(args) { return all().then(function (databases) { return mutate(args.databaseId, args, "record", function (next, current) { var index = next.records.findIndex(function (record) { return record.id === validation.id(args.recordId, "record id"); }); if (index === -1) throw error("Knowledge database record not found.", "NOT_FOUND"); var before = next.records[index]; ensureRevision(args.expectedRevision, before.revision, "record"); if (before.archivedAt) throw error("Knowledge database record is archived.", "ARCHIVED", before.revision); next.recordHistory[before.id] = (next.recordHistory[before.id] || []).concat([{ revision: before.revision, at: now(), actor: actor(args.actor), action: "update", values: before.values }]).slice(-MAX_HISTORY); var record = clone(before); record.values = validation.normalizeValues(args.values || {}, current.schema, referenceContext(databases, current), record.values); record.revision++; record.updatedAt = now(); record.updatedBy = actor(args.actor); next.records[index] = record; next.revision++; next.updatedAt = record.updatedAt; next.updatedBy = record.updatedBy; return { databaseRevision: next.revision, record: publicRecord(record) }; }); }); }
168
158
  function archiveRecord(args) { return mutate(args.databaseId, args, "record", function (next) { var index = next.records.findIndex(function (record) { return record.id === validation.id(args.recordId, "record id"); }); if (index === -1) throw error("Knowledge database record not found.", "NOT_FOUND"); var before = next.records[index]; ensureRevision(args.expectedRevision, before.revision, "record"); next.recordHistory[before.id] = (next.recordHistory[before.id] || []).concat([{ revision: before.revision, at: now(), actor: actor(args.actor), action: args.recover === true ? "recover" : "archive", values: before.values, archivedAt: before.archivedAt }]).slice(-MAX_HISTORY); var record = clone(before); record.archivedAt = args.recover === true ? null : now(); record.revision++; record.updatedAt = now(); record.updatedBy = actor(args.actor); next.records[index] = record; next.revision++; next.updatedAt = record.updatedAt; next.updatedBy = record.updatedBy; return { databaseRevision: next.revision, record: publicRecord(record) }; }); }
169
159
  function readRecord(args) { return all().then(function (databases) { var item = databases.filter(function (entry) { return entry._id === validation.id(args.databaseId, "database id"); })[0]; if (!item) throw error("Knowledge database not found.", "NOT_FOUND"); var record = item.records.filter(function (entry) { return entry.id === validation.id(args.recordId, "record id"); })[0]; if (!record) throw error("Knowledge database record not found.", "NOT_FOUND"); return { database: publicDatabase(item, false), record: publicRecord(record, referenceStates(item, record, databases, settings)), title: titleValue(item, record), history: clone(item.recordHistory[record.id] || []) }; }); }
170
160
  function query(args) { return all().then(function (databases) { var item = databases.filter(function (entry) { return entry._id === validation.id(args.databaseId, "database id"); })[0]; if (!item) throw error("Knowledge database not found.", "NOT_FOUND"); if (item.archivedAt) throw error("Knowledge database is archived.", "ARCHIVED", item.revision); return queryRecords(item, args, databases, settings); }); }
171
- function retryProjection(args) { return serialize(args.databaseId, function () { return load(args.databaseId).then(function (item) { return finish(item, { database: publicDatabase(item, false) }, actor(args.actor)); }); }); }
172
- return { filename: filename, hasStore: function () { try { return fs.lstatSync(filename).isFile(); } catch (cause) { return false; } }, isReady: function () { return entry.ready === true; }, initialize: open, listCached: listCached, create: create, list: list, read: read, rename: rename, archive: archive, recover: function (args) { return archive(Object.assign({}, args, { recover: true })); }, updateSchema: updateSchema, saveView: saveView, createRecord: createRecord, updateRecord: updateRecord, archiveRecord: archiveRecord, recoverRecord: function (args) { return archiveRecord(Object.assign({}, args, { recover: true })); }, readRecord: readRecord, query: query, retryProjection: retryProjection };
161
+ function retryProjection(args) { return serialize(args.databaseId, function () { return load(args.databaseId).then(function (item) { guard(args, item, "saving"); return finish(item, { database: publicDatabase(item, false) }, actor(args.actor)).then(function (result) { guard(args, null, "saved"); return result; }); }); }); }
162
+ var importer = imports.attachKnowledgeDbImport({ clone: clone, error: error, actor: actor, newId: newId, mutationId: mutationId, fingerprint: fingerprint, ensureRevision: ensureRevision, receipt: receipt, remember: remember, serialize: serialize, load: load, all: all, referenceContext: referenceContext, replace: replace, guard: guard, finish: finish });
163
+ return { readStorageStatus: function () { return typeof storage.diagnostics === "function" ? storage.diagnostics() : Promise.resolve(null); }, importRecords: importer.importRecords, readImportProgress: importer.readImportProgress, hasStore: function () { return storage.hasStore(); }, isReady: function () { return storage.isReady(); }, initialize: function () { return Promise.resolve(storage.initialize()).then(function () {}); }, listCached: listCached, create: create, list: list, read: read, rename: rename, archive: archive, recover: function (args) { return archive(Object.assign({}, args, { recover: true })); }, updateSchema: updateSchema, saveView: saveView, createRecord: createRecord, updateRecord: updateRecord, archiveRecord: archiveRecord, recoverRecord: function (args) { return archiveRecord(Object.assign({}, args, { recover: true })); }, readRecord: readRecord, query: query, retryProjection: retryProjection };
173
164
  }
174
165
 
175
166
  module.exports = { createKnowledgeDbService: createKnowledgeDbService, MAX_HISTORY: MAX_HISTORY, MAX_PAGE: MAX_PAGE, MAX_AGGREGATE_BYTES: MAX_AGGREGATE_BYTES, IDEMPOTENCY_WINDOW_MS: IDEMPOTENCY_WINDOW_MS };
@@ -0,0 +1,99 @@
1
+ var fs = require("fs");
2
+
3
+ var MIN_COMPACTION_BYTES = 1024 * 1024;
4
+ var MAX_WRITE_AMPLIFICATION = 3;
5
+ var MAX_WRITES_WITHOUT_COMPACTION = 64;
6
+ var FAILURE_HEADROOM_BYTES = 4 * 1024 * 1024;
7
+ var FAILURE_AMPLIFICATION = 6;
8
+
9
+ // Shared by every service instance for this filename. No interval or background work:
10
+ // maintenance runs inside the same I/O gate as writes, reads and failed-write reloads.
11
+ function attachKnowledgeDbNedbMaintenance(ctx) {
12
+ var entry = ctx.entry;
13
+ if (!entry.storage) entry.storage = {
14
+ queue: Promise.resolve(), store: null, cached: [], sizes: new Map(), liveBytes: 0,
15
+ journalBytes: 0, peakJournalBytes: 0, journalUnknown: false, successfulWrites: 0,
16
+ writesSinceCompaction: 0, compactions: 0, failedCompactions: 0, recoveries: 0,
17
+ maintenancePending: false, maintenanceError: null
18
+ };
19
+ var state = entry.storage;
20
+ function enqueue(work) {
21
+ var next = state.queue.catch(function () {}).then(work);
22
+ state.queue = next.catch(function () {}); return next;
23
+ }
24
+ function size(value) { return Buffer.byteLength(JSON.stringify(value), "utf8") + 1; }
25
+ function refresh(store) {
26
+ state.store = store; state.cached = store.getAllData(); state.sizes = new Map(); state.liveBytes = 0;
27
+ state.cached.forEach(function (value) { var bytes = size(value); state.sizes.set(value._id, bytes); state.liveBytes += bytes; });
28
+ }
29
+ function issue(cause) { state.maintenancePending = true; state.maintenanceError = cause.message || String(cause); }
30
+ async function measure() {
31
+ try {
32
+ state.journalBytes = (await fs.promises.stat(ctx.filename)).size; state.journalUnknown = false;
33
+ state.peakJournalBytes = Math.max(state.peakJournalBytes, state.journalBytes);
34
+ return true;
35
+ } catch (cause) { state.journalUnknown = true; issue(cause); return false; }
36
+ }
37
+ async function ensure() {
38
+ var store = await ctx.open();
39
+ if (state.store !== store) { refresh(store); await measure(); }
40
+ return store;
41
+ }
42
+ async function compact(store) {
43
+ try {
44
+ // Supported datastore API also participates in NeDB's own executor.
45
+ await store.compactDatafileAsync();
46
+ state.compactions++; state.writesSinceCompaction = 0;
47
+ if (await measure()) { state.maintenancePending = false; state.maintenanceError = null; }
48
+ } catch (cause) { state.failedCompactions++; issue(cause); await measure(); }
49
+ }
50
+ function due() {
51
+ return state.journalBytes > Math.max(MIN_COMPACTION_BYTES, MAX_WRITE_AMPLIFICATION * state.liveBytes) ||
52
+ state.writesSinceCompaction >= MAX_WRITES_WITHOUT_COMPACTION && state.journalBytes - state.liveBytes >= MIN_COMPACTION_BYTES;
53
+ }
54
+ function blocked() {
55
+ return state.maintenancePending && (state.journalUnknown || state.journalBytes > Math.max(FAILURE_HEADROOM_BYTES, FAILURE_AMPLIFICATION * state.liveBytes));
56
+ }
57
+ function read(work) { return enqueue(async function () { return work(await ensure()); }); }
58
+ function write(work, value) {
59
+ return enqueue(async function () {
60
+ var store = await ensure(); var attempted = false;
61
+ if (state.maintenancePending) { attempted = true; await compact(store); }
62
+ // Repeated maintenance failure cannot allow unbounded journal growth. This
63
+ // rejection happens before the next canonical write, never after its success.
64
+ if (blocked()) throw Object.assign(new Error("Knowledge database maintenance must recover before more writes: " + state.maintenanceError), { code: "STORAGE_MAINTENANCE_BLOCKED" });
65
+ var result;
66
+ try { result = await work(store); }
67
+ catch (cause) {
68
+ // NeDB changes indexes before appending. Hold the shared gate through reload
69
+ // so another database cannot compact or persist an unsaved in-memory state.
70
+ try {
71
+ await store.loadDatabaseAsync(); refresh(store); state.recoveries++; state.writesSinceCompaction = 0;
72
+ if (await measure()) { state.maintenancePending = false; state.maintenanceError = null; }
73
+ } catch (recoveryCause) { state.store = null; state.cached = []; issue(recoveryCause); ctx.invalidate(); }
74
+ throw cause;
75
+ }
76
+ if (result && result.numAffected === 0) return result;
77
+ var bytes = size(value); state.liveBytes += bytes - (state.sizes.get(value._id) || 0); state.sizes.set(value._id, bytes);
78
+ state.cached = store.getAllData(); state.successfulWrites++; state.writesSinceCompaction++;
79
+ if (await measure() && !attempted && due()) await compact(store);
80
+ // A maintenance error never changes a successful canonical write into a failure.
81
+ return result;
82
+ });
83
+ }
84
+ function status() {
85
+ return read(async function () {
86
+ await measure();
87
+ return { maintenancePending: state.maintenancePending, maintenanceError: state.maintenanceError,
88
+ liveBytes: state.liveBytes, journalBytes: state.journalBytes, peakJournalBytes: state.peakJournalBytes,
89
+ successfulWrites: state.successfulWrites, writesSinceCompaction: state.writesSinceCompaction,
90
+ compactions: state.compactions, failedCompactions: state.failedCompactions, recoveries: state.recoveries };
91
+ });
92
+ }
93
+ return { read: read, write: write, cached: function () { return state.cached; }, readStorageStatus: status };
94
+ }
95
+
96
+ module.exports = { attachKnowledgeDbNedbMaintenance: attachKnowledgeDbNedbMaintenance,
97
+ MIN_COMPACTION_BYTES: MIN_COMPACTION_BYTES, MAX_WRITE_AMPLIFICATION: MAX_WRITE_AMPLIFICATION,
98
+ MAX_WRITES_WITHOUT_COMPACTION: MAX_WRITES_WITHOUT_COMPACTION,
99
+ FAILURE_HEADROOM_BYTES: FAILURE_HEADROOM_BYTES, FAILURE_AMPLIFICATION: FAILURE_AMPLIFICATION };
@@ -0,0 +1,66 @@
1
+ var fs = require("fs");
2
+ var path = require("path");
3
+ var Datastore = require("@seald-io/nedb");
4
+ var maintenance = require("./knowledge-db-storage-nedb-maintenance");
5
+ var STORE_REGISTRY = new Map();
6
+
7
+ function clone(value) { return JSON.parse(JSON.stringify(value)); }
8
+ function error(message, code) { return Object.assign(new Error(message), { code: code }); }
9
+ function createKnowledgeDbNedbStorage(options) {
10
+ var projectDir = path.resolve(options.projectDir); var projectReal = null;
11
+ var knowledgeDir = path.join(projectDir, "knowledge"); var dataDir = path.join(knowledgeDir, ".clay-db");
12
+ var filename = path.join(dataDir, "databases.db"); var entry = STORE_REGISTRY.get(filename);
13
+ if (!entry) { entry = { queues: new Map(), database: null, loading: null, ready: false }; STORE_REGISTRY.set(filename, entry); }
14
+ function safeDirectory(target, create) {
15
+ var stat;
16
+ try { stat = fs.lstatSync(target); }
17
+ catch (cause) { if (!create || cause.code !== "ENOENT") throw cause; fs.mkdirSync(target, { recursive: true, mode: 0o700 }); stat = fs.lstatSync(target); }
18
+ if (!stat.isDirectory() || stat.isSymbolicLink()) throw error("Knowledge database path is unsafe.", "UNSAFE_PATH");
19
+ var real = fs.realpathSync(target);
20
+ if (real !== projectReal && !real.startsWith(projectReal + path.sep)) throw error("Knowledge database path escapes the Mate project.", "UNSAFE_PATH");
21
+ }
22
+ function open() {
23
+ if (entry.loading) return entry.loading;
24
+ entry.loading = Promise.resolve().then(function () {
25
+ projectReal = fs.realpathSync(projectDir); safeDirectory(knowledgeDir, true); safeDirectory(dataDir, true);
26
+ var stat; try { stat = fs.lstatSync(filename); } catch (cause) { if (cause.code !== "ENOENT") throw cause; }
27
+ if (stat && (!stat.isFile() || stat.isSymbolicLink())) throw error("Knowledge database file is unsafe.", "UNSAFE_PATH");
28
+ entry.database = new Datastore({ filename: filename }); return entry.database.loadDatabaseAsync();
29
+ }).then(function () { return entry.database.ensureIndexAsync({ fieldName: "_id", unique: true }); })
30
+ .then(function () { entry.ready = true; return entry.database; })
31
+ .catch(function (cause) { invalidate(); throw cause; });
32
+ return entry.loading;
33
+ }
34
+ function invalidate() { entry.database = null; entry.loading = null; entry.ready = false; }
35
+ var io = maintenance.attachKnowledgeDbNedbMaintenance({ entry: entry, filename: filename, open: open, invalidate: invalidate });
36
+ function serialize(scope, work) {
37
+ var previous = entry.queues.get(scope) || Promise.resolve(); var next = previous.catch(function () {}).then(function () { return work(); });
38
+ entry.queues.set(scope, next.catch(function () {})); return next;
39
+ }
40
+ function insert(snapshot) {
41
+ var value = clone(snapshot);
42
+ return io.write(function (store) { return store.insertAsync(value); }, value).then(function () {}, function (cause) {
43
+ if (cause.errorType === "uniqueViolated") throw error("Knowledge storage identity already exists.", "ALREADY_EXISTS");
44
+ throw cause;
45
+ });
46
+ }
47
+ function replaceIfRevision(id, revision, snapshot) {
48
+ var value = clone(snapshot);
49
+ if (value._id !== id) return Promise.reject(error("Knowledge storage replacement identity must match.", "INVALID_STORAGE_ID"));
50
+ return io.write(function (store) { return store.updateAsync({ _id: id, revision: revision }, value, {}); }, value)
51
+ .then(function (result) { return result.numAffected === 1; });
52
+ }
53
+ return {
54
+ contractVersion: 1,
55
+ initialize: function () { return io.read(function () {}); },
56
+ hasStore: function () { try { return fs.lstatSync(filename).isFile(); } catch (cause) { return false; } },
57
+ isReady: function () { return entry.ready === true; },
58
+ get: function (id) { return io.read(function (store) { return store.findOneAsync({ _id: id }); }); },
59
+ list: function () { return io.read(function (store) { return store.findAsync({}); }); },
60
+ getCached: function () { return clone(io.cached()); },
61
+ insert: insert, replaceIfRevision: replaceIfRevision, serialize: serialize,
62
+ diagnostics: function () { return io.readStorageStatus().then(function (status) { return Object.assign({ engine: "nedb", automaticCompaction: false }, status); }); }
63
+ };
64
+ }
65
+
66
+ module.exports = { createKnowledgeDbNedbStorage: createKnowledgeDbNedbStorage };
@@ -0,0 +1,72 @@
1
+ // Version 1 persists opaque JSON aggregate snapshots with a stable _id and revision.
2
+ // _id is the existing Knowledge identity, not a query expression. Engines may map it
3
+ // to their own primary key; aggregate format/limits remain application responsibilities.
4
+ // Each adapter is bound to one server-authorized Mate-project store; get/list cannot
5
+ // broaden that scope. Facades for the same store must share locks and committed cache.
6
+ //
7
+ // initialize() -> Promise<void>; hasStore()/isReady() -> boolean.
8
+ // get(id) -> Promise<snapshot|null>; list() -> Promise<snapshot[]>;
9
+ // getCached() -> snapshot[] (committed, detached, no initialization side effect).
10
+ // insert(snapshot) -> Promise<void> (reject ALREADY_EXISTS; never overwrite).
11
+ // replaceIfRevision(id, revision, snapshot) -> Promise<boolean>: atomic compare and
12
+ // full replacement, false on missing/mismatch without writing. Same-revision writes
13
+ // are allowed for receipts/projection status. Identity must remain unchanged.
14
+ // serialize(scope, work) -> Promise<result>: same-scope callbacks exclude each other
15
+ // across all facades of one physical store. Callback receives no engine objects and
16
+ // may await adapter operations; this is not a multi-aggregate transaction or I/O lock.
17
+ // Engines separately serialize reads/writes/maintenance/recovery as needed. A failed
18
+ // write may have committed durably; restore readable committed state before releasing
19
+ // the I/O gate, or invalidate it. Never turn committed success into maintenance failure.
20
+ // Domain operation receipts resolve ambiguous retries; the adapter does not own them.
21
+ // diagnostics() -> Promise<JSON> is optional, engine-specific and never a native handle.
22
+
23
+ var METHODS = ["initialize", "hasStore", "isReady", "get", "list", "getCached", "insert", "replaceIfRevision", "serialize"];
24
+ function invalid(message) { return Object.assign(new Error("Invalid Knowledge storage adapter: " + message), { code: "INVALID_STORAGE_ADAPTER" }); }
25
+ function validateAdapter(adapter) {
26
+ if (!adapter || typeof adapter !== "object" || adapter.contractVersion !== 1) throw invalid("contractVersion must be 1.");
27
+ METHODS.forEach(function (name) { if (typeof adapter[name] !== "function") throw invalid(name + " must be a function."); });
28
+ if (adapter.diagnostics !== undefined && typeof adapter.diagnostics !== "function") throw invalid("diagnostics must be a function when supplied.");
29
+ return adapter;
30
+ }
31
+ function bindAdapter(adapter) {
32
+ function snapshot(value) {
33
+ if (!value || Object.getPrototypeOf(value) !== Object.prototype || typeof value._id !== "string" || !Number.isInteger(value.revision)) throw invalid("snapshot must be a plain aggregate with _id and integer revision.");
34
+ return value;
35
+ }
36
+ function snapshots(values) { if (!Array.isArray(values)) throw invalid("list/getCached must return an array."); values.forEach(snapshot); return values; }
37
+ function call(name, args, check) {
38
+ var result;
39
+ try { result = adapter[name].apply(adapter, args); } catch (cause) { return Promise.reject(cause); }
40
+ if (!result || typeof result.then !== "function") return Promise.reject(invalid(name + " must return a Promise."));
41
+ return result.then(check);
42
+ }
43
+ function flag(name) { var value = adapter[name](); if (typeof value !== "boolean") throw invalid(name + " must return a boolean."); return value; }
44
+ var bound = {
45
+ contractVersion: 1,
46
+ initialize: function () { return call("initialize", [], function () {}); },
47
+ hasStore: function () { return flag("hasStore"); }, isReady: function () { return flag("isReady"); },
48
+ get: function (id) { return call("get", [id], function (value) { if (value === null) return null; snapshot(value); if (value._id !== id) throw invalid("get returned a different identity."); return value; }); },
49
+ list: function () { return call("list", [], snapshots); }, getCached: function () { return snapshots(adapter.getCached()); },
50
+ insert: function (value) { return call("insert", [value], function (result) { if (result !== undefined) throw invalid("insert must resolve without a native result."); }); },
51
+ replaceIfRevision: function (id, revision, value) { return call("replaceIfRevision", [id, revision, value], function (result) { if (typeof result !== "boolean") throw invalid("replaceIfRevision must resolve to a boolean."); return result; }); },
52
+ serialize: function (scope, work) { return call("serialize", [scope, function () { return work(); }], function (result) { return result; }); }
53
+ };
54
+ if (typeof adapter.diagnostics === "function") bound.diagnostics = function () {
55
+ return call("diagnostics", [], function (result) { try { return JSON.parse(JSON.stringify(result)); } catch (cause) { throw invalid("diagnostics must resolve to JSON data."); } });
56
+ };
57
+ return bound;
58
+ }
59
+ function createDefaultKnowledgeDbStorage(options) {
60
+ // Lazy engine loading: injected adapters can run domain code without NeDB installed.
61
+ return require("./knowledge-db-storage-nedb").createKnowledgeDbNedbStorage(options);
62
+ }
63
+ function createKnowledgeDbStorage(options) {
64
+ var settings = options || {}; var adapter;
65
+ if (settings.storageAdapter !== undefined) adapter = settings.storageAdapter;
66
+ else if (settings.storageFactory !== undefined) {
67
+ if (typeof settings.storageFactory !== "function") throw invalid("storageFactory must be a synchronous function.");
68
+ adapter = settings.storageFactory({ projectDir: settings.projectDir });
69
+ } else adapter = module.exports.createDefaultKnowledgeDbStorage({ projectDir: settings.projectDir });
70
+ return bindAdapter(validateAdapter(adapter));
71
+ }
72
+ module.exports = { createKnowledgeDbStorage: createKnowledgeDbStorage, createDefaultKnowledgeDbStorage: createDefaultKnowledgeDbStorage, validateAdapter: validateAdapter, invalid: invalid };
Binary file
@@ -18,7 +18,8 @@ function createKnowledgeDocumentIndex(options) {
18
18
  if (file.size > options.maxDocumentBytes) { errors.push({ name: file.name, code: "TOO_LARGE", error: "Document exceeds the safe read limit." }); continue; }
19
19
  if (known && token && known.token === token) {
20
20
  if (bytes + known.bytes > MAX_INDEX_BYTES) { errors.push({ name: file.name, code: "INDEX_LIMIT", error: "Workspace Knowledge exceeds the safe index limit." }); continue; }
21
- next[key] = known; documents.push(known.document); bytes += known.bytes; continue;
21
+ var fresh = Object.assign({}, known, { document: Object.assign({}, known.document, file) });
22
+ next[key] = fresh; documents.push(fresh.document); bytes += known.bytes; continue;
22
23
  }
23
24
  try { content = options.read(file); } catch (error) { errors.push({ name: file.name, code: error.code || "READ_FAILED", error: error.message }); continue; }
24
25
  var size = Buffer.byteLength(content, "utf8");
@@ -136,7 +136,13 @@ function createKnowledgeFileStore(cwd, options) {
136
136
  var listed = list(); var identity = listed.filter(function (entry) { return entry.name === item.name; })[0]; if (!identity) return; ensureMetadata(true);
137
137
  var folder = path.join(historyRoot, identity.id); safeDirectory(folder, true);
138
138
  var target = path.join(folder, Date.now() + "-" + item.revision + ".md");
139
- fs.writeFileSync(target, item.content, { flag: "wx", mode: 0o600 });
139
+ try { fs.writeFileSync(target, item.content, { flag: "wx", mode: 0o600 }); }
140
+ catch (error) {
141
+ // A move and its link rewrite can snapshot the same revision in one millisecond.
142
+ if (error.code !== "EEXIST") throw error;
143
+ var stat = fs.lstatSync(target);
144
+ if (!stat.isFile() || stat.isSymbolicLink() || fs.readFileSync(target, "utf8") !== item.content) throw error;
145
+ }
140
146
  }
141
147
  function save(name, content, expectedRevision) {
142
148
  var clean = cleanName(name); if (!clean || itemType(clean) !== "text") throw new Error("Only valid Markdown documents can be edited.");
@@ -0,0 +1,46 @@
1
+ var validName = require('./knowledge-file-store').validName;
2
+ // Narrow operations over the same document store used by the Knowledge workbench.
3
+ function createKnowledgeProductOperations(ctx) {
4
+ function find(args, deleted) {
5
+ var item = args.documentId ? ctx.files.list().concat(deleted ? ctx.files.deleted() : []).find(function (entry) { return entry.id === args.documentId; }) : null;
6
+ if (args.documentId && !item) throw Object.assign(new Error('Knowledge document not found.'), { code: 'ENOENT' });
7
+ var name = args.name || item && item.name;
8
+ if (!name || item && args.name && args.name !== item.name) throw new Error('Choose one exact Knowledge document.');
9
+ if (item && item.deleted) return item;
10
+ var current = ctx.files.read(name);
11
+ if (current.itemType !== 'text') throw new Error('Legacy JSONL sources are read-only.');
12
+ return current;
13
+ }
14
+ function read(args) { var item = find(args); return { documentId: item.id, name: item.name, revision: item.revision, content: item.content }; }
15
+ function saved(item, who) { return Object.assign({ documentId: item.id, name: item.name, revision: item.revision, persisted: true }, ctx.mirror(who, [item.name])); }
16
+ function snapshot(op) {
17
+ if (op.action === 'retry_document_sync' && op.names.some(function (name) { return !validName(name); })) throw new Error('Invalid Knowledge source name.');
18
+ if (op.action === 'create_document') return ctx.files.list().filter(function (item) { return item.name === op.name; });
19
+ if (op.action === 'retry_document_sync') return ctx.files.list().filter(function (item) { return op.names.indexOf(item.name) >= 0; });
20
+ var item = find(op, op.action === 'restore_document');
21
+ var result = { documentId: item.id, name: item.name, revision: item.revision, deleted: !!item.deleted };
22
+ if (op.action === 'restore_document') result.version = ctx.files.readHistory(item.id, op.version);
23
+ if (op.action === 'rename_document') result.documents = ctx.files.list();
24
+ return result;
25
+ }
26
+ function mutate(op, who) {
27
+ if (op.action === 'create_document') return saved(ctx.files.save(op.name, op.content, null), who);
28
+ if (op.action === 'retry_document_sync') return Object.assign({ persisted: true }, ctx.mirror(who, op.names));
29
+ var item = find(op, op.action === 'restore_document');
30
+ if (op.action === 'update_document') return saved(ctx.files.save(item.name, op.content, op.expectedRevision), who);
31
+ if (op.action === 'rename_document') return ctx.rename({ from: item.name, name: op.newName, documentId: item.id, expectedRevision: op.expectedRevision }, who);
32
+ if (op.action === 'delete_document') { ctx.files.remove(item.name, op.expectedRevision); return Object.assign({ documentId: item.id, name: item.name, persisted: true, deleted: true }, ctx.mirror(who, [item.name])); }
33
+ if (op.action === 'restore_document') return saved(ctx.files.restore(item.id, op.version, item.name, item.deleted ? null : op.expectedRevision), who);
34
+ throw new Error('Unsupported Knowledge document operation.');
35
+ }
36
+ function query(op) {
37
+ if (op.action === 'list_documents') return { documents: op.deleted ? ctx.files.deleted() : ctx.files.list() };
38
+ if (op.action === 'read_document') return read(op);
39
+ var item = find(op, true);
40
+ if (op.action === 'document_history') return { documentId: item.id, name: item.name, versions: ctx.files.history(item.id) };
41
+ if (op.action === 'read_document_version') return Object.assign({ documentId: item.id, name: item.name }, ctx.files.readHistory(item.id, op.version));
42
+ throw new Error('Unsupported Knowledge document query.');
43
+ }
44
+ return { query: query, snapshot: snapshot, mutate: mutate };
45
+ }
46
+ module.exports = { createKnowledgeProductOperations: createKnowledgeProductOperations };
@@ -0,0 +1,12 @@
1
+ // Stable catalog identities are the only accepted library references.
2
+ var catalog = require('./public/mate-avatars/catalog.json');
3
+ var ids = new Set(catalog.map(function (entry) { return entry.id; }));
4
+ function valid(id) { return typeof id === 'string' && ids.has(id); }
5
+ function validate(profile, mate) {
6
+ if (profile !== undefined && (!profile || typeof profile !== 'object' || Array.isArray(profile))) return 'Choose a valid Mate profile.';
7
+ if (profile && Object.prototype.hasOwnProperty.call(profile, 'avatarCatalogId') && profile.avatarCatalogId !== '' && !valid(profile.avatarCatalogId) && !(profile.avatarCatalogId === 'lead-clay' && mate && mate.builtinKey === 'clay')) {
8
+ return 'Choose an avatar from the Clay catalog.';
9
+ }
10
+ return null;
11
+ }
12
+ module.exports = { valid: valid, validate: validate };
@@ -0,0 +1,41 @@
1
+ // Stable v1 migration, run only against the caller's normal Mate registry.
2
+ var catalog = require('./mate-avatar-catalog');
3
+ var managedArtwork = { clay: ['/clay-studio-symbol.png', '/mates/ally.png', '/mate-avatars/lead-clay.png'], ally: ['/mates/ally.png'] };
4
+ function mappedId(mate) {
5
+ var p = mate.profile || mate;
6
+ var key = JSON.stringify([mate.id || '', p.avatarStyle || 'imprint', p.avatarSeed || mate.id || p.displayName || mate.name || 'Mate']);
7
+ var hash = 2166136261;
8
+ for (var i = 0; i < key.length; i++) hash = Math.imul(hash ^ key.charCodeAt(i), 16777619) >>> 0;
9
+ var index = hash % 96;
10
+ return (index < 48 ? 'B' : 'C') + String(index % 48 + 1).padStart(2, '0');
11
+ }
12
+ function hasCustom(mate) {
13
+ var p = mate.profile || {};
14
+ var custom = p.avatarCustom || mate.avatarCustom;
15
+ if (!custom) return false;
16
+ var managed = managedArtwork[mate.builtinKey] || [];
17
+ return managed.indexOf(custom) === -1;
18
+ }
19
+ function normalizeMate(mate) {
20
+ if (!mate || hasCustom(mate)) return false;
21
+ var before = JSON.stringify(mate.profile || {});
22
+ var p = Object.assign({}, mate.profile || {});
23
+ p.avatarCatalogId = mate.builtinKey === 'clay' ? 'lead-clay' : catalog.valid(p.avatarCatalogId) ? p.avatarCatalogId : mappedId(mate);
24
+ p.avatarStyle = 'catalog';
25
+ delete p.avatarSeed;
26
+ if (p.avatarCustom) p.avatarCustom = '';
27
+ if (mate.builtinKey === 'clay') p.avatarLocked = true;
28
+ if (before === JSON.stringify(p) && !Object.prototype.hasOwnProperty.call(mate, 'avatarStyle') && !Object.prototype.hasOwnProperty.call(mate, 'avatarSeed') && !Object.prototype.hasOwnProperty.call(mate, 'avatarCustom')) return false;
29
+ mate.profile = p;
30
+ delete mate.avatarStyle;
31
+ delete mate.avatarSeed;
32
+ delete mate.avatarCustom;
33
+ return true;
34
+ }
35
+ function migrate(data) {
36
+ var changed = false;
37
+ data.mates.forEach(function (mate) { if (normalizeMate(mate)) changed = true; });
38
+ if (data.avatarCatalogMigrationVersion !== 1) { data.avatarCatalogMigrationVersion = 1; changed = true; }
39
+ return changed;
40
+ }
41
+ module.exports = { mappedId: mappedId, hasCustom: hasCustom, normalizeMate: normalizeMate, migrate: migrate };