@rubytech/create-sitedesk-code 0.1.522 → 0.1.523

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 (338) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  3. package/payload/platform/lib/graph-style/dist/index.js +28 -0
  4. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  5. package/payload/platform/lib/graph-style/src/__tests__/caption-coverage.test.ts +7 -0
  6. package/payload/platform/lib/graph-style/src/index.ts +24 -0
  7. package/payload/platform/lib/graph-write/dist/__tests__/merge-on.test.d.ts.map +1 -0
  8. package/payload/platform/lib/graph-write/dist/__tests__/merge-on.test.js.map +1 -0
  9. package/payload/platform/lib/graph-write/dist/index.d.ts +16 -0
  10. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
  11. package/payload/platform/lib/graph-write/dist/index.js +83 -6
  12. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  13. package/payload/platform/lib/graph-write/src/index.ts +117 -10
  14. package/payload/platform/lib/routine-templates/dist/index.d.ts +151 -0
  15. package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -0
  16. package/payload/platform/lib/routine-templates/dist/index.js +207 -0
  17. package/payload/platform/lib/routine-templates/dist/index.js.map +1 -0
  18. package/payload/platform/lib/routine-templates/dist/roster.d.ts +57 -0
  19. package/payload/platform/lib/routine-templates/dist/roster.d.ts.map +1 -0
  20. package/payload/platform/lib/routine-templates/dist/roster.js +182 -0
  21. package/payload/platform/lib/routine-templates/dist/roster.js.map +1 -0
  22. package/payload/platform/lib/routine-templates/dist/seed-cli.d.ts +2 -0
  23. package/payload/platform/lib/routine-templates/dist/seed-cli.d.ts.map +1 -0
  24. package/payload/platform/lib/routine-templates/dist/seed-cli.js +64 -0
  25. package/payload/platform/lib/routine-templates/dist/seed-cli.js.map +1 -0
  26. package/payload/platform/lib/routine-templates/package.json +6 -0
  27. package/payload/platform/lib/routine-templates/src/__tests__/roster.test.ts +170 -0
  28. package/payload/platform/lib/routine-templates/src/__tests__/seed.test.ts +298 -0
  29. package/payload/platform/lib/routine-templates/src/index.ts +299 -0
  30. package/payload/platform/lib/routine-templates/src/roster.ts +206 -0
  31. package/payload/platform/lib/routine-templates/src/seed-cli.ts +65 -0
  32. package/payload/platform/lib/routine-templates/tsconfig.json +9 -0
  33. package/payload/platform/lib/routine-templates/vitest.config.ts +9 -0
  34. package/payload/platform/neo4j/edge-annotations.json +2 -2
  35. package/payload/platform/neo4j/schema.cypher +25 -1
  36. package/payload/platform/package.json +3 -2
  37. package/payload/platform/plugins/admin/PLUGIN.md +2 -2
  38. package/payload/platform/plugins/admin/mcp/dist/index.js +39 -1
  39. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  40. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +277 -61
  41. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
  42. package/payload/platform/plugins/docs/references/admin-ui.md +265 -59
  43. package/payload/platform/plugins/docs/references/memory-guide.md +11 -1
  44. package/payload/platform/plugins/graph/.claude-plugin/plugin.json +1 -1
  45. package/payload/platform/plugins/graph/PLUGIN.md +1 -1
  46. package/payload/platform/plugins/memory/PLUGIN.md +1 -1
  47. package/payload/platform/plugins/memory/mcp/dist/index.js +12 -5
  48. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  49. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-estate-census.test.d.ts +2 -0
  50. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-estate-census.test.d.ts.map +1 -0
  51. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-estate-census.test.js +197 -0
  52. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-estate-census.test.js.map +1 -0
  53. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js +55 -9
  54. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js.map +1 -1
  55. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js +96 -0
  56. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js.map +1 -1
  57. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.d.ts +7 -0
  58. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.d.ts.map +1 -1
  59. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-estate-census.d.ts +29 -0
  60. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-estate-census.d.ts.map +1 -0
  61. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-estate-census.js +126 -0
  62. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-estate-census.js.map +1 -0
  63. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js +7 -4
  64. package/payload/platform/plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js.map +1 -1
  65. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.d.ts +1 -0
  66. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.d.ts.map +1 -1
  67. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.js +18 -1
  68. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.js.map +1 -1
  69. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +7 -0
  70. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
  71. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +4 -3
  72. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  73. package/payload/platform/plugins/memory/mcp/vitest.config.ts +2 -0
  74. package/payload/platform/plugins/memory/references/schema-estate-agent.md +2 -2
  75. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +4 -4
  76. package/payload/platform/plugins/quickbooks/PLUGIN.md +10 -10
  77. package/payload/platform/plugins/scheduling/PLUGIN.md +49 -1
  78. package/payload/platform/plugins/scheduling/mcp/dist/index.js +48 -0
  79. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  80. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/notes-cap.test.d.ts +2 -0
  81. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/notes-cap.test.d.ts.map +1 -0
  82. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/notes-cap.test.js +78 -0
  83. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/notes-cap.test.js.map +1 -0
  84. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.d.ts +2 -0
  85. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.d.ts.map +1 -0
  86. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js +457 -0
  87. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js.map +1 -0
  88. package/payload/platform/plugins/scheduling/mcp/dist/lib/notes-cap.d.ts +35 -0
  89. package/payload/platform/plugins/scheduling/mcp/dist/lib/notes-cap.d.ts.map +1 -0
  90. package/payload/platform/plugins/scheduling/mcp/dist/lib/notes-cap.js +39 -0
  91. package/payload/platform/plugins/scheduling/mcp/dist/lib/notes-cap.js.map +1 -0
  92. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts +175 -0
  93. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts.map +1 -0
  94. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js +533 -0
  95. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js.map +1 -0
  96. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +123 -9
  97. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
  98. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/routine-roster-audit.test.d.ts +2 -0
  99. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/routine-roster-audit.test.d.ts.map +1 -0
  100. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/routine-roster-audit.test.js +189 -0
  101. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/routine-roster-audit.test.js.map +1 -0
  102. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/suspension-census.test.d.ts +2 -0
  103. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/suspension-census.test.d.ts.map +1 -0
  104. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/suspension-census.test.js +95 -0
  105. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/suspension-census.test.js.map +1 -0
  106. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/sweep-excludes-suspended.test.d.ts +2 -0
  107. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/sweep-excludes-suspended.test.d.ts.map +1 -0
  108. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/sweep-excludes-suspended.test.js +114 -0
  109. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/sweep-excludes-suspended.test.js.map +1 -0
  110. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +109 -2
  111. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  112. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +340 -9
  113. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  114. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts +9 -1
  115. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts.map +1 -1
  116. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +210 -45
  117. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  118. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +43 -1
  119. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
  120. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-get-agent.test.js +55 -7
  121. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-get-agent.test.js.map +1 -1
  122. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-list.test.js +45 -1
  123. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-list.test.js.map +1 -1
  124. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-runs.test.d.ts +2 -0
  125. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-runs.test.d.ts.map +1 -0
  126. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-runs.test.js +96 -0
  127. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-runs.test.js.map +1 -0
  128. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -1
  129. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +2 -1
  130. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -1
  131. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts +5 -0
  132. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts.map +1 -1
  133. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js +13 -0
  134. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js.map +1 -1
  135. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.d.ts +4 -0
  136. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.d.ts.map +1 -1
  137. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.js +24 -3
  138. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.js.map +1 -1
  139. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-runs.d.ts +33 -0
  140. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-runs.d.ts.map +1 -0
  141. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-runs.js +51 -0
  142. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-runs.js.map +1 -0
  143. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
  144. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +12 -2
  145. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
  146. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +30 -2
  147. package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +1 -1
  148. package/payload/platform/scripts/check-specialist-tool-surface.mjs +92 -16
  149. package/payload/platform/scripts/seed-neo4j.sh +41 -0
  150. package/payload/platform/scripts/verify-skill-tool-surface.sh +91 -2
  151. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  152. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  153. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  154. package/payload/platform/templates/specialists/agents/librarian.md +1 -1
  155. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  156. package/payload/server/{chunk-K7CJGZPU.js → chunk-VUXKXOJU.js} +342 -152
  157. package/payload/server/{chunk-UX2FRNO7.js → chunk-WT2PFGY4.js} +37 -265
  158. package/payload/server/{chunk-PXNY2TAP.js → chunk-XCR5D2G3.js} +239 -10
  159. package/payload/server/{manager-RKL7JZ4Y.js → manager-4TJK3YOY.js} +2 -2
  160. package/payload/server/maxy-edge.js +2 -2
  161. package/payload/server/public/activity.html +5 -5
  162. package/payload/server/public/agents.html +4 -4
  163. package/payload/server/public/assets/{AdminLoginScreens-zc2_qqh-.js → AdminLoginScreens-uknqh2Pm.js} +1 -1
  164. package/payload/server/public/assets/AdminLoginScreens-uknqh2Pm.js.br +0 -0
  165. package/payload/server/public/assets/AdminLoginScreens-uknqh2Pm.js.gz +0 -0
  166. package/payload/server/public/assets/AdminShell-GqtMImyQ.js +2 -0
  167. package/payload/server/public/assets/AdminShell-GqtMImyQ.js.br +0 -0
  168. package/payload/server/public/assets/AdminShell-GqtMImyQ.js.gz +0 -0
  169. package/payload/server/public/assets/{activity-DVgO8YuM.js → activity-B4KfMJqO.js} +1 -1
  170. package/payload/server/public/assets/activity-B4KfMJqO.js.br +0 -0
  171. package/payload/server/public/assets/activity-B4KfMJqO.js.gz +0 -0
  172. package/payload/server/public/assets/admin-DxCZeVw0.js +1 -0
  173. package/payload/server/public/assets/admin-DxCZeVw0.js.br +0 -0
  174. package/payload/server/public/assets/admin-DxCZeVw0.js.gz +0 -0
  175. package/payload/server/public/assets/agents-BtwBuO4G.js +1 -0
  176. package/payload/server/public/assets/agents-BtwBuO4G.js.br +0 -0
  177. package/payload/server/public/assets/agents-BtwBuO4G.js.gz +0 -0
  178. package/payload/server/public/assets/{browser-Mw7DY3ft.js → browser-B3hSzI3O.js} +1 -1
  179. package/payload/server/public/assets/browser-B3hSzI3O.js.br +0 -0
  180. package/payload/server/public/assets/browser-B3hSzI3O.js.gz +0 -0
  181. package/payload/server/public/assets/{calendar-B9gvL_1_.js → calendar-BggxXxhS.js} +1 -1
  182. package/payload/server/public/assets/calendar-BggxXxhS.js.br +0 -0
  183. package/payload/server/public/assets/calendar-BggxXxhS.js.gz +0 -0
  184. package/payload/server/public/assets/chat-flivHt0t.js +1 -0
  185. package/payload/server/public/assets/chat-flivHt0t.js.br +0 -0
  186. package/payload/server/public/assets/chat-flivHt0t.js.gz +0 -0
  187. package/payload/server/public/assets/chevron-left-nVRThX7f.js +1 -0
  188. package/payload/server/public/assets/chevron-right-CLqfrkRA.js +1 -0
  189. package/payload/server/public/assets/chevron-right-CLqfrkRA.js.br +0 -0
  190. package/payload/server/public/assets/clock-Dj3SRZKo.js +1 -0
  191. package/payload/server/public/assets/clock-Dj3SRZKo.js.br +0 -0
  192. package/payload/server/public/assets/clock-Dj3SRZKo.js.gz +0 -0
  193. package/payload/server/public/assets/data-Ckjkne54.js +1 -0
  194. package/payload/server/public/assets/data-Ckjkne54.js.br +3 -0
  195. package/payload/server/public/assets/data-Ckjkne54.js.gz +0 -0
  196. package/payload/server/public/assets/{file-text-dYBnXNEX.js → file-text-BKs9eyiw.js} +1 -1
  197. package/payload/server/public/assets/file-text-BKs9eyiw.js.br +0 -0
  198. package/payload/server/public/assets/file-text-BKs9eyiw.js.gz +0 -0
  199. package/payload/server/public/assets/{graph-CDyzd1Et.js → graph-DTi71NaZ.js} +3 -3
  200. package/payload/server/public/assets/graph-DTi71NaZ.js.br +0 -0
  201. package/payload/server/public/assets/graph-DTi71NaZ.js.gz +0 -0
  202. package/payload/server/public/assets/graph-labels-BT3S6e9H.js +1 -0
  203. package/payload/server/public/assets/graph-labels-BT3S6e9H.js.br +0 -0
  204. package/payload/server/public/assets/graph-labels-BT3S6e9H.js.gz +0 -0
  205. package/payload/server/public/assets/{maximize-2-M-iSaznd.js → maximize-2-zC94tsxY.js} +1 -1
  206. package/payload/server/public/assets/maximize-2-zC94tsxY.js.br +0 -0
  207. package/payload/server/public/assets/maximize-2-zC94tsxY.js.gz +0 -0
  208. package/payload/server/public/assets/operator-BtWNEMh-.js +1 -0
  209. package/payload/server/public/assets/operator-BtWNEMh-.js.br +0 -0
  210. package/payload/server/public/assets/operator-BtWNEMh-.js.gz +0 -0
  211. package/payload/server/public/assets/page-BFm91p0e.js +1 -0
  212. package/payload/server/public/assets/page-BFm91p0e.js.br +0 -0
  213. package/payload/server/public/assets/page-BFm91p0e.js.gz +0 -0
  214. package/payload/server/public/assets/{page-CZ-73FAk.js → page-Ccl0FazM.js} +3 -3
  215. package/payload/server/public/assets/page-Ccl0FazM.js.br +0 -0
  216. package/payload/server/public/assets/page-Ccl0FazM.js.gz +0 -0
  217. package/payload/server/public/assets/{public-CN-ltC8x.js → public-BpC6cn9S.js} +1 -1
  218. package/payload/server/public/assets/public-BpC6cn9S.js.br +0 -0
  219. package/payload/server/public/assets/public-BpC6cn9S.js.gz +0 -0
  220. package/payload/server/public/assets/{rotate-ccw-Buopsc22.js → rotate-ccw-BNcqbHkZ.js} +1 -1
  221. package/payload/server/public/assets/rotate-ccw-BNcqbHkZ.js.br +0 -0
  222. package/payload/server/public/assets/rotate-ccw-BNcqbHkZ.js.gz +0 -0
  223. package/payload/server/public/assets/routines-D5iia-XG.js +1 -0
  224. package/payload/server/public/assets/routines-D5iia-XG.js.br +0 -0
  225. package/payload/server/public/assets/routines-D5iia-XG.js.gz +0 -0
  226. package/payload/server/public/assets/{skills-DiiuVzDK.js → skills-COLAw_jt.js} +1 -1
  227. package/payload/server/public/assets/skills-COLAw_jt.js.br +0 -0
  228. package/payload/server/public/assets/skills-COLAw_jt.js.gz +0 -0
  229. package/payload/server/public/assets/tasks-CZDQI4nB.js +1 -0
  230. package/payload/server/public/assets/tasks-CZDQI4nB.js.br +0 -0
  231. package/payload/server/public/assets/tasks-CZDQI4nB.js.gz +0 -0
  232. package/payload/server/public/assets/{time-entry-format-BBokCF-D.js → time-entry-format-laTFzawg.js} +1 -1
  233. package/payload/server/public/assets/time-entry-format-laTFzawg.js.br +0 -0
  234. package/payload/server/public/assets/time-entry-format-laTFzawg.js.gz +0 -0
  235. package/payload/server/public/assets/{triangle-alert-C_AcpTW5.js → triangle-alert-DrwqhEog.js} +1 -1
  236. package/payload/server/public/assets/triangle-alert-DrwqhEog.js.br +0 -0
  237. package/payload/server/public/assets/triangle-alert-DrwqhEog.js.gz +0 -0
  238. package/payload/server/public/assets/{useCopyFeedback-TdimmPVR.js → useCopyFeedback-Cxme5GK6.js} +1 -1
  239. package/payload/server/public/assets/useCopyFeedback-Cxme5GK6.js.br +0 -0
  240. package/payload/server/public/assets/useCopyFeedback-Cxme5GK6.js.gz +0 -0
  241. package/payload/server/public/assets/useSubAccountSwitcher-B-K8y5a4.css +1 -0
  242. package/payload/server/public/assets/useSubAccountSwitcher-B-K8y5a4.css.br +0 -0
  243. package/payload/server/public/assets/useSubAccountSwitcher-B-K8y5a4.css.gz +0 -0
  244. package/payload/server/public/assets/useSubAccountSwitcher-C_1E11Dv.js +14 -0
  245. package/payload/server/public/assets/useSubAccountSwitcher-C_1E11Dv.js.br +0 -0
  246. package/payload/server/public/assets/useSubAccountSwitcher-C_1E11Dv.js.gz +0 -0
  247. package/payload/server/public/assets/{useVoiceRecorder-BT2738ZS.js → useVoiceRecorder-DUBpVa2T.js} +1 -1
  248. package/payload/server/public/assets/useVoiceRecorder-DUBpVa2T.js.br +0 -0
  249. package/payload/server/public/assets/useVoiceRecorder-DUBpVa2T.js.gz +0 -0
  250. package/payload/server/public/assets/{wrench-B51s5kGA.js → wrench-DWuxPnzF.js} +1 -1
  251. package/payload/server/public/assets/wrench-DWuxPnzF.js.br +0 -0
  252. package/payload/server/public/assets/wrench-DWuxPnzF.js.gz +0 -0
  253. package/payload/server/public/browser.html +4 -4
  254. package/payload/server/public/calendar.html +7 -7
  255. package/payload/server/public/chat.html +13 -13
  256. package/payload/server/public/data.html +11 -11
  257. package/payload/server/public/graph.html +9 -9
  258. package/payload/server/public/index.html +14 -14
  259. package/payload/server/public/operator.html +14 -14
  260. package/payload/server/public/public.html +13 -13
  261. package/payload/server/public/routines.html +6 -6
  262. package/payload/server/public/skills.html +5 -5
  263. package/payload/server/public/tasks.html +6 -6
  264. package/payload/server/server.js +5910 -5369
  265. package/payload/server/public/assets/AdminLoginScreens-zc2_qqh-.js.br +0 -0
  266. package/payload/server/public/assets/AdminLoginScreens-zc2_qqh-.js.gz +0 -0
  267. package/payload/server/public/assets/AdminShell-IGUdTx5q.js +0 -2
  268. package/payload/server/public/assets/AdminShell-IGUdTx5q.js.br +0 -0
  269. package/payload/server/public/assets/AdminShell-IGUdTx5q.js.gz +0 -0
  270. package/payload/server/public/assets/activity-DVgO8YuM.js.br +0 -0
  271. package/payload/server/public/assets/activity-DVgO8YuM.js.gz +0 -0
  272. package/payload/server/public/assets/admin-xtpM7fgl.js +0 -1
  273. package/payload/server/public/assets/admin-xtpM7fgl.js.br +0 -0
  274. package/payload/server/public/assets/admin-xtpM7fgl.js.gz +0 -0
  275. package/payload/server/public/assets/agents-P0nTIxo-.js +0 -1
  276. package/payload/server/public/assets/agents-P0nTIxo-.js.br +0 -0
  277. package/payload/server/public/assets/agents-P0nTIxo-.js.gz +0 -0
  278. package/payload/server/public/assets/browser-Mw7DY3ft.js.br +0 -0
  279. package/payload/server/public/assets/browser-Mw7DY3ft.js.gz +0 -0
  280. package/payload/server/public/assets/calendar-B9gvL_1_.js.br +0 -0
  281. package/payload/server/public/assets/calendar-B9gvL_1_.js.gz +0 -0
  282. package/payload/server/public/assets/chat-DBGqh4wg.js +0 -1
  283. package/payload/server/public/assets/chat-DBGqh4wg.js.br +0 -2
  284. package/payload/server/public/assets/chat-DBGqh4wg.js.gz +0 -0
  285. package/payload/server/public/assets/chevron-left-Bl4vpOM0.js +0 -1
  286. package/payload/server/public/assets/chevron-left-Bl4vpOM0.js.br +0 -0
  287. package/payload/server/public/assets/chevron-right-BExigCnp.js +0 -1
  288. package/payload/server/public/assets/chevron-right-BExigCnp.js.br +0 -0
  289. package/payload/server/public/assets/clock-D8TJvgJC.js +0 -1
  290. package/payload/server/public/assets/clock-D8TJvgJC.js.br +0 -0
  291. package/payload/server/public/assets/data-HfFSxaC2.js +0 -1
  292. package/payload/server/public/assets/data-HfFSxaC2.js.br +0 -0
  293. package/payload/server/public/assets/data-HfFSxaC2.js.gz +0 -0
  294. package/payload/server/public/assets/file-text-dYBnXNEX.js.br +0 -0
  295. package/payload/server/public/assets/file-text-dYBnXNEX.js.gz +0 -0
  296. package/payload/server/public/assets/graph-CDyzd1Et.js.br +0 -0
  297. package/payload/server/public/assets/graph-CDyzd1Et.js.gz +0 -0
  298. package/payload/server/public/assets/graph-labels-D1LkKiJr.js +0 -1
  299. package/payload/server/public/assets/graph-labels-D1LkKiJr.js.br +0 -0
  300. package/payload/server/public/assets/graph-labels-D1LkKiJr.js.gz +0 -0
  301. package/payload/server/public/assets/maximize-2-M-iSaznd.js.br +0 -0
  302. package/payload/server/public/assets/maximize-2-M-iSaznd.js.gz +0 -0
  303. package/payload/server/public/assets/operator-9jfCv1Fg.js +0 -1
  304. package/payload/server/public/assets/operator-9jfCv1Fg.js.br +0 -0
  305. package/payload/server/public/assets/operator-9jfCv1Fg.js.gz +0 -0
  306. package/payload/server/public/assets/page-CZ-73FAk.js.br +0 -0
  307. package/payload/server/public/assets/page-CZ-73FAk.js.gz +0 -0
  308. package/payload/server/public/assets/page-CjwSt7kx.js +0 -1
  309. package/payload/server/public/assets/page-CjwSt7kx.js.br +0 -0
  310. package/payload/server/public/assets/page-CjwSt7kx.js.gz +0 -0
  311. package/payload/server/public/assets/public-CN-ltC8x.js.br +0 -0
  312. package/payload/server/public/assets/public-CN-ltC8x.js.gz +0 -0
  313. package/payload/server/public/assets/rotate-ccw-Buopsc22.js.br +0 -0
  314. package/payload/server/public/assets/rotate-ccw-Buopsc22.js.gz +0 -0
  315. package/payload/server/public/assets/routines-C-yr8ddT.js +0 -1
  316. package/payload/server/public/assets/routines-C-yr8ddT.js.br +0 -0
  317. package/payload/server/public/assets/routines-C-yr8ddT.js.gz +0 -0
  318. package/payload/server/public/assets/skills-DiiuVzDK.js.br +0 -0
  319. package/payload/server/public/assets/skills-DiiuVzDK.js.gz +0 -0
  320. package/payload/server/public/assets/tasks-CnHIfn2_.js +0 -1
  321. package/payload/server/public/assets/tasks-CnHIfn2_.js.br +0 -0
  322. package/payload/server/public/assets/tasks-CnHIfn2_.js.gz +0 -0
  323. package/payload/server/public/assets/time-entry-format-BBokCF-D.js.br +0 -0
  324. package/payload/server/public/assets/time-entry-format-BBokCF-D.js.gz +0 -0
  325. package/payload/server/public/assets/triangle-alert-C_AcpTW5.js.br +0 -0
  326. package/payload/server/public/assets/triangle-alert-C_AcpTW5.js.gz +0 -0
  327. package/payload/server/public/assets/useCopyFeedback-TdimmPVR.js.br +0 -0
  328. package/payload/server/public/assets/useCopyFeedback-TdimmPVR.js.gz +0 -0
  329. package/payload/server/public/assets/useSubAccountSwitcher-BwHqV55p.js +0 -14
  330. package/payload/server/public/assets/useSubAccountSwitcher-BwHqV55p.js.br +0 -0
  331. package/payload/server/public/assets/useSubAccountSwitcher-BwHqV55p.js.gz +0 -0
  332. package/payload/server/public/assets/useSubAccountSwitcher-CsrPYqtm.css +0 -1
  333. package/payload/server/public/assets/useSubAccountSwitcher-CsrPYqtm.css.br +0 -0
  334. package/payload/server/public/assets/useSubAccountSwitcher-CsrPYqtm.css.gz +0 -0
  335. package/payload/server/public/assets/useVoiceRecorder-BT2738ZS.js.br +0 -0
  336. package/payload/server/public/assets/useVoiceRecorder-BT2738ZS.js.gz +0 -0
  337. package/payload/server/public/assets/wrench-B51s5kGA.js.br +0 -0
  338. package/payload/server/public/assets/wrench-B51s5kGA.js.gz +0 -0
@@ -218,14 +218,44 @@ export interface WriteNodeWithEdgesParams {
218
218
  * a failed embed must never abort an otherwise-valid write.
219
219
  */
220
220
  embed?: (text: string) => Promise<number[]>;
221
+ /**
222
+ * Optional natural-key merge. When present and non-empty the node write
223
+ * becomes a MERGE on `accountId` plus the named properties, and every
224
+ * relationship in the same call becomes a MERGE — a re-import of the same
225
+ * row then matches the existing node and its existing edges instead of
226
+ * creating a second copy. Absent (the default), both paths CREATE exactly
227
+ * as before. `accountId` is always part of the key and is never named here.
228
+ * Task 2132.
229
+ */
230
+ mergeOn?: string[];
221
231
  }
222
232
 
223
233
  export interface WriteNodeResult {
224
234
  nodeId: string;
225
235
  labels: string[];
236
+ /**
237
+ * Edges created on a plain write. Under `mergeOn` this counts edges
238
+ * *resolved* — created plus already-present — because a re-import
239
+ * legitimately creates none. Both readings satisfy the same invariant the
240
+ * writer checks: one edge per requested relationship, or the write rolls back.
241
+ */
226
242
  edgesCreated: number;
227
243
  }
228
244
 
245
+ /**
246
+ * Properties a `mergeOn` write sets on creation only, so a re-import
247
+ * preserves the original provenance and creation time rather than restamping
248
+ * them with the second run's values. Mirrors the ON CREATE blocks in
249
+ * memory-archive-write.ts and the installer's LocalBusiness bootstrap.
250
+ */
251
+ const MERGE_CREATE_ONLY_PROPS = new Set([
252
+ "createdAt",
253
+ "createdByAgent",
254
+ "createdBySession",
255
+ "createdByTool",
256
+ "createdBySource",
257
+ ]);
258
+
229
259
  /** Stamp flattened provenance into node properties. */
230
260
  export function stampCreatedBy(
231
261
  props: Record<string, unknown>,
@@ -316,6 +346,34 @@ export async function writeNodeWithEdges(
316
346
  );
317
347
  }
318
348
 
349
+ // Natural-key merge (Task 2132). Validated here so a malformed key throws
350
+ // before any query runs — a key naming a property the caller did not write
351
+ // would silently MERGE on `null` and collapse unrelated rows onto one node.
352
+ const mergeKeys = params.mergeOn;
353
+ if (mergeKeys !== undefined) {
354
+ if (mergeKeys.length === 0) {
355
+ throw new Error(
356
+ "mergeOn must name at least one property (accountId is always included and must not be named)."
357
+ );
358
+ }
359
+ for (const k of mergeKeys) {
360
+ if (!(k in props)) {
361
+ throw new Error(
362
+ `mergeOn property "${k}" is not present in props — the natural key must be written with the node.`
363
+ );
364
+ }
365
+ // `k in props` is true for an explicit undefined, and Neo4j would then
366
+ // MERGE on null and collapse every keyless row onto one node — the exact
367
+ // failure this validation exists to prevent.
368
+ const v = (props as Record<string, unknown>)[k];
369
+ if (v === undefined || v === null || v === "") {
370
+ throw new Error(
371
+ `mergeOn property "${k}" is empty — a natural key must carry a value, or the merge collapses unrelated rows onto one node.`
372
+ );
373
+ }
374
+ }
375
+ }
376
+
319
377
  // Embed safety net. When the node carries a vector-indexed label, lacks an
320
378
  // embedding, and an embedder is injected, compute a bounded props embedding
321
379
  // so no indexed node enters the graph invisible to vector search. A failed
@@ -410,10 +468,39 @@ export async function writeNodeWithEdges(
410
468
 
411
469
  let nodeRes;
412
470
  try {
413
- nodeRes = await tx.run(
414
- `CREATE (n:${labelStr} $props) RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels`,
415
- { props: nodeProps }
416
- );
471
+ if (mergeKeys) {
472
+ // Natural-key MERGE. Creation-only properties sit under ON CREATE so a
473
+ // re-import preserves the original provenance and createdAt, matching
474
+ // PERSON_AND_CONNECTED_EDGE_CYPHER in memory-archive-write.ts and the
475
+ // installer's LocalBusiness bootstrap. Everything else refreshes.
476
+ const keyProps = ["accountId", ...mergeKeys];
477
+ const keyPattern = keyProps.map((k) => `${k}: $key_${k}`).join(", ");
478
+ const keyParams: Record<string, unknown> = {};
479
+ for (const k of keyProps) {
480
+ keyParams[`key_${k}`] = (nodeProps as Record<string, unknown>)[k];
481
+ }
482
+ const createProps: Record<string, unknown> = {};
483
+ const updateProps: Record<string, unknown> = {};
484
+ for (const [k, v] of Object.entries(nodeProps as Record<string, unknown>)) {
485
+ if (keyProps.includes(k)) continue;
486
+ (MERGE_CREATE_ONLY_PROPS.has(k) ? createProps : updateProps)[k] = v;
487
+ }
488
+ nodeRes = await tx.run(
489
+ `MERGE (n:${labelStr} {${keyPattern}}) ON CREATE SET n += $createProps SET n += $updateProps RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels`,
490
+ { ...keyParams, createProps, updateProps }
491
+ );
492
+ const outcome = nodeRes.summary?.counters.updates().nodesCreated
493
+ ? "created"
494
+ : "matched";
495
+ process.stderr.write(
496
+ `[graph-write] op=merge label=${labelCsv} key=${keyProps.join(",")} outcome=${outcome}\n`
497
+ );
498
+ } else {
499
+ nodeRes = await tx.run(
500
+ `CREATE (n:${labelStr} $props) RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels`,
501
+ { props: nodeProps }
502
+ );
503
+ }
417
504
  } catch (err) {
418
505
  // surface UserProfile uniqueness violations as a structured
419
506
  // reject line. Neo4j's ConstraintValidationFailed message names the
@@ -448,12 +535,32 @@ export async function writeNodeWithEdges(
448
535
  let edgesCreated = 0;
449
536
  for (const rel of relationships) {
450
537
  const type = rel.type.replace(/`/g, "");
451
- const q =
452
- rel.direction === "outgoing"
453
- ? `MATCH (a), (b) WHERE elementId(a) = $from AND elementId(b) = $to CREATE (a)-[:\`${type}\`]->(b)`
454
- : `MATCH (a), (b) WHERE elementId(a) = $from AND elementId(b) = $to CREATE (b)-[:\`${type}\`]->(a)`;
455
- const r = await tx.run(q, { from: nodeId, to: rel.targetNodeId });
456
- const created = r.summary.counters.updates().relationshipsCreated;
538
+ let created: number;
539
+ if (mergeKeys) {
540
+ // Under a natural-key merge the edges MERGE too: a node that matched
541
+ // must not accumulate a second copy of each relationship. A repeat
542
+ // legitimately creates zero relationships, so the unresolved-target
543
+ // guard below switches from the create counter to the returned row
544
+ // count — 0 rows means the MATCH failed to resolve an endpoint, the
545
+ // condition the guard was written for.
546
+ const dir =
547
+ rel.direction === "outgoing"
548
+ ? `(a)-[r:\`${type}\`]->(b)`
549
+ : `(b)-[r:\`${type}\`]->(a)`;
550
+ const r = await tx.run(
551
+ `MATCH (a), (b) WHERE elementId(a) = $from AND elementId(b) = $to MERGE ${dir} RETURN count(r) AS n`,
552
+ { from: nodeId, to: rel.targetNodeId }
553
+ );
554
+ created =
555
+ r.records.length === 0 ? 0 : Number(r.records[0].get("n") ?? 0);
556
+ } else {
557
+ const q =
558
+ rel.direction === "outgoing"
559
+ ? `MATCH (a), (b) WHERE elementId(a) = $from AND elementId(b) = $to CREATE (a)-[:\`${type}\`]->(b)`
560
+ : `MATCH (a), (b) WHERE elementId(a) = $from AND elementId(b) = $to CREATE (b)-[:\`${type}\`]->(a)`;
561
+ const r = await tx.run(q, { from: nodeId, to: rel.targetNodeId });
562
+ created = r.summary.counters.updates().relationshipsCreated;
563
+ }
457
564
  if (created === 0) {
458
565
  process.stderr.write(
459
566
  `[graph-write] reject reason=unresolved-target-on-create labels=${labelCsv} agent=${agentLabel} relType=${rel.type} targetId=${rel.targetNodeId}\n`
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Task 2130 — the routine-roster seed.
3
+ *
4
+ * One module, two callers: `platform/scripts/seed-neo4j.sh` reaches it through
5
+ * `dist/seed-cli.js` on every install and upgrade (which is what covers the
6
+ * existing fleet), and the admin plugin's `account_create` imports it directly
7
+ * for a new client sub-account. Sharing the MERGE rather than writing it twice
8
+ * is the point: two copies drift, and the drift would only ever be noticed as
9
+ * "the sub-accounts have different routines from the house".
10
+ *
11
+ * The seed is inert by construction. Every row lands `eventStatus:'suspended'`
12
+ * with `nextRun` NULL, and all four selecting queries in `check-due-events.ts`
13
+ * admit only `'scheduled'`: the one-time dispatch (`:686-690`, `WHERE
14
+ * e.eventStatus = 'scheduled' AND e.recurrence IS NULL`), the recurring
15
+ * dispatch (`:739-744`), the lifecycle activate/heal probe (`:491`) and the
16
+ * lifecycle deactivation sweep (`:550-551`). NULL `nextRun` is the second,
17
+ * independent guard: the recurring query also requires `e.nextRun IS NOT NULL`
18
+ * (`:742`). Neither guard depends on the other holding.
19
+ *
20
+ * `nextRun` is left NULL rather than computed, and that is not tidiness. The
21
+ * recurring loop advances from the STORED value, not from now
22
+ * (`check-due-events.ts:778`, `currentDate: new Date(currentNextRun)`), so a
23
+ * row seeded with a computed `nextRun` and enabled a month later advances one
24
+ * occurrence per tick and dispatches on every one of them. A quarter-hourly
25
+ * routine would replay roughly 2,880 turns. The only safe value is no value,
26
+ * until an operator supplies a recurrence through `schedule-update`, which
27
+ * recomputes from now.
28
+ *
29
+ * Each line number above is paired with the construct it points at. Bare
30
+ * numbers drift on the next edit to that file and then send a reader somewhere
31
+ * unrelated, which is worse than no citation.
32
+ */
33
+ import { type RoutineTemplate } from "./roster.js";
34
+ export { ROUTINE_ROSTER, ROUTINE_ROSTER_KEYS, ROUTINE_TEMPLATE_VERSION } from "./roster.js";
35
+ export type { RoutineTemplate } from "./roster.js";
36
+ /** The minimal Neo4j session surface the seed needs. Both the admin plugin's
37
+ * `getSession()` and a driver session from `seed-cli` satisfy it; the tests
38
+ * pass an in-memory fake. Deliberately not `neo4j-driver`'s `Session` type, so
39
+ * this module stays importable by a consumer that has no driver types. */
40
+ export interface SeedSessionLike {
41
+ run(query: string, params?: Record<string, unknown>): Promise<{
42
+ records: Array<{
43
+ get(key: string): unknown;
44
+ }>;
45
+ }>;
46
+ }
47
+ /** What the seed did to one routine.
48
+ * - `create` — the row did not exist. On an already-seeded account this is the
49
+ * clobber signature: something deleted the row, or the MERGE key changed.
50
+ * - `refresh-version` — the stored template version was behind and no operator
51
+ * had edited the row, so the prompt and name were refreshed.
52
+ * - `skip-operator-edited` — a refresh was due and was withheld because the row
53
+ * carries `operatorEdited`. The operator's prompt wins, permanently.
54
+ * - `unchanged` — the row is already at this version. The steady state. */
55
+ export type RoutineMergeAction = "create" | "refresh-version" | "skip-operator-edited" | "unchanged";
56
+ export interface RoutineMergeRow {
57
+ key: string;
58
+ eventId: string;
59
+ action: RoutineMergeAction;
60
+ }
61
+ /** The post-condition, measured back out of the graph rather than counted from
62
+ * the statements issued. A seed that ran and wrote nothing must not be able to
63
+ * report success, which is exactly what counting its own writes would do.
64
+ *
65
+ * `expected === actual` is the health signal. `suspended` and `nextRunNull`
66
+ * equal `actual` on a fresh seed and legitimately fall below it once an
67
+ * operator enables a routine — they are measurements, not assertions. */
68
+ export interface RoutineVerifyCounts {
69
+ expected: number;
70
+ actual: number;
71
+ suspended: number;
72
+ nextRunNull: number;
73
+ }
74
+ export interface RoutineSeedReport {
75
+ accountId: string;
76
+ version: number;
77
+ timezone: string | null;
78
+ timezoneSource: "owner-profile" | "absent";
79
+ merges: RoutineMergeRow[];
80
+ created: number;
81
+ refreshed: number;
82
+ skippedOperatorEdited: number;
83
+ unchanged: number;
84
+ verify: RoutineVerifyCounts;
85
+ ranMs: number;
86
+ }
87
+ /** First eight characters of the accountId — the correlation key every
88
+ * `[routine-seed]` and `[schedule-audit]` line carries. */
89
+ export declare function acctTag(accountId: string): string;
90
+ /**
91
+ * The owner's IANA timezone, read from the owner `:UserProfile` and accepted
92
+ * only when it is owner-set.
93
+ *
94
+ * A profile whose `timezoneSource` is anything else was backfilled from the
95
+ * box's own zone, and seeding that onto a routine would give the operator a
96
+ * routine that fires at the server's hour while looking entirely healthy. NULL
97
+ * is the honest value in that case, and the heartbeat's `op=null-timezone`
98
+ * count is what surfaces it — on occasion one, rather than at the first
99
+ * mis-timed fire.
100
+ */
101
+ export declare function resolveOwnerTimezone(session: SeedSessionLike, accountId: string): Promise<{
102
+ timezone: string | null;
103
+ source: "owner-profile" | "absent";
104
+ }>;
105
+ /** The MERGE. One statement over the whole roster.
106
+ *
107
+ * The pre-state is captured by an OPTIONAL MATCH before the MERGE, because the
108
+ * MERGE itself cannot report which branch it took. Without it the seed could
109
+ * only log what it intended; `action=create` on an already-seeded account
110
+ * would be indistinguishable from `action=unchanged`, and the clobber it
111
+ * signals would be invisible.
112
+ *
113
+ * ON MATCH writes nothing an operator controls: not `eventStatus`, not
114
+ * `agentChannel`, not `agentDestination`, not `recurrence`, not `timezone`. A
115
+ * re-seed on upgrade must not re-suspend an enabled routine, unbind a bound
116
+ * destination, or reset a retimed cron. Only the prompt, the name and the
117
+ * version move, and only when the row is behind and unedited. */
118
+ export declare const MERGE_CYPHER = "\nUNWIND $rows AS row\nOPTIONAL MATCH (pre:Event {accountId: $accountId, routineTemplate: row.key})\nWITH row,\n pre IS NOT NULL AS existed,\n coalesce(pre.routineTemplateVersion, 0) AS priorVersion,\n pre.operatorEdited IS NOT NULL AS edited\nWITH row, existed, priorVersion, edited,\n (existed AND NOT edited AND priorVersion < $version) AS refreshing\nMERGE (e:Event {accountId: $accountId, routineTemplate: row.key})\n ON CREATE SET e.eventId = randomUUID(),\n e.name = row.name,\n e.agentPrompt = row.prompt,\n e.recurrence = row.recurrence,\n e.routineTemplateVersion = $version,\n e.eventStatus = 'suspended',\n e.nextRun = null,\n e.agentChannel = null,\n e.agentDestination = null,\n e.actionPlugin = null,\n e.actionTool = null,\n e.actionArgs = null,\n e.sourcePlugin = null,\n e.timezone = $timezone,\n e.createdBySource = 'installer',\n e.createdByAgent = 'system',\n e.createdByTool = 'routine-roster-seed',\n e.createdAt = $now,\n e.updatedAt = $now\n ON MATCH SET e.agentPrompt = CASE WHEN refreshing THEN row.prompt ELSE e.agentPrompt END,\n e.name = CASE WHEN refreshing THEN row.name ELSE e.name END,\n e.routineTemplateVersion = CASE WHEN refreshing THEN $version ELSE e.routineTemplateVersion END,\n e.updatedAt = CASE WHEN refreshing THEN $now ELSE e.updatedAt END\nRETURN row.key AS key,\n e.eventId AS eventId,\n CASE WHEN NOT existed THEN 'create'\n WHEN priorVersion >= $version THEN 'unchanged'\n WHEN edited THEN 'skip-operator-edited'\n ELSE 'refresh-version' END AS action";
119
+ /** The post-condition read. Counts every roster row the account actually holds,
120
+ * independently of what the MERGE above believes it wrote. */
121
+ export declare const VERIFY_CYPHER = "\nMATCH (e:Event {accountId: $accountId})\nWHERE e.routineTemplate IS NOT NULL\nRETURN count(e) AS actual,\n sum(CASE WHEN e.eventStatus = 'suspended' THEN 1 ELSE 0 END) AS suspended,\n sum(CASE WHEN e.nextRun IS NULL THEN 1 ELSE 0 END) AS nextRunNull";
122
+ export interface SeedRoutineRosterArgs {
123
+ session: SeedSessionLike;
124
+ accountId: string;
125
+ /** Defaults to `ROUTINE_TEMPLATE_VERSION`. Injected by the tests. */
126
+ version?: number;
127
+ /** ISO timestamp stamped on created rows. Injected by the tests. */
128
+ now?: string;
129
+ /** Defaults to `ROUTINE_ROSTER`. Injected by the tests. */
130
+ roster?: readonly RoutineTemplate[];
131
+ /** Where the `[routine-seed]` lines go. Defaults to stderr. */
132
+ log?: (line: string) => void;
133
+ /** Elapsed milliseconds for `op=end`. Injected by the tests so the line is
134
+ * assertable; `Date.now()` either side of the work otherwise. */
135
+ clock?: () => number;
136
+ }
137
+ /**
138
+ * Seed (or re-seed) the roster for one account and report what happened.
139
+ *
140
+ * Emits the full `[routine-seed]` lifecycle on every run, including a run that
141
+ * changes nothing: `op=begin`, `op=tz-resolved`, one `op=merge` per routine,
142
+ * `op=verify`, `op=end`. A no-op run that logged nothing would be
143
+ * indistinguishable from a seed that never ran, and "never ran" is the failure
144
+ * this logging exists to make visible.
145
+ *
146
+ * Throws on a Neo4j failure. Both callers catch: the installer path exits
147
+ * non-zero, and `account_create` reports a created-but-routine-less account
148
+ * with the recovery action rather than a generic create failure.
149
+ */
150
+ export declare function seedRoutineRoster(args: SeedRoutineRosterArgs): Promise<RoutineSeedReport>;
151
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAA4C,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7F,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;2EAG2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAClH;AAED;;;;;;;4EAO4E;AAC5E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,iBAAiB,GAAG,sBAAsB,GAAG,WAAW,CAAC;AAErG,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED;;;;;;0EAM0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,eAAe,GAAG,QAAQ,CAAC;IAC3C,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAYD;4DAC4D;AAC5D,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,eAAe,GAAG,QAAQ,CAAA;CAAE,CAAC,CAa1E;AAED;;;;;;;;;;;;kEAYkE;AAClE,eAAO,MAAM,YAAY,01DAsCwB,CAAC;AAElD;+DAC+D;AAC/D,eAAO,MAAM,aAAa,4QAK+C,CAAC;AAE1E,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,MAAM,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACpC,+DAA+D;IAC/D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B;sEACkE;IAClE,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAyE/F"}
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VERIFY_CYPHER = exports.MERGE_CYPHER = exports.ROUTINE_TEMPLATE_VERSION = exports.ROUTINE_ROSTER_KEYS = exports.ROUTINE_ROSTER = void 0;
4
+ exports.acctTag = acctTag;
5
+ exports.resolveOwnerTimezone = resolveOwnerTimezone;
6
+ exports.seedRoutineRoster = seedRoutineRoster;
7
+ /**
8
+ * Task 2130 — the routine-roster seed.
9
+ *
10
+ * One module, two callers: `platform/scripts/seed-neo4j.sh` reaches it through
11
+ * `dist/seed-cli.js` on every install and upgrade (which is what covers the
12
+ * existing fleet), and the admin plugin's `account_create` imports it directly
13
+ * for a new client sub-account. Sharing the MERGE rather than writing it twice
14
+ * is the point: two copies drift, and the drift would only ever be noticed as
15
+ * "the sub-accounts have different routines from the house".
16
+ *
17
+ * The seed is inert by construction. Every row lands `eventStatus:'suspended'`
18
+ * with `nextRun` NULL, and all four selecting queries in `check-due-events.ts`
19
+ * admit only `'scheduled'`: the one-time dispatch (`:686-690`, `WHERE
20
+ * e.eventStatus = 'scheduled' AND e.recurrence IS NULL`), the recurring
21
+ * dispatch (`:739-744`), the lifecycle activate/heal probe (`:491`) and the
22
+ * lifecycle deactivation sweep (`:550-551`). NULL `nextRun` is the second,
23
+ * independent guard: the recurring query also requires `e.nextRun IS NOT NULL`
24
+ * (`:742`). Neither guard depends on the other holding.
25
+ *
26
+ * `nextRun` is left NULL rather than computed, and that is not tidiness. The
27
+ * recurring loop advances from the STORED value, not from now
28
+ * (`check-due-events.ts:778`, `currentDate: new Date(currentNextRun)`), so a
29
+ * row seeded with a computed `nextRun` and enabled a month later advances one
30
+ * occurrence per tick and dispatches on every one of them. A quarter-hourly
31
+ * routine would replay roughly 2,880 turns. The only safe value is no value,
32
+ * until an operator supplies a recurrence through `schedule-update`, which
33
+ * recomputes from now.
34
+ *
35
+ * Each line number above is paired with the construct it points at. Bare
36
+ * numbers drift on the next edit to that file and then send a reader somewhere
37
+ * unrelated, which is worse than no citation.
38
+ */
39
+ const roster_js_1 = require("./roster.js");
40
+ var roster_js_2 = require("./roster.js");
41
+ Object.defineProperty(exports, "ROUTINE_ROSTER", { enumerable: true, get: function () { return roster_js_2.ROUTINE_ROSTER; } });
42
+ Object.defineProperty(exports, "ROUTINE_ROSTER_KEYS", { enumerable: true, get: function () { return roster_js_2.ROUTINE_ROSTER_KEYS; } });
43
+ Object.defineProperty(exports, "ROUTINE_TEMPLATE_VERSION", { enumerable: true, get: function () { return roster_js_2.ROUTINE_TEMPLATE_VERSION; } });
44
+ /** Neo4j returns integers as its own `Integer` type over bolt and as plain
45
+ * numbers through a test fake. Normalise both without importing the driver. */
46
+ function toInt(raw) {
47
+ if (typeof raw === "number")
48
+ return raw;
49
+ if (raw && typeof raw.toNumber === "function") {
50
+ return raw.toNumber();
51
+ }
52
+ return Number(raw ?? 0);
53
+ }
54
+ /** First eight characters of the accountId — the correlation key every
55
+ * `[routine-seed]` and `[schedule-audit]` line carries. */
56
+ function acctTag(accountId) {
57
+ return accountId.slice(0, 8);
58
+ }
59
+ /**
60
+ * The owner's IANA timezone, read from the owner `:UserProfile` and accepted
61
+ * only when it is owner-set.
62
+ *
63
+ * A profile whose `timezoneSource` is anything else was backfilled from the
64
+ * box's own zone, and seeding that onto a routine would give the operator a
65
+ * routine that fires at the server's hour while looking entirely healthy. NULL
66
+ * is the honest value in that case, and the heartbeat's `op=null-timezone`
67
+ * count is what surfaces it — on occasion one, rather than at the first
68
+ * mis-timed fire.
69
+ */
70
+ async function resolveOwnerTimezone(session, accountId) {
71
+ const res = await session.run(`MATCH (up:UserProfile {accountId: $accountId})
72
+ WHERE up.timezoneSource = 'owner-set' AND up.timezone IS NOT NULL AND trim(up.timezone) <> ''
73
+ RETURN up.timezone AS timezone
74
+ LIMIT 1`, { accountId });
75
+ const raw = res.records[0]?.get("timezone");
76
+ if (typeof raw === "string" && raw.trim() !== "") {
77
+ return { timezone: raw.trim(), source: "owner-profile" };
78
+ }
79
+ return { timezone: null, source: "absent" };
80
+ }
81
+ /** The MERGE. One statement over the whole roster.
82
+ *
83
+ * The pre-state is captured by an OPTIONAL MATCH before the MERGE, because the
84
+ * MERGE itself cannot report which branch it took. Without it the seed could
85
+ * only log what it intended; `action=create` on an already-seeded account
86
+ * would be indistinguishable from `action=unchanged`, and the clobber it
87
+ * signals would be invisible.
88
+ *
89
+ * ON MATCH writes nothing an operator controls: not `eventStatus`, not
90
+ * `agentChannel`, not `agentDestination`, not `recurrence`, not `timezone`. A
91
+ * re-seed on upgrade must not re-suspend an enabled routine, unbind a bound
92
+ * destination, or reset a retimed cron. Only the prompt, the name and the
93
+ * version move, and only when the row is behind and unedited. */
94
+ exports.MERGE_CYPHER = `
95
+ UNWIND $rows AS row
96
+ OPTIONAL MATCH (pre:Event {accountId: $accountId, routineTemplate: row.key})
97
+ WITH row,
98
+ pre IS NOT NULL AS existed,
99
+ coalesce(pre.routineTemplateVersion, 0) AS priorVersion,
100
+ pre.operatorEdited IS NOT NULL AS edited
101
+ WITH row, existed, priorVersion, edited,
102
+ (existed AND NOT edited AND priorVersion < $version) AS refreshing
103
+ MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
104
+ ON CREATE SET e.eventId = randomUUID(),
105
+ e.name = row.name,
106
+ e.agentPrompt = row.prompt,
107
+ e.recurrence = row.recurrence,
108
+ e.routineTemplateVersion = $version,
109
+ e.eventStatus = 'suspended',
110
+ e.nextRun = null,
111
+ e.agentChannel = null,
112
+ e.agentDestination = null,
113
+ e.actionPlugin = null,
114
+ e.actionTool = null,
115
+ e.actionArgs = null,
116
+ e.sourcePlugin = null,
117
+ e.timezone = $timezone,
118
+ e.createdBySource = 'installer',
119
+ e.createdByAgent = 'system',
120
+ e.createdByTool = 'routine-roster-seed',
121
+ e.createdAt = $now,
122
+ e.updatedAt = $now
123
+ ON MATCH SET e.agentPrompt = CASE WHEN refreshing THEN row.prompt ELSE e.agentPrompt END,
124
+ e.name = CASE WHEN refreshing THEN row.name ELSE e.name END,
125
+ e.routineTemplateVersion = CASE WHEN refreshing THEN $version ELSE e.routineTemplateVersion END,
126
+ e.updatedAt = CASE WHEN refreshing THEN $now ELSE e.updatedAt END
127
+ RETURN row.key AS key,
128
+ e.eventId AS eventId,
129
+ CASE WHEN NOT existed THEN 'create'
130
+ WHEN priorVersion >= $version THEN 'unchanged'
131
+ WHEN edited THEN 'skip-operator-edited'
132
+ ELSE 'refresh-version' END AS action`;
133
+ /** The post-condition read. Counts every roster row the account actually holds,
134
+ * independently of what the MERGE above believes it wrote. */
135
+ exports.VERIFY_CYPHER = `
136
+ MATCH (e:Event {accountId: $accountId})
137
+ WHERE e.routineTemplate IS NOT NULL
138
+ RETURN count(e) AS actual,
139
+ sum(CASE WHEN e.eventStatus = 'suspended' THEN 1 ELSE 0 END) AS suspended,
140
+ sum(CASE WHEN e.nextRun IS NULL THEN 1 ELSE 0 END) AS nextRunNull`;
141
+ /**
142
+ * Seed (or re-seed) the roster for one account and report what happened.
143
+ *
144
+ * Emits the full `[routine-seed]` lifecycle on every run, including a run that
145
+ * changes nothing: `op=begin`, `op=tz-resolved`, one `op=merge` per routine,
146
+ * `op=verify`, `op=end`. A no-op run that logged nothing would be
147
+ * indistinguishable from a seed that never ran, and "never ran" is the failure
148
+ * this logging exists to make visible.
149
+ *
150
+ * Throws on a Neo4j failure. Both callers catch: the installer path exits
151
+ * non-zero, and `account_create` reports a created-but-routine-less account
152
+ * with the recovery action rather than a generic create failure.
153
+ */
154
+ async function seedRoutineRoster(args) {
155
+ const { session, accountId, version = roster_js_1.ROUTINE_TEMPLATE_VERSION, now = new Date().toISOString(), roster = roster_js_1.ROUTINE_ROSTER, log = (line) => process.stderr.write(`${line}\n`), clock = () => Date.now(), } = args;
156
+ const acct = acctTag(accountId);
157
+ const startedAt = clock();
158
+ log(`[routine-seed] op=begin acct=${acct} roster=${roster.length} version=${version}`);
159
+ const { timezone, source } = await resolveOwnerTimezone(session, accountId);
160
+ log(`[routine-seed] op=tz-resolved acct=${acct} tz=${timezone ?? "null"} source=${source}`);
161
+ const mergeRes = await session.run(exports.MERGE_CYPHER, {
162
+ accountId,
163
+ version,
164
+ timezone,
165
+ now,
166
+ rows: roster.map((r) => ({ key: r.key, name: r.name, prompt: r.prompt, recurrence: r.recurrence })),
167
+ });
168
+ const merges = mergeRes.records.map((rec) => ({
169
+ key: String(rec.get("key")),
170
+ eventId: String(rec.get("eventId")),
171
+ action: String(rec.get("action")),
172
+ }));
173
+ for (const m of merges) {
174
+ log(`[routine-seed] op=merge acct=${acct} key=${m.key} action=${m.action} eventId=${m.eventId}`);
175
+ }
176
+ const verifyRes = await session.run(exports.VERIFY_CYPHER, { accountId });
177
+ const verifyRec = verifyRes.records[0];
178
+ const verify = {
179
+ expected: roster.length,
180
+ actual: toInt(verifyRec?.get("actual")),
181
+ suspended: toInt(verifyRec?.get("suspended")),
182
+ nextRunNull: toInt(verifyRec?.get("nextRunNull")),
183
+ };
184
+ log(`[routine-seed] op=verify acct=${acct} expected=${verify.expected} actual=${verify.actual} ` +
185
+ `suspended=${verify.suspended} nextRunNull=${verify.nextRunNull}`);
186
+ const created = merges.filter((m) => m.action === "create").length;
187
+ const refreshed = merges.filter((m) => m.action === "refresh-version").length;
188
+ const skippedOperatorEdited = merges.filter((m) => m.action === "skip-operator-edited").length;
189
+ const unchanged = merges.filter((m) => m.action === "unchanged").length;
190
+ const ranMs = clock() - startedAt;
191
+ log(`[routine-seed] op=end acct=${acct} ranMs=${ranMs} created=${created} ` +
192
+ `skipped=${skippedOperatorEdited} refreshed=${refreshed} unchanged=${unchanged}`);
193
+ return {
194
+ accountId,
195
+ version,
196
+ timezone,
197
+ timezoneSource: source,
198
+ merges,
199
+ created,
200
+ refreshed,
201
+ skippedOperatorEdited,
202
+ unchanged,
203
+ verify,
204
+ ranMs,
205
+ };
206
+ }
207
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Task 2130 — the shipped routine roster.
3
+ *
4
+ * A fresh install used to ship zero routines, so the only working examples
5
+ * lived in one customer's graph and every operator wrote the prompts from
6
+ * scratch. These eleven are the catalogue that ships with the platform instead.
7
+ *
8
+ * Two properties make a routine shippable, and both are load-bearing:
9
+ *
10
+ * 1. It resolves its own surfaces at run time. Every prompt opens on
11
+ * `capabilities-here`, which reports the account's live install set, and
12
+ * ends the turn without replying when the surface it needs is absent. That
13
+ * is what makes the same eleven rows correct on an estate agency, a web studio
14
+ * and a field-service install rather than a template someone must edit.
15
+ *
16
+ * 2. It names nobody. No prompt carries a person's name, an email address, a
17
+ * phone number, a hostname or a database name. `scripts/check-routine-
18
+ * templates-generic.sh` is the standing control for that; a review pass is
19
+ * not, because the failure is silent and the routine still works.
20
+ *
21
+ * The `recurrence` on each row is a PROPOSAL, not a schedule. Seeded rows carry
22
+ * `eventStatus:'suspended'` and `nextRun:NULL`, so nothing here fires until an
23
+ * operator enables it and supplies the cron and zone they actually want (see
24
+ * `.docs/routine-roster.md` for why the enable path takes all four arguments).
25
+ *
26
+ * Every tool name cited in a prompt exists in
27
+ * `platform/services/claude-session-manager/src/canonical-tool-names.generated.ts`.
28
+ * The roster test asserts that, so a renamed tool breaks the build rather than
29
+ * shipping a prompt that reaches for a tool no install serves.
30
+ */
31
+ /** Bumped whenever any prompt in the roster changes. The seed refreshes a
32
+ * routine's prompt only when the stored `routineTemplateVersion` is BELOW this
33
+ * and no operator has edited the row, so an unbumped edit ships to new installs
34
+ * and never reaches existing ones — bump it in the same commit as the edit. */
35
+ export declare const ROUTINE_TEMPLATE_VERSION = 1;
36
+ export interface RoutineTemplate {
37
+ /** Stable identity. Half of the MERGE key `(accountId, routineTemplate)`, so
38
+ * it is never renamed: a renamed key seeds a duplicate row and orphans the
39
+ * original, which the operator then has to delete by hand. */
40
+ readonly key: string;
41
+ /** The title shown on `/routines`. */
42
+ readonly name: string;
43
+ /** The proposed cron. Written ON CREATE only, never refreshed, so an operator
44
+ * who retimes a routine keeps their expression across upgrades. */
45
+ readonly recurrence: string;
46
+ /** The injected turn. Refreshed on a version bump when the row is unedited. */
47
+ readonly prompt: string;
48
+ }
49
+ /** The eleven. Order is the display order on `/routines` before the operator
50
+ * retimes anything: the daily rhythm first, then the reconciles, then the
51
+ * weekly, then the standing check. */
52
+ export declare const ROUTINE_ROSTER: readonly RoutineTemplate[];
53
+ /** Every roster key, in roster order. The scheduling heartbeat's `op=roster`
54
+ * drift check reconciles this expected set against what is actually in the
55
+ * graph, so it is exported rather than re-derived there. */
56
+ export declare const ROUTINE_ROSTER_KEYS: readonly string[];
57
+ //# sourceMappingURL=roster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH;;;gFAGgF;AAChF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,MAAM,WAAW,eAAe;IAC9B;;mEAE+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;wEACoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAwID;;uCAEuC;AACvC,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAYpD,CAAC;AAEF;;6DAE6D;AAC7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAqC,CAAC"}