@rubytech/create-maxy-code 0.1.423 → 0.1.429

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 (333) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/embed-client/dist/index.d.ts +5 -1
  3. package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/embed-client/dist/index.js +114 -36
  5. package/payload/platform/lib/embed-client/dist/index.js.map +1 -1
  6. package/payload/platform/lib/embed-client/src/index.ts +141 -34
  7. package/payload/platform/neo4j/schema.cypher +13 -0
  8. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  9. package/payload/platform/plugins/admin/PLUGIN.md +5 -1
  10. package/payload/platform/plugins/admin/hooks/__tests__/datetime-inject.test.sh +119 -0
  11. package/payload/platform/plugins/admin/hooks/datetime-inject.sh +115 -0
  12. package/payload/platform/plugins/admin/mcp/dist/index.js +62 -4
  13. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  14. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +44 -0
  15. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
  16. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +96 -0
  17. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
  18. package/payload/platform/plugins/admin/skills/datetime/SKILL.md +9 -2
  19. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +17 -3
  20. package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
  21. package/payload/platform/plugins/docs/references/cross-account-authority.md +8 -0
  22. package/payload/platform/plugins/docs/references/internals.md +5 -1
  23. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  24. package/payload/platform/plugins/email/PLUGIN.md +2 -2
  25. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +73 -4
  26. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -1
  27. package/payload/platform/plugins/email/mcp/dist/__tests__/mailbox-resolve.test.js +42 -1
  28. package/payload/platform/plugins/email/mcp/dist/__tests__/mailbox-resolve.test.js.map +1 -1
  29. package/payload/platform/plugins/email/mcp/dist/index.js +1 -0
  30. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  31. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +4 -0
  32. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -1
  33. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +5 -0
  34. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -1
  35. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +25 -3
  36. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  37. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +67 -12
  38. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  39. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts +1 -0
  40. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  41. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +1 -0
  42. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  43. package/payload/platform/plugins/email/references/email-reference.md +8 -0
  44. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.d.ts +2 -0
  45. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.d.ts.map +1 -0
  46. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.js +92 -0
  47. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-throughput.test.js.map +1 -0
  48. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.d.ts +2 -0
  49. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.d.ts.map +1 -0
  50. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.js +56 -0
  51. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embed-timeout.test.js.map +1 -0
  52. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js +56 -0
  53. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js.map +1 -1
  54. package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
  55. package/payload/platform/plugins/scheduling/mcp/dist/index.js +5 -2
  56. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  57. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js +50 -1
  58. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js.map +1 -1
  59. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts +2 -0
  60. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts.map +1 -0
  61. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js +22 -0
  62. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js.map +1 -0
  63. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts +35 -0
  64. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts.map +1 -1
  65. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js +36 -0
  66. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js.map +1 -1
  67. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts +11 -0
  68. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts.map +1 -0
  69. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js +19 -0
  70. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js.map +1 -0
  71. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +85 -3
  72. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
  73. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js +32 -1
  74. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js.map +1 -1
  75. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +14 -1
  76. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  77. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +94 -4
  78. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  79. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +23 -7
  80. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  81. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.d.ts +2 -0
  82. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.d.ts.map +1 -0
  83. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js +30 -0
  84. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js.map +1 -0
  85. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts +29 -0
  86. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -1
  87. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +47 -2
  88. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -1
  89. package/payload/platform/plugins/whatsapp/PLUGIN.md +2 -0
  90. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.d.ts +2 -0
  91. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.d.ts.map +1 -0
  92. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.js +20 -0
  93. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.js.map +1 -0
  94. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts +1 -1
  95. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts.map +1 -1
  96. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js +5 -2
  97. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js.map +1 -1
  98. package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.d.ts +9 -0
  99. package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.d.ts.map +1 -0
  100. package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.js +18 -0
  101. package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.js.map +1 -0
  102. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +13 -11
  103. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  104. package/payload/platform/plugins/work/PLUGIN.md +1 -1
  105. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.d.ts +2 -0
  106. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.d.ts.map +1 -0
  107. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js +72 -0
  108. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js.map +1 -0
  109. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.d.ts +2 -0
  110. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.d.ts.map +1 -0
  111. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.js +67 -0
  112. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.js.map +1 -0
  113. package/payload/platform/plugins/work/mcp/dist/index.js +3 -0
  114. package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
  115. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts +9 -3
  116. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts.map +1 -1
  117. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js +19 -15
  118. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js.map +1 -1
  119. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts +6 -0
  120. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts.map +1 -1
  121. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js +34 -1
  122. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -1
  123. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.d.ts +1 -1
  124. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.d.ts.map +1 -1
  125. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.js +7 -18
  126. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.js.map +1 -1
  127. package/payload/platform/scripts/lib/provision-account-dir.sh +2 -1
  128. package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts +39 -0
  129. package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts.map +1 -0
  130. package/payload/platform/services/claude-session-manager/dist/account-admin-census.js +122 -0
  131. package/payload/platform/services/claude-session-manager/dist/account-admin-census.js.map +1 -0
  132. package/payload/platform/services/claude-session-manager/dist/account-timezone.d.ts +40 -0
  133. package/payload/platform/services/claude-session-manager/dist/account-timezone.d.ts.map +1 -0
  134. package/payload/platform/services/claude-session-manager/dist/account-timezone.js +126 -0
  135. package/payload/platform/services/claude-session-manager/dist/account-timezone.js.map +1 -0
  136. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  137. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  138. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  139. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  140. package/payload/platform/services/claude-session-manager/dist/http-server.js +18 -1
  141. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  142. package/payload/platform/services/claude-session-manager/dist/index.js +13 -0
  143. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  144. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +11 -0
  145. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  146. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +28 -0
  147. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  148. package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
  149. package/payload/platform/services/telegram-channel/dist/instructions.js +8 -1
  150. package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
  151. package/payload/platform/services/telegram-channel/dist/notification.d.ts +22 -0
  152. package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
  153. package/payload/platform/services/telegram-channel/dist/notification.js +22 -1
  154. package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
  155. package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
  156. package/payload/platform/services/webchat-channel/dist/instructions.js +8 -1
  157. package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
  158. package/payload/platform/services/webchat-channel/dist/notification.d.ts +22 -0
  159. package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
  160. package/payload/platform/services/webchat-channel/dist/notification.js +22 -1
  161. package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
  162. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +28 -2
  163. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  164. package/payload/platform/services/whatsapp-channel/dist/notification.js +32 -3
  165. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  166. package/payload/platform/templates/account.json +2 -1
  167. package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
  168. package/payload/server/{chunk-3Z5WE53X.js → chunk-UUG6ZSO5.js} +65 -9
  169. package/payload/server/maxy-edge.js +1 -1
  170. package/payload/server/public/assets/AdminLoginScreens-C4AZT7cQ.js +1 -0
  171. package/payload/server/public/assets/AdminShell-BfLQQ27Z.js +2 -0
  172. package/payload/server/public/assets/{Checkbox-CgCqOslz.js → Checkbox-BC0c_gbn.js} +1 -1
  173. package/payload/server/public/assets/admin-SaF1F4e-.js +1 -0
  174. package/payload/server/public/assets/{arc-DyzjCWmw.js → arc-qKfXIt8v.js} +1 -1
  175. package/payload/server/public/assets/architecture-YZFGNWBL-FPHT7s-C.js +1 -0
  176. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-qWfElD16.js → architectureDiagram-Q4EWVU46-DkVrGn7G.js} +1 -1
  177. package/payload/server/public/assets/audio-attachment-mime-BBW07eyG.js +2 -0
  178. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DO2fFHC3.js → blockDiagram-DXYQGD6D-DqavswGH.js} +1 -1
  179. package/payload/server/public/assets/browser-CvZxNdKw.js +1 -0
  180. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Ca-q5gDe.js → c4Diagram-AHTNJAMY-B7fyKiXe.js} +1 -1
  181. package/payload/server/public/assets/calendar-DXxLMF2J.js +1 -0
  182. package/payload/server/public/assets/channel-j70eMvcL.js +1 -0
  183. package/payload/server/public/assets/chat-B9Qjt7C9.js +1 -0
  184. package/payload/server/public/assets/chevron-left-CLPxfjDV.js +1 -0
  185. package/payload/server/public/assets/{chunk-2KRD3SAO-CX2PxuDw.js → chunk-2KRD3SAO-DsgMtGkv.js} +1 -1
  186. package/payload/server/public/assets/{chunk-336JU56O-D8l6U4Ne.js → chunk-336JU56O-CkdISfNt.js} +2 -2
  187. package/payload/server/public/assets/chunk-426QAEUC-D-NcAlTW.js +1 -0
  188. package/payload/server/public/assets/{chunk-4BX2VUAB-CG32Lkbh.js → chunk-4BX2VUAB-CYpiF2bl.js} +1 -1
  189. package/payload/server/public/assets/{chunk-4TB4RGXK-BnAQbO-v.js → chunk-4TB4RGXK-CWyc_F7v.js} +1 -1
  190. package/payload/server/public/assets/{chunk-55IACEB6-ejqRH2M5.js → chunk-55IACEB6-BbzKMw2Z.js} +1 -1
  191. package/payload/server/public/assets/{chunk-5FUZZQ4R-ClkicQ-T.js → chunk-5FUZZQ4R-u19Nai9e.js} +1 -1
  192. package/payload/server/public/assets/{chunk-5PVQY5BW-Be-mE_rx.js → chunk-5PVQY5BW-Ba8by6Uy.js} +1 -1
  193. package/payload/server/public/assets/{chunk-67CJDMHE-DPsemed2.js → chunk-67CJDMHE-BwUuxtyb.js} +1 -1
  194. package/payload/server/public/assets/{chunk-7N4EOEYR-BQRQJETl.js → chunk-7N4EOEYR-BRH9iM9L.js} +1 -1
  195. package/payload/server/public/assets/{chunk-AA7GKIK3-B1wcAVCK.js → chunk-AA7GKIK3-BGoztgLL.js} +1 -1
  196. package/payload/server/public/assets/{chunk-BSJP7CBP-DIua053h.js → chunk-BSJP7CBP-C5GDAZTl.js} +1 -1
  197. package/payload/server/public/assets/{chunk-CIAEETIT-C9GHSCS9.js → chunk-CIAEETIT-ChY32VPS.js} +1 -1
  198. package/payload/server/public/assets/{chunk-EDXVE4YY-C1T3l1xj.js → chunk-EDXVE4YY-CPSD3p6p.js} +1 -1
  199. package/payload/server/public/assets/{chunk-ENJZ2VHE-8kPcXEQC.js → chunk-ENJZ2VHE-D1oL-iUr.js} +1 -1
  200. package/payload/server/public/assets/{chunk-FMBD7UC4-Bhoeq9sD.js → chunk-FMBD7UC4-CPvYEr54.js} +1 -1
  201. package/payload/server/public/assets/{chunk-FOC6F5B3-BIBpJi8I.js → chunk-FOC6F5B3-9Yyj7Vbz.js} +1 -1
  202. package/payload/server/public/assets/{chunk-ICPOFSXX-DELXp6fj.js → chunk-ICPOFSXX-BaYgh8FR.js} +2 -2
  203. package/payload/server/public/assets/{chunk-K5T4RW27-DdckXldP.js → chunk-K5T4RW27-5ucpeRvm.js} +1 -1
  204. package/payload/server/public/assets/{chunk-KGLVRYIC-BJhXejKT.js → chunk-KGLVRYIC-DW-FHk7T.js} +1 -1
  205. package/payload/server/public/assets/{chunk-LIHQZDEY-BSd8nyM2.js → chunk-LIHQZDEY-CGGVfAyG.js} +1 -1
  206. package/payload/server/public/assets/{chunk-ORNJ4GCN-CBi55uxq.js → chunk-ORNJ4GCN-Bv8EUa5d.js} +1 -1
  207. package/payload/server/public/assets/{chunk-OYMX7WX6-Dfbzl8xh.js → chunk-OYMX7WX6-C1mXJnyw.js} +1 -1
  208. package/payload/server/public/assets/chunk-QZHKN3VN-CAwbQBtf.js +1 -0
  209. package/payload/server/public/assets/{chunk-U2HBQHQK-BN1w8_Cq.js → chunk-U2HBQHQK-PwSQz6EP.js} +1 -1
  210. package/payload/server/public/assets/{chunk-X2U36JSP-CrRay1NJ.js → chunk-X2U36JSP--NPHTBlU.js} +1 -1
  211. package/payload/server/public/assets/{chunk-XPW4576I-C_ZE776O.js → chunk-XPW4576I-Bbc7Da32.js} +1 -1
  212. package/payload/server/public/assets/{chunk-YZCP3GAM-CUSlqWBY.js → chunk-YZCP3GAM-D-9v8e--.js} +1 -1
  213. package/payload/server/public/assets/{chunk-ZZ45TVLE-BdPUfSiD.js → chunk-ZZ45TVLE-CMPg670Q.js} +1 -1
  214. package/payload/server/public/assets/classDiagram-6PBFFD2Q-Ct6Rn0vt.js +1 -0
  215. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-B_2XCIFv.js +1 -0
  216. package/payload/server/public/assets/clone-DjPWA_NH.js +1 -0
  217. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-D4E9htTz.js → cose-bilkent-S5V4N54A-NVSb1Bhy.js} +1 -1
  218. package/payload/server/public/assets/{dagre-KV5264BT-ByuvYV7N.js → dagre-KV5264BT-V2Ai1DFl.js} +1 -1
  219. package/payload/server/public/assets/{dagre-D1B5TQL1.js → dagre-QfLcO-1j.js} +1 -1
  220. package/payload/server/public/assets/data-BKE6Sa-g.js +1 -0
  221. package/payload/server/public/assets/{diagram-5BDNPKRD-B-0KduTa.js → diagram-5BDNPKRD-Caw21693.js} +1 -1
  222. package/payload/server/public/assets/{diagram-G4DWMVQ6-CSQmo3eB.js → diagram-G4DWMVQ6-CgwVkT2q.js} +1 -1
  223. package/payload/server/public/assets/{diagram-MMDJMWI5-DK0kWiB3.js → diagram-MMDJMWI5-DFUrLZhs.js} +1 -1
  224. package/payload/server/public/assets/{diagram-TYMM5635-CYbK2reZ.js → diagram-TYMM5635-CEEiEuZJ.js} +1 -1
  225. package/payload/server/public/assets/{dist-CADCHk0t.js → dist-Cvgxm7qv.js} +1 -1
  226. package/payload/server/public/assets/{erDiagram-SMLLAGMA-C-JQHvJF.js → erDiagram-SMLLAGMA-CG10NrT3.js} +1 -1
  227. package/payload/server/public/assets/file-download-B2B2DTar.js +1 -0
  228. package/payload/server/public/assets/{flatten-ROVzlo1u.js → flatten-DAO0sfCM.js} +1 -1
  229. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-OTOd2czg.js → flowDiagram-DWJPFMVM-BqkV9Okv.js} +1 -1
  230. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BWJ778ou.js → ganttDiagram-T4ZO3ILL-DRiCDQF6.js} +1 -1
  231. package/payload/server/public/assets/gitGraph-7Q5UKJZL-B8Hx7f-D.js +1 -0
  232. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CkNcyISe.js → gitGraphDiagram-UUTBAWPF-BZV2voyy.js} +1 -1
  233. package/payload/server/public/assets/graph-DRNzDBTV.js +51 -0
  234. package/payload/server/public/assets/{graph-labels-BfG6FO25.js → graph-labels-DxqDdO7G.js} +1 -1
  235. package/payload/server/public/assets/{graphlib-8z59Ng6C.js → graphlib-DGPThX8M.js} +1 -1
  236. package/payload/server/public/assets/info-OMHHGYJF-BicCJTqU.js +1 -0
  237. package/payload/server/public/assets/infoDiagram-42DDH7IO-tf-8rOez.js +2 -0
  238. package/payload/server/public/assets/{isEmpty-DXf_sApt.js → isEmpty-Cb_U81C6.js} +1 -1
  239. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-Cg7pRRGp.js → ishikawaDiagram-UXIWVN3A-BKsAxSvp.js} +1 -1
  240. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CZT_4r_Z.js → journeyDiagram-VCZTEJTY-CmliuOd-.js} +1 -1
  241. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Dp1Vd5YM.js → kanban-definition-6JOO6SKY-DAlElMb-.js} +1 -1
  242. package/payload/server/public/assets/{line-UPAcwY66.js → line-DKZqLKAC.js} +1 -1
  243. package/payload/server/public/assets/{linear-BeeahLKw.js → linear-CbSGdh1x.js} +1 -1
  244. package/payload/server/public/assets/{maximize-2-DrBaKD3z.js → maximize-2-DKx6OBKv.js} +1 -1
  245. package/payload/server/public/assets/{mermaid-parser.core-CLKle8df.js → mermaid-parser.core-DFvbao9C.js} +2 -2
  246. package/payload/server/public/assets/{mermaid.core-CwRj5rL5.js → mermaid.core-C0vEBxDm.js} +3 -3
  247. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CNQUY9UJ.js → mindmap-definition-QFDTVHPH-CShASUKd.js} +1 -1
  248. package/payload/server/public/assets/operator-CTJjI8te.js +1 -0
  249. package/payload/server/public/assets/{ordinal-B2r5L1v4.js → ordinal-H0tVmBDP.js} +1 -1
  250. package/payload/server/public/assets/packet-4T2RLAQJ-Ckn_5hq0.js +1 -0
  251. package/payload/server/public/assets/page-CbI1wtef.js +1 -0
  252. package/payload/server/public/assets/page-JzxyFGle.js +32 -0
  253. package/payload/server/public/assets/{pdf-render-m08Xm2Nm.js → pdf-render-jAQU0nXt.js} +1 -1
  254. package/payload/server/public/assets/pie-ZZUOXDRM-DzlGQW3J.js +1 -0
  255. package/payload/server/public/assets/{pieDiagram-DEJITSTG-Scnq58FX.js → pieDiagram-DEJITSTG-CBZHpDAJ.js} +1 -1
  256. package/payload/server/public/assets/play-DHttF4fl.js +1 -0
  257. package/payload/server/public/assets/public-DzeW3_eM.js +1 -0
  258. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-wPfZo_vs.js → quadrantDiagram-34T5L4WZ-n3bB3K91.js} +1 -1
  259. package/payload/server/public/assets/radar-PYXPWWZC-BHo2YD8b.js +1 -0
  260. package/payload/server/public/assets/{reduce-CFlDlJf5.js → reduce-DAvwat-a.js} +1 -1
  261. package/payload/server/public/assets/{requirementDiagram-MS252O5E-yYkH12K2.js → requirementDiagram-MS252O5E-DiDvQK3c.js} +1 -1
  262. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-fVWRBzzV.js → sankeyDiagram-XADWPNL6-DWDQQZmd.js} +1 -1
  263. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-Dbap3X6h.js → sequenceDiagram-FGHM5R23-DmAqRlBT.js} +1 -1
  264. package/payload/server/public/assets/square-CHcQHtK8.js +1 -0
  265. package/payload/server/public/assets/{src-Bi0fLV9t.js → src-DV4LKv2E.js} +1 -1
  266. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DkPLAqIh.js → stateDiagram-FHFEXIEX-D4R-n6bZ.js} +1 -1
  267. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BcFRbGRu.js +1 -0
  268. package/payload/server/public/assets/tasks-ClfJU1CK.js +1 -0
  269. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DabKBJyd.js → timeline-definition-GMOUNBTQ-CjiHGP4l.js} +1 -1
  270. package/payload/server/public/assets/treeView-SZITEDCU-BtRr5vXp.js +1 -0
  271. package/payload/server/public/assets/treemap-W4RFUUIX-D8p0sbyo.js +1 -0
  272. package/payload/server/public/assets/useCopyFeedback-CPEOUSGU.js +1 -0
  273. package/payload/server/public/assets/useSubAccountSwitcher-CdS1CorH.css +1 -0
  274. package/payload/server/public/assets/useSubAccountSwitcher-DyjTbzQR.js +9 -0
  275. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CaKT7c-c.js → vennDiagram-DHZGUBPP-CBdDQ7c-.js} +1 -1
  276. package/payload/server/public/assets/wardley-RL74JXVD-DgMn-9ZJ.js +1 -0
  277. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BZ5TTSOL.js → wardleyDiagram-NUSXRM2D-BlIQPKLb.js} +1 -1
  278. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CLfeklJ9.js → xychartDiagram-5P7HB3ND-CslKgh9B.js} +1 -1
  279. package/payload/server/public/browser.html +7 -5
  280. package/payload/server/public/calendar.html +8 -6
  281. package/payload/server/public/chat.html +14 -12
  282. package/payload/server/public/data.html +11 -10
  283. package/payload/server/public/graph.html +12 -10
  284. package/payload/server/public/index.html +15 -14
  285. package/payload/server/public/operator.html +16 -14
  286. package/payload/server/public/public.html +14 -12
  287. package/payload/server/public/tasks.html +18 -0
  288. package/payload/server/server.js +832 -233
  289. package/payload/server/public/assets/AdminLoginScreens-B1P6PrZ3.js +0 -1
  290. package/payload/server/public/assets/AdminShell-Y1fHQApK.js +0 -2
  291. package/payload/server/public/assets/Transcript-DZzFjhoq.js +0 -2
  292. package/payload/server/public/assets/admin-BRBjJEci.js +0 -1
  293. package/payload/server/public/assets/admin-types-hioowVct.js +0 -1
  294. package/payload/server/public/assets/architecture-YZFGNWBL-XiVs-N7Z.js +0 -1
  295. package/payload/server/public/assets/browser-ID7iqIi4.js +0 -1
  296. package/payload/server/public/assets/calendar-BEQPMTtd.js +0 -1
  297. package/payload/server/public/assets/channel-CYBkRz7E.js +0 -1
  298. package/payload/server/public/assets/chat-D0GDSWM-.js +0 -1
  299. package/payload/server/public/assets/chevron-left-A0HYKwGY.js +0 -1
  300. package/payload/server/public/assets/chunk-426QAEUC-CPhOHriU.js +0 -1
  301. package/payload/server/public/assets/chunk-QZHKN3VN-CDnAAZVJ.js +0 -1
  302. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BdXUKVrS.js +0 -1
  303. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DAq-uJr_.js +0 -1
  304. package/payload/server/public/assets/clone-DQl28-jK.js +0 -1
  305. package/payload/server/public/assets/data-CV38dClT.js +0 -1
  306. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BM-KaDZy.js +0 -1
  307. package/payload/server/public/assets/graph-BK0MjKRy.js +0 -51
  308. package/payload/server/public/assets/info-OMHHGYJF-CtZajyAB.js +0 -1
  309. package/payload/server/public/assets/infoDiagram-42DDH7IO-C-_WYlmI.js +0 -2
  310. package/payload/server/public/assets/operator-CnpNyIJ8.js +0 -1
  311. package/payload/server/public/assets/packet-4T2RLAQJ-T-SYedp7.js +0 -1
  312. package/payload/server/public/assets/page-DC_L-IS1.js +0 -32
  313. package/payload/server/public/assets/page-DKHLflh7.js +0 -1
  314. package/payload/server/public/assets/pie-ZZUOXDRM-BWECFVVd.js +0 -1
  315. package/payload/server/public/assets/public-ByUJr48E.js +0 -1
  316. package/payload/server/public/assets/radar-PYXPWWZC-Dx0YUklX.js +0 -1
  317. package/payload/server/public/assets/rotate-ccw-D45TbeAI.js +0 -1
  318. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DceWO1u6.js +0 -1
  319. package/payload/server/public/assets/treeView-SZITEDCU-C3197Rac.js +0 -1
  320. package/payload/server/public/assets/treemap-W4RFUUIX-BPrpx29h.js +0 -1
  321. package/payload/server/public/assets/useSubAccountSwitcher-CCn22f98.css +0 -1
  322. package/payload/server/public/assets/useSubAccountSwitcher-CprHkBnZ.js +0 -9
  323. package/payload/server/public/assets/wardley-RL74JXVD-DW4Jlbhw.js +0 -1
  324. /package/payload/server/public/assets/{_baseFor-BVuIxZJh.js → _baseFor-D3BqAOBr.js} +0 -0
  325. /package/payload/server/public/assets/{array-B9UHiPd-.js → array-iYP9fzJp.js} +0 -0
  326. /package/payload/server/public/assets/{chunk-CAM3fms7.js → chunk-Ck5AOu5v.js} +0 -0
  327. /package/payload/server/public/assets/{cytoscape.esm-D5_TRwB-.js → cytoscape.esm-BQSBzPsB.js} +0 -0
  328. /package/payload/server/public/assets/{defaultLocale-5eAKkKJC.js → defaultLocale-BrdA1gDi.js} +0 -0
  329. /package/payload/server/public/assets/{init-DlZdxViB.js → init-Bx0S6pkp.js} +0 -0
  330. /package/payload/server/public/assets/{katex-Xo0SyWvP.js → katex-BsiH_a6d.js} +0 -0
  331. /package/payload/server/public/assets/{path-6uRLdFF7.js → path-BLSgTy3w.js} +0 -0
  332. /package/payload/server/public/assets/{preload-helper-CvXuAEud.js → preload-helper-ClBMtM1g.js} +0 -0
  333. /package/payload/server/public/assets/{rough.esm-Djo4Abte.js → rough.esm-BMOtDaaS.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.423",
3
+ "version": "0.1.429",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -1,6 +1,10 @@
1
- export declare const EMBED_INPUT_MAX_CHARS = 8000;
1
+ export declare const EMBED_INPUT_MAX_CHARS: number;
2
2
  export declare const EMBED_SUBBATCH_SIZE: number;
3
3
  export declare const EMBED_SUBBATCH_COOLDOWN_MS: number;
4
+ export declare const EMBED_MS_PER_INPUT: number;
5
+ export declare const EMBED_REQUEST_TIMEOUT_MS: number;
6
+ export declare const EMBED_KEEP_ALIVE: number | string;
4
7
  export declare function embed(text: string): Promise<number[]>;
8
+ export declare function effectiveSubBatchSize(): number;
5
9
  export declare function embedBatch(texts: string[]): Promise<number[][]>;
6
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAmB1C,eAAO,MAAM,mBAAmB,QAA6D,CAAC;AAC9F,eAAO,MAAM,0BAA0B,QAGtC,CAAC;AA4BF,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAa3D;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAoBrE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,qBAAqB,QASjC,CAAC;AAaF,eAAO,MAAM,mBAAmB,QAA6D,CAAC;AAC9F,eAAO,MAAM,0BAA0B,QAGtC,CAAC;AAWF,eAAO,MAAM,kBAAkB,QAA8D,CAAC;AAQ9F,eAAO,MAAM,wBAAwB,QAGpC,CAAC;AAcF,eAAO,MAAM,gBAAgB,EAAE,MAAM,GAAG,MAEhB,CAAC;AA8EzB,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAG3D;AAKD,wBAAgB,qBAAqB,IAAI,MAAM,CAM9C;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAqBrE"}
@@ -6,16 +6,32 @@
6
6
  // and one POST shape across the platform (Task 636). fetch-only — no node:fs —
7
7
  // so it is safe to bundle into the ESM payload.
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.EMBED_SUBBATCH_COOLDOWN_MS = exports.EMBED_SUBBATCH_SIZE = exports.EMBED_INPUT_MAX_CHARS = void 0;
9
+ exports.EMBED_KEEP_ALIVE = exports.EMBED_REQUEST_TIMEOUT_MS = exports.EMBED_MS_PER_INPUT = exports.EMBED_SUBBATCH_COOLDOWN_MS = exports.EMBED_SUBBATCH_SIZE = exports.EMBED_INPUT_MAX_CHARS = void 0;
10
10
  exports.embed = embed;
11
+ exports.effectiveSubBatchSize = effectiveSubBatchSize;
11
12
  exports.embedBatch = embedBatch;
12
13
  const OLLAMA_URL = process.env.OLLAMA_URL ?? "http://localhost:11434";
13
14
  const EMBED_MODEL = process.env.EMBED_MODEL ?? "nomic-embed-text";
14
- // nomic-embed-text has a 2048-token context (~8k chars at ~4 chars/token).
15
- // An over-limit input makes the Ollama embed endpoint error; cap defensively so
16
- // an oversized body embeds (truncated) instead of throwing and aborting the
17
- // caller.
18
- exports.EMBED_INPUT_MAX_CHARS = 8000;
15
+ function envInt(name, def) {
16
+ const raw = process.env[name];
17
+ if (raw === undefined || raw === "")
18
+ return def;
19
+ const n = Number(raw);
20
+ return Number.isFinite(n) ? n : def;
21
+ }
22
+ // nomic-embed-text's usable embed context is 2048 tokens. The old 8000-char cap
23
+ // assumed ~4 chars/token, but dense emoji/markup content runs richer, so a
24
+ // section that passed the char cap still errored with "input length exceeds the
25
+ // context length". Size the default against a conservative 3 chars/token worst
26
+ // case, reserving a small token margin for the tokenizer's specials, so a capped
27
+ // input is provably under context: (2048 - 48) * 3 = 6000. Context is
28
+ // env-overridable so raising it raises the cap; EMBED_INPUT_MAX_CHARS is also
29
+ // directly overridable.
30
+ const EMBED_MODEL_CONTEXT_TOKENS = Math.max(1, Math.floor(envInt("EMBED_MODEL_CONTEXT_TOKENS", 2048)));
31
+ const EMBED_CONTEXT_MARGIN_TOKENS = 48;
32
+ const EMBED_WORST_CASE_CHARS_PER_TOKEN = 3;
33
+ exports.EMBED_INPUT_MAX_CHARS = Math.max(1, Math.floor(envInt("EMBED_INPUT_MAX_CHARS", (EMBED_MODEL_CONTEXT_TOKENS - EMBED_CONTEXT_MARGIN_TOKENS) *
34
+ EMBED_WORST_CASE_CHARS_PER_TOKEN)));
19
35
  // Batch pacing (Task 960). On a passively-cooled Pi, embedding a whole
20
36
  // document's sections in one `/api/embed` POST pins ollama's llama-server
21
37
  // across every core for the entire batch with no idle gaps — the SoC climbs
@@ -27,15 +43,39 @@ exports.EMBED_INPUT_MAX_CHARS = 8000;
27
43
  // this pacing is defence-in-depth and faster recovery. Both knobs are
28
44
  // env-overridable so an operator can tune them from on-device thermal
29
45
  // measurement without a code change.
30
- function envInt(name, def) {
31
- const raw = process.env[name];
32
- if (raw === undefined || raw === "")
33
- return def;
34
- const n = Number(raw);
35
- return Number.isFinite(n) ? n : def;
36
- }
37
46
  exports.EMBED_SUBBATCH_SIZE = Math.max(1, Math.floor(envInt("EMBED_SUBBATCH_SIZE", 32)));
38
47
  exports.EMBED_SUBBATCH_COOLDOWN_MS = Math.max(0, envInt("EMBED_SUBBATCH_COOLDOWN_MS", 1000));
48
+ // Throughput-aware sub-batch sizing (Task 1533). On a CPU-only embedder each
49
+ // input takes ~EMBED_MS_PER_INPUT ms; a fixed 32-input POST at the char cap is
50
+ // ~128 s, past the 120 s request timeout, so a full-document batch aborts and
51
+ // the atomic ingest write lands nothing. Bound each POST to 80% of the timeout
52
+ // so it provably completes: derive a duration ceiling and take the smaller of
53
+ // it and the count ceiling (EMBED_SUBBATCH_SIZE, Task 960's thermal cap).
54
+ // EMBED_MS_PER_INPUT is the budgeted worst-case wall-time for one input at the
55
+ // EMBED_INPUT_MAX_CHARS cap on the measured device; env-tunable for other
56
+ // hardware.
57
+ exports.EMBED_MS_PER_INPUT = Math.max(1, Math.floor(envInt("EMBED_MS_PER_INPUT", 6000)));
58
+ const EMBED_TIMEOUT_UTILISATION = 0.8;
59
+ // Explicit per-request timeout, well under undici's 300000ms headers default.
60
+ // Without it a slow or wedged ollama returns no headers and the caller hangs a
61
+ // silent 5 minutes before a bare `fetch failed`. With it the request aborts in
62
+ // seconds and throws a cause-naming error instead. Env-overridable for
63
+ // on-device tuning.
64
+ exports.EMBED_REQUEST_TIMEOUT_MS = Math.max(1, Math.floor(envInt("EMBED_REQUEST_TIMEOUT_MS", 120000)));
65
+ // Model warmth (Task 1533). Keep the embed model resident so an interactive
66
+ // graph query-embed never cold-loads (~10 s) and blows its 5 s timeout, and so
67
+ // a query issued while an ingest runs embeds warm instead of degrading to BM25.
68
+ // Ollama's keep_alive accepts a number (seconds; -1 = keep forever) or a
69
+ // duration string ("30m"). Pass a numeric value through as a number so "-1" is
70
+ // the keep-forever sentinel rather than an unparseable duration string.
71
+ // Treat an empty-string env as unset (matches envInt above), so
72
+ // `EMBED_KEEP_ALIVE=` does not send an empty keep_alive that Ollama rejects.
73
+ const EMBED_KEEP_ALIVE_RAW = process.env.EMBED_KEEP_ALIVE === undefined || process.env.EMBED_KEEP_ALIVE === ""
74
+ ? "-1"
75
+ : process.env.EMBED_KEEP_ALIVE;
76
+ exports.EMBED_KEEP_ALIVE = /^-?\d+$/.test(EMBED_KEEP_ALIVE_RAW)
77
+ ? Number(EMBED_KEEP_ALIVE_RAW)
78
+ : EMBED_KEEP_ALIVE_RAW;
39
79
  function capInput(text) {
40
80
  if (text.length <= exports.EMBED_INPUT_MAX_CHARS)
41
81
  return text;
@@ -43,49 +83,87 @@ function capInput(text) {
43
83
  return text.slice(0, exports.EMBED_INPUT_MAX_CHARS);
44
84
  }
45
85
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
46
- // POST one already-capped sub-batch of inputs to the embed endpoint.
47
- async function postBatch(inputs) {
48
- const res = await fetch(`${OLLAMA_URL}/api/embed`, {
49
- method: "POST",
50
- headers: { "Content-Type": "application/json" },
51
- body: JSON.stringify({ model: EMBED_MODEL, input: inputs }),
52
- });
86
+ // One POST to the embed endpoint for an already-capped input (a single string
87
+ // for embed(), an array for a sub-batch). Both paths route through here so the
88
+ // timeout and the cause-naming error apply on every embed call. The wire shape
89
+ // of `input` is preserved (string vs array) so the ollama request is unchanged.
90
+ // On timeout or failure the error's first line names the cause (timeout vs HTTP
91
+ // status), the input count, and the largest input size, so a slow or failing
92
+ // ollama is legible immediately rather than after a 5-minute silent hang.
93
+ async function embedRequest(input) {
94
+ const inputs = Array.isArray(input) ? input : [input];
95
+ const maxChars = inputs.reduce((m, s) => Math.max(m, s.length), 0);
96
+ const target = `${OLLAMA_URL}/api/embed`;
97
+ const startedAt = Date.now();
98
+ let res;
99
+ try {
100
+ res = await fetch(target, {
101
+ method: "POST",
102
+ headers: { "Content-Type": "application/json" },
103
+ body: JSON.stringify({ model: EMBED_MODEL, input, keep_alive: exports.EMBED_KEEP_ALIVE }),
104
+ signal: AbortSignal.timeout(exports.EMBED_REQUEST_TIMEOUT_MS),
105
+ });
106
+ }
107
+ catch (err) {
108
+ const name = err instanceof Error ? err.name : "";
109
+ if (name === "TimeoutError" || name === "AbortError") {
110
+ process.stderr.write(`[embed] op=timeout ms=${exports.EMBED_REQUEST_TIMEOUT_MS} inputs=${inputs.length} maxChars=${maxChars}\n`);
111
+ throw new Error(`Ollama embed request timed out after ${exports.EMBED_REQUEST_TIMEOUT_MS}ms (inputs=${inputs.length}, largestInputChars=${maxChars}) at ${target}; ollama did not respond in time (slow, cold-loading, or CPU-saturated). Raise EMBED_REQUEST_TIMEOUT_MS or check ollama.`);
112
+ }
113
+ // undici throws TypeError("fetch failed", { cause }) on a connection error
114
+ // (ollama down, refused, DNS). The legible cause is on err.cause, not the
115
+ // "fetch failed" message, so name it so "network is down" reads distinctly
116
+ // from "ollama is slow".
117
+ let detail = err instanceof Error ? err.message : String(err);
118
+ const cause = err instanceof Error ? err.cause : undefined;
119
+ if (cause !== undefined) {
120
+ detail += `: ${cause instanceof Error ? cause.message : String(cause)}`;
121
+ }
122
+ throw new Error(`Ollama embed request failed (inputs=${inputs.length}, largestInputChars=${maxChars}) at ${target}: ${detail}`);
123
+ }
53
124
  if (!res.ok) {
54
125
  const body = await res.text();
55
- throw new Error(`Ollama batch embedding failed (${res.status}): ${body}`);
126
+ throw new Error(`Ollama embed request failed (HTTP ${res.status}, inputs=${inputs.length}, largestInputChars=${maxChars}): ${body}`);
56
127
  }
57
128
  const data = (await res.json());
129
+ // Per-POST breadcrumb (Task 1533). One line per successful POST so an
130
+ // oversized or slow sub-batch is visible before it times out and the
131
+ // throughput-aware sizing is verifiable from the log. inputs is the POST's
132
+ // sub-batch size; maxChars its largest input.
133
+ process.stderr.write(`[embed] op=post inputs=${inputs.length} maxChars=${maxChars} ms=${Date.now() - startedAt}\n`);
58
134
  return data.embeddings;
59
135
  }
136
+ // POST one already-capped sub-batch of inputs to the embed endpoint.
137
+ async function postBatch(inputs) {
138
+ return embedRequest(inputs);
139
+ }
60
140
  async function embed(text) {
61
- const input = capInput(text);
62
- const res = await fetch(`${OLLAMA_URL}/api/embed`, {
63
- method: "POST",
64
- headers: { "Content-Type": "application/json" },
65
- body: JSON.stringify({ model: EMBED_MODEL, input }),
66
- });
67
- if (!res.ok) {
68
- const body = await res.text();
69
- throw new Error(`Ollama embedding failed (${res.status}): ${body}`);
70
- }
71
- const data = (await res.json());
72
- return data.embeddings[0];
141
+ const data = await embedRequest(capInput(text));
142
+ return data[0];
143
+ }
144
+ // The POST size actually used by embedBatch: the smaller of the count ceiling
145
+ // (thermal, Task 960) and the duration ceiling (throughput, Task 1533). At
146
+ // defaults: min(32, floor(120000*0.8/6000)) = min(32, 16) = 16.
147
+ function effectiveSubBatchSize() {
148
+ const durationCap = Math.max(1, Math.floor((exports.EMBED_REQUEST_TIMEOUT_MS * EMBED_TIMEOUT_UTILISATION) / exports.EMBED_MS_PER_INPUT));
149
+ return Math.min(exports.EMBED_SUBBATCH_SIZE, durationCap);
73
150
  }
74
151
  async function embedBatch(texts) {
75
152
  const inputs = texts.map(capInput);
153
+ const subBatch = effectiveSubBatchSize();
76
154
  // Common case — an array within the sub-batch size is one POST, unchanged.
77
- if (inputs.length <= exports.EMBED_SUBBATCH_SIZE) {
155
+ if (inputs.length <= subBatch) {
78
156
  return postBatch(inputs);
79
157
  }
80
158
  // Oversized: split into sub-batches, cooling between each (not after the
81
159
  // last). Vectors are concatenated in input order so callers can keep their
82
160
  // index-aligned `embeddings[i]` ↔ `texts[i]` contract.
83
161
  const out = [];
84
- for (let i = 0; i < inputs.length; i += exports.EMBED_SUBBATCH_SIZE) {
162
+ for (let i = 0; i < inputs.length; i += subBatch) {
85
163
  if (i > 0 && exports.EMBED_SUBBATCH_COOLDOWN_MS > 0) {
86
164
  await sleep(exports.EMBED_SUBBATCH_COOLDOWN_MS);
87
165
  }
88
- const chunk = inputs.slice(i, i + exports.EMBED_SUBBATCH_SIZE);
166
+ const chunk = inputs.slice(i, i + subBatch);
89
167
  out.push(...(await postBatch(chunk)));
90
168
  }
91
169
  return out;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -8,11 +8,34 @@
8
8
  const OLLAMA_URL = process.env.OLLAMA_URL ?? "http://localhost:11434";
9
9
  const EMBED_MODEL = process.env.EMBED_MODEL ?? "nomic-embed-text";
10
10
 
11
- // nomic-embed-text has a 2048-token context (~8k chars at ~4 chars/token).
12
- // An over-limit input makes the Ollama embed endpoint error; cap defensively so
13
- // an oversized body embeds (truncated) instead of throwing and aborting the
14
- // caller.
15
- export const EMBED_INPUT_MAX_CHARS = 8000;
11
+ function envInt(name: string, def: number): number {
12
+ const raw = process.env[name];
13
+ if (raw === undefined || raw === "") return def;
14
+ const n = Number(raw);
15
+ return Number.isFinite(n) ? n : def;
16
+ }
17
+
18
+ // nomic-embed-text's usable embed context is 2048 tokens. The old 8000-char cap
19
+ // assumed ~4 chars/token, but dense emoji/markup content runs richer, so a
20
+ // section that passed the char cap still errored with "input length exceeds the
21
+ // context length". Size the default against a conservative 3 chars/token worst
22
+ // case, reserving a small token margin for the tokenizer's specials, so a capped
23
+ // input is provably under context: (2048 - 48) * 3 = 6000. Context is
24
+ // env-overridable so raising it raises the cap; EMBED_INPUT_MAX_CHARS is also
25
+ // directly overridable.
26
+ const EMBED_MODEL_CONTEXT_TOKENS = Math.max(1, Math.floor(envInt("EMBED_MODEL_CONTEXT_TOKENS", 2048)));
27
+ const EMBED_CONTEXT_MARGIN_TOKENS = 48;
28
+ const EMBED_WORST_CASE_CHARS_PER_TOKEN = 3;
29
+ export const EMBED_INPUT_MAX_CHARS = Math.max(
30
+ 1,
31
+ Math.floor(
32
+ envInt(
33
+ "EMBED_INPUT_MAX_CHARS",
34
+ (EMBED_MODEL_CONTEXT_TOKENS - EMBED_CONTEXT_MARGIN_TOKENS) *
35
+ EMBED_WORST_CASE_CHARS_PER_TOKEN,
36
+ ),
37
+ ),
38
+ );
16
39
 
17
40
  // Batch pacing (Task 960). On a passively-cooled Pi, embedding a whole
18
41
  // document's sections in one `/api/embed` POST pins ollama's llama-server
@@ -25,18 +48,50 @@ export const EMBED_INPUT_MAX_CHARS = 8000;
25
48
  // this pacing is defence-in-depth and faster recovery. Both knobs are
26
49
  // env-overridable so an operator can tune them from on-device thermal
27
50
  // measurement without a code change.
28
- function envInt(name: string, def: number): number {
29
- const raw = process.env[name];
30
- if (raw === undefined || raw === "") return def;
31
- const n = Number(raw);
32
- return Number.isFinite(n) ? n : def;
33
- }
34
51
  export const EMBED_SUBBATCH_SIZE = Math.max(1, Math.floor(envInt("EMBED_SUBBATCH_SIZE", 32)));
35
52
  export const EMBED_SUBBATCH_COOLDOWN_MS = Math.max(
36
53
  0,
37
54
  envInt("EMBED_SUBBATCH_COOLDOWN_MS", 1000),
38
55
  );
39
56
 
57
+ // Throughput-aware sub-batch sizing (Task 1533). On a CPU-only embedder each
58
+ // input takes ~EMBED_MS_PER_INPUT ms; a fixed 32-input POST at the char cap is
59
+ // ~128 s, past the 120 s request timeout, so a full-document batch aborts and
60
+ // the atomic ingest write lands nothing. Bound each POST to 80% of the timeout
61
+ // so it provably completes: derive a duration ceiling and take the smaller of
62
+ // it and the count ceiling (EMBED_SUBBATCH_SIZE, Task 960's thermal cap).
63
+ // EMBED_MS_PER_INPUT is the budgeted worst-case wall-time for one input at the
64
+ // EMBED_INPUT_MAX_CHARS cap on the measured device; env-tunable for other
65
+ // hardware.
66
+ export const EMBED_MS_PER_INPUT = Math.max(1, Math.floor(envInt("EMBED_MS_PER_INPUT", 6000)));
67
+ const EMBED_TIMEOUT_UTILISATION = 0.8;
68
+
69
+ // Explicit per-request timeout, well under undici's 300000ms headers default.
70
+ // Without it a slow or wedged ollama returns no headers and the caller hangs a
71
+ // silent 5 minutes before a bare `fetch failed`. With it the request aborts in
72
+ // seconds and throws a cause-naming error instead. Env-overridable for
73
+ // on-device tuning.
74
+ export const EMBED_REQUEST_TIMEOUT_MS = Math.max(
75
+ 1,
76
+ Math.floor(envInt("EMBED_REQUEST_TIMEOUT_MS", 120000)),
77
+ );
78
+
79
+ // Model warmth (Task 1533). Keep the embed model resident so an interactive
80
+ // graph query-embed never cold-loads (~10 s) and blows its 5 s timeout, and so
81
+ // a query issued while an ingest runs embeds warm instead of degrading to BM25.
82
+ // Ollama's keep_alive accepts a number (seconds; -1 = keep forever) or a
83
+ // duration string ("30m"). Pass a numeric value through as a number so "-1" is
84
+ // the keep-forever sentinel rather than an unparseable duration string.
85
+ // Treat an empty-string env as unset (matches envInt above), so
86
+ // `EMBED_KEEP_ALIVE=` does not send an empty keep_alive that Ollama rejects.
87
+ const EMBED_KEEP_ALIVE_RAW =
88
+ process.env.EMBED_KEEP_ALIVE === undefined || process.env.EMBED_KEEP_ALIVE === ""
89
+ ? "-1"
90
+ : process.env.EMBED_KEEP_ALIVE;
91
+ export const EMBED_KEEP_ALIVE: number | string = /^-?\d+$/.test(EMBED_KEEP_ALIVE_RAW)
92
+ ? Number(EMBED_KEEP_ALIVE_RAW)
93
+ : EMBED_KEEP_ALIVE_RAW;
94
+
40
95
  function capInput(text: string): string {
41
96
  if (text.length <= EMBED_INPUT_MAX_CHARS) return text;
42
97
  process.stderr.write(
@@ -48,41 +103,93 @@ function capInput(text: string): string {
48
103
  const sleep = (ms: number): Promise<void> =>
49
104
  new Promise((resolve) => setTimeout(resolve, ms));
50
105
 
51
- // POST one already-capped sub-batch of inputs to the embed endpoint.
52
- async function postBatch(inputs: string[]): Promise<number[][]> {
53
- const res = await fetch(`${OLLAMA_URL}/api/embed`, {
54
- method: "POST",
55
- headers: { "Content-Type": "application/json" },
56
- body: JSON.stringify({ model: EMBED_MODEL, input: inputs }),
57
- });
106
+ // One POST to the embed endpoint for an already-capped input (a single string
107
+ // for embed(), an array for a sub-batch). Both paths route through here so the
108
+ // timeout and the cause-naming error apply on every embed call. The wire shape
109
+ // of `input` is preserved (string vs array) so the ollama request is unchanged.
110
+ // On timeout or failure the error's first line names the cause (timeout vs HTTP
111
+ // status), the input count, and the largest input size, so a slow or failing
112
+ // ollama is legible immediately rather than after a 5-minute silent hang.
113
+ async function embedRequest(input: string | string[]): Promise<number[][]> {
114
+ const inputs = Array.isArray(input) ? input : [input];
115
+ const maxChars = inputs.reduce((m, s) => Math.max(m, s.length), 0);
116
+ const target = `${OLLAMA_URL}/api/embed`;
117
+ const startedAt = Date.now();
118
+ let res: Response;
119
+ try {
120
+ res = await fetch(target, {
121
+ method: "POST",
122
+ headers: { "Content-Type": "application/json" },
123
+ body: JSON.stringify({ model: EMBED_MODEL, input, keep_alive: EMBED_KEEP_ALIVE }),
124
+ signal: AbortSignal.timeout(EMBED_REQUEST_TIMEOUT_MS),
125
+ });
126
+ } catch (err) {
127
+ const name = err instanceof Error ? err.name : "";
128
+ if (name === "TimeoutError" || name === "AbortError") {
129
+ process.stderr.write(
130
+ `[embed] op=timeout ms=${EMBED_REQUEST_TIMEOUT_MS} inputs=${inputs.length} maxChars=${maxChars}\n`,
131
+ );
132
+ throw new Error(
133
+ `Ollama embed request timed out after ${EMBED_REQUEST_TIMEOUT_MS}ms (inputs=${inputs.length}, largestInputChars=${maxChars}) at ${target}; ollama did not respond in time (slow, cold-loading, or CPU-saturated). Raise EMBED_REQUEST_TIMEOUT_MS or check ollama.`,
134
+ );
135
+ }
136
+ // undici throws TypeError("fetch failed", { cause }) on a connection error
137
+ // (ollama down, refused, DNS). The legible cause is on err.cause, not the
138
+ // "fetch failed" message, so name it so "network is down" reads distinctly
139
+ // from "ollama is slow".
140
+ let detail = err instanceof Error ? err.message : String(err);
141
+ const cause = err instanceof Error ? (err as { cause?: unknown }).cause : undefined;
142
+ if (cause !== undefined) {
143
+ detail += `: ${cause instanceof Error ? cause.message : String(cause)}`;
144
+ }
145
+ throw new Error(
146
+ `Ollama embed request failed (inputs=${inputs.length}, largestInputChars=${maxChars}) at ${target}: ${detail}`,
147
+ );
148
+ }
58
149
  if (!res.ok) {
59
150
  const body = await res.text();
60
- throw new Error(`Ollama batch embedding failed (${res.status}): ${body}`);
151
+ throw new Error(
152
+ `Ollama embed request failed (HTTP ${res.status}, inputs=${inputs.length}, largestInputChars=${maxChars}): ${body}`,
153
+ );
61
154
  }
62
155
  const data = (await res.json()) as { embeddings: number[][] };
156
+ // Per-POST breadcrumb (Task 1533). One line per successful POST so an
157
+ // oversized or slow sub-batch is visible before it times out and the
158
+ // throughput-aware sizing is verifiable from the log. inputs is the POST's
159
+ // sub-batch size; maxChars its largest input.
160
+ process.stderr.write(
161
+ `[embed] op=post inputs=${inputs.length} maxChars=${maxChars} ms=${Date.now() - startedAt}\n`,
162
+ );
63
163
  return data.embeddings;
64
164
  }
65
165
 
166
+ // POST one already-capped sub-batch of inputs to the embed endpoint.
167
+ async function postBatch(inputs: string[]): Promise<number[][]> {
168
+ return embedRequest(inputs);
169
+ }
170
+
66
171
  export async function embed(text: string): Promise<number[]> {
67
- const input = capInput(text);
68
- const res = await fetch(`${OLLAMA_URL}/api/embed`, {
69
- method: "POST",
70
- headers: { "Content-Type": "application/json" },
71
- body: JSON.stringify({ model: EMBED_MODEL, input }),
72
- });
73
- if (!res.ok) {
74
- const body = await res.text();
75
- throw new Error(`Ollama embedding failed (${res.status}): ${body}`);
76
- }
77
- const data = (await res.json()) as { embeddings: number[][] };
78
- return data.embeddings[0];
172
+ const data = await embedRequest(capInput(text));
173
+ return data[0];
174
+ }
175
+
176
+ // The POST size actually used by embedBatch: the smaller of the count ceiling
177
+ // (thermal, Task 960) and the duration ceiling (throughput, Task 1533). At
178
+ // defaults: min(32, floor(120000*0.8/6000)) = min(32, 16) = 16.
179
+ export function effectiveSubBatchSize(): number {
180
+ const durationCap = Math.max(
181
+ 1,
182
+ Math.floor((EMBED_REQUEST_TIMEOUT_MS * EMBED_TIMEOUT_UTILISATION) / EMBED_MS_PER_INPUT),
183
+ );
184
+ return Math.min(EMBED_SUBBATCH_SIZE, durationCap);
79
185
  }
80
186
 
81
187
  export async function embedBatch(texts: string[]): Promise<number[][]> {
82
188
  const inputs = texts.map(capInput);
189
+ const subBatch = effectiveSubBatchSize();
83
190
 
84
191
  // Common case — an array within the sub-batch size is one POST, unchanged.
85
- if (inputs.length <= EMBED_SUBBATCH_SIZE) {
192
+ if (inputs.length <= subBatch) {
86
193
  return postBatch(inputs);
87
194
  }
88
195
 
@@ -90,11 +197,11 @@ export async function embedBatch(texts: string[]): Promise<number[][]> {
90
197
  // last). Vectors are concatenated in input order so callers can keep their
91
198
  // index-aligned `embeddings[i]` ↔ `texts[i]` contract.
92
199
  const out: number[][] = [];
93
- for (let i = 0; i < inputs.length; i += EMBED_SUBBATCH_SIZE) {
200
+ for (let i = 0; i < inputs.length; i += subBatch) {
94
201
  if (i > 0 && EMBED_SUBBATCH_COOLDOWN_MS > 0) {
95
202
  await sleep(EMBED_SUBBATCH_COOLDOWN_MS);
96
203
  }
97
- const chunk = inputs.slice(i, i + EMBED_SUBBATCH_SIZE);
204
+ const chunk = inputs.slice(i, i + subBatch);
98
205
  out.push(...(await postBatch(chunk)));
99
206
  }
100
207
  return out;
@@ -190,6 +190,19 @@ OPTIONS {
190
190
  }
191
191
  };
192
192
 
193
+ // ----------------------------------------------------------
194
+ // TimeEntry node — per-task billable time recording (Task 1507)
195
+ // A running timer is the single :TimeEntry for an account with endedAt=null.
196
+ // On stop, endedAt + seconds are set and the task's denormalized
197
+ // secondsLogged sum is bumped. (:TimeEntry)-[:LOGGED_AGAINST]->(:Task).
198
+ // ----------------------------------------------------------
199
+
200
+ CREATE CONSTRAINT time_entry_id_unique IF NOT EXISTS
201
+ FOR (te:TimeEntry) REQUIRE te.entryId IS UNIQUE;
202
+
203
+ CREATE INDEX time_entry_task IF NOT EXISTS
204
+ FOR (te:TimeEntry) ON (te.taskId);
205
+
193
206
  // ----------------------------------------------------------
194
207
  // CreativeWork node — agent-authored documents (session summaries etc.)
195
208
  // Schema.org: schema.org/CreativeWork
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "admin",
3
- "description": "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_channel_routing_set repoints the install's single WhatsApp/Telegram inbound stream to a different sub-account), admin-add, admin-remove, admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform.",
3
+ "description": "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires a managing house admin (its userId) and refuses without one, recording it as the sub-account's managingAdminUserId; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId); account_channel_routing_set repoints the install's single WhatsApp/Telegram inbound stream to a different sub-account), admin-add, admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform.",
4
4
  "version": "0.1.0",
5
5
  "author": {
6
6
  "name": "Rubytech LLC"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: admin
3
3
  surface: platform
4
- description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_channel_routing_set repoints the install's single WhatsApp/Telegram inbound stream to a different sub-account), admin-add, admin-remove, admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
4
+ description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), admin-hostname (the admin-host twin of public-hostname — resolves the host that serves /calendar and the rest of the admin shell behind sign-in from the same ingress + alias + operator files, so agents point the operator at the admin /calendar URL instead of the public host that 404s it), publish-site (move an extracted static-site tree under <accountDir>/sites/<slug>/, emit one canonical path slug, and refresh llms.txt at the site root — typed refusal taxonomy replaces the prior skill-prose contract), brand-settings, account-manage, capabilities-here (deterministic install-introspection — returns enabledPlugins, tier, models, installed platform + premium specialists, registered Claude Code agent types, and the brand block as a single JSON object; the canonical tool for grounding any claim about what is enabled on the current account), account-update, the multi-account managed-service lifecycle tools (account_list, account_create, account_delete, account_purge, account_channel_routing, account_channel_routing_set — one Rubytech operator hosting N client accounts on one house install; create/delete/purge are operator-only and purge is two-step with a typed confirmation; account_create requires a managing house admin (its userId) and refuses without one, recording it as the sub-account's managingAdminUserId; account_reassign_admin repoints a client sub-account's managing admin to another live house admin (the repair path for a dangling managingAdminUserId); account_channel_routing_set repoints the install's single WhatsApp/Telegram inbound stream to a different sub-account), admin-add, admin-remove (refuses to remove a house admin who still manages one or more client sub-accounts, naming them so the operator reassigns each with account_reassign_admin first — never silently orphans them), admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), skill-search (free-text intent → skill resolver: ranks every plugin skill's SKILL.md name+description against a query and returns the top owners with their canonical skills/<slug>/ path, so intent→skill mapping survives the available-skills menu leaving context after a compaction), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
5
5
  tools:
6
6
  - name: system-status
7
7
  publicAllowlist: false
@@ -33,6 +33,9 @@ tools:
33
33
  - name: account_create
34
34
  publicAllowlist: false
35
35
  adminAllowlist: true
36
+ - name: account_reassign_admin
37
+ publicAllowlist: false
38
+ adminAllowlist: true
36
39
  - name: account_delete
37
40
  publicAllowlist: false
38
41
  adminAllowlist: true
@@ -175,6 +178,7 @@ Tools are available via the `admin` MCP server.
175
178
  - `hooks/post-tool-use-agent.sh` — **PostToolUse hook on `Agent`.** Drains any subagent hook-decision buffers under `~/.maxy-code/logs/hook-decisions/` modified since this parent's previous PostToolUse-Agent fire (cursor file keyed by parent session id), prints one `[hook-propagate]` line per record to stdout — Claude Code attaches the stdout as a `hook_success` attachment on the parent JSONL, making the records grep-queryable from the parent session alone. Rotates consumed buffers to `consumed/`. Emits one `[hook-propagate-census] parentSession=<…> subagentHooksObserved=<N> attachmentsEmitted=<M>` line per fire to stdout and server.log; `N != M` is the propagation regression signal. The companion emitter library `hooks/lib/hook-emit.sh` is sourced by `post-tool-use-agent.sh` and any other hook that records a block decision (4 KB stderr truncation, `truncated=true` set on the record).
176
179
  - `hooks/admin-authoring-observer.sh` — **PostToolUse hook on Write and Edit.** Observation only — never blocks; exits 0 on every path. Fires when the admin agent (not a specialist subagent — gated by `MAXY_SPECIALIST` env) writes or edits a file under `<accountDir>/output/`. Walks the session transcript from the latest real-user turn forward to detect any prior `Task` `tool_use` whose `subagent_type` starts with `specialists:`. Emits one stderr line `[admin-authoring] inline-write path=<rel> priorSpecialistSpawnInTurn=<true|false|unknown>`. A `false` value on a long-form prose file is the regression signal this hook was designed to make visible — the BioSymm proposal session (admin authored a customer-facing proposal inline despite content-producer being installed) is the failure mode this surfaces mechanically. Mechanical enforcement (refuse the write, force a re-spawn) is deferred per the task spec.
177
180
  - `hooks/prompt-optimiser-directive.sh` — **UserPromptSubmit hook.** Injects the standing prompt-optimiser restatement directive plus the per-turn three-tier routing ladder as `additionalContext`: **(1)** delegate to the specialist that owns the deliverable via the Agent tool — the brief states the outcome plus binding constraints, never lines/anchors/literal text; **(2)** only if none fits, load an admin-usable skill with `skill-load`; **(3)** only if neither fits, author inline — freestyle is the named last resort. Re-emits the full agent roster (`agents/admin/AGENTS.md`) and the full admin-usable skills list (`agents/admin/ADMIN-SKILLS.md`) every turn by reading the two generated files from the account dir (the hook fires with the account dir as cwd); it never walks the plugins tree per turn. Fail-open is **visible**: a missing list logs `[prompt-optimiser] missing=<AGENTS.md\|ADMIN-SKILLS.md> emitting-partial` to stderr and the ladder still injects. The trivial-turn skip (one-word confirmation, slash-command, direct continuation) is unchanged. **Staleness:** `ADMIN-SKILLS.md` is regenerated only by `setup-account.sh`; a plugin add/remove since the last setup leaves the list stale — compare `ADMIN-SKILLS.md` mtime against the newest `SKILL.md` mtime and re-run setup to refresh. The list generator is `platform/scripts/lib/admin-skills-bootstrap.sh`; it logs `[admin-skills] scanned=<N> admin-usable=<M> no-declaration=<K>` (failure signature: `admin-usable=0` while `scanned>0`, or any `missing-declaration` line). The directive also carries a standing CAPABILITY-QUESTIONS-ARE-OWNED-WORK clause (how-to / "do you have instructions for X" / config questions about platform features are answered from the owning specialist or plugin tool/reference, never from training memory), and the hook appends a durable `<ts> [prompt-optimiser-directive] injected len=<n> session=<id>` breadcrumb to `$LOG_DIR/prompt-optimiser-directive.log` so per-turn injection is greppable, not stderr-only. The directive is also **suppressed on native channel turns** — when the parsed `.prompt` starts with the `<channel source=` event marker, the hook logs `[prompt-optimiser-directive] skipped reason=channel-turn session=<id>` to stderr and exits without injecting, because the channel service already reframes the inbound into a select-and-dispatch turn (`composeAdminContent`, see `.docs/whatsapp-inbound-lifeline.md`). Marker-matched at start-of-prompt only, so an admin/Terminal prompt that merely mentions "channel" still gets the directive; fail-open injects if the prompt cannot be parsed.
181
+ - `hooks/datetime-inject.sh` — **UserPromptSubmit hook.** Injects a fresh `<datetime>` block as `additionalContext` on every turn (`refresh=per-turn`), so the agent always has the current instant — date, time, timezone, weekday, and the raw UTC ISO — without hand-computing it and without depending on Claude Code's spawn-time "Today's date" line going stale. The instant is computed fresh each turn; the timezone is **not** computed here — it is the operator's own zone, resolved from their `UserProfile.timezone` on the graph once per admin spawn and stamped into `MAXY_ACCOUNT_TZ` (see `platform/services/claude-session-manager/src/account-timezone.ts`). When `MAXY_ACCOUNT_TZ` is empty (a non-admin turn, an unset profile timezone, or a neo4j hiccup at spawn) the block falls back to the server's own zone and labels the source, so a reader can always tell which clock the agent saw. This is the current-time surface the `datetime` skill points at. **Fail-open** on every path (missing `python3` or `node`, any formatting error → exit 0, empty stdout — the turn is never blocked). The hook appends `<ts> [datetime-inject] injected tz=<zone> source=<graph|server-fallback> refresh=per-turn session=<id>` to `$LOG_DIR/datetime-inject.log` so "did the agent have the right time this turn, and from which clock?" is answerable from logs without reproduction.
178
182
  - `hooks/prompt-optimiser-compliance.sh` — **Stop hook.** After each admin turn, reads the just-finished turn from `transcript_path` and appends `<ts> [prompt-optimiser-compliance] directive-fired no-route-taken session=<id8> prompt="<clip>"` to `$LOG_DIR/prompt-optimiser-directive.log` (and stderr) when the routing directive fired, the prompt was non-trivial (not a slash-command, not a one-word confirmation), and the turn took **no route** — no `Agent` dispatch, no `Skill` load, no `ToolSearch`, no `mcp__*` tool call. This is the standing compliance signal that surfaces the session-`da0b12d4` failure class (agent answers a capability question from memory) as a visible event instead of a silent stale answer. Directive-fired is detected by the marker `PROMPT-OPTIMISER DIRECTIVE` in the turn slice, so it is robust to the CC-version difference in how `UserPromptSubmit` `additionalContext` is recorded (`attachment`/`hook_success` vs `hook_additional_context`). **Known limitation:** "direct continuation of the prior turn" is not detectable from the transcript, so a continuation turn that legitimately needs no route can be flagged; treat the log as a review signal, not a gate. **Fail-open:** no python3, no `transcript_path`, or an unreadable transcript → exit 0, no output. Lives in the same log as the directive breadcrumb, so a single `grep` interleaves "fired" and "no-route" into one per-session timeline; cross-check via `platform/scripts/logs-read.sh <sessionKey>`. This is a lightweight transcript read, not a per-turn spawn (contrast the turn recorder below).
179
183
  - **Turn recorder — removed entirely.** The `turn-completed-graph-write.sh` Stop hook, the `/api/admin/claude-sessions` loopback bypass it relied on, the `[turn-recorder]` emitters, the envelope walker, and the recorder-auto-archive subscriber are deleted. It had been dormant for a long time (never re-registered in settings.json); the admin now writes to the graph by delegating to `database-operator` via the Task tool inside the live session, and the on-demand `/insight` pass (`skills/insight/SKILL.md`, a registered admin skill) is the per-session review. There is no per-turn spawn.
180
184