@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
@@ -75,6 +75,7 @@ import {
75
75
  loadUserProfile,
76
76
  migrateLegacyRemotePassword,
77
77
  persistMessage,
78
+ preloadEmbedModel,
78
79
  projectAgent,
79
80
  reconcileEnabledPlugins,
80
81
  recordFailedAttempt,
@@ -110,7 +111,7 @@ import {
110
111
  vncLog,
111
112
  walkPremiumBundles,
112
113
  writeAdminUserAndPerson
113
- } from "./chunk-3Z5WE53X.js";
114
+ } from "./chunk-UUG6ZSO5.js";
114
115
  import {
115
116
  __commonJS,
116
117
  __toESM
@@ -3336,6 +3337,17 @@ var STORE_ROOT = () => join3(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data",
3336
3337
  function conversationFile(platformAccountId, remoteJid) {
3337
3338
  return join3(STORE_ROOT(), platformAccountId, `${remoteJid}.jsonl`);
3338
3339
  }
3340
+ function listStoredAccountIds() {
3341
+ const root = STORE_ROOT();
3342
+ if (!existsSync3(root)) return [];
3343
+ return readdirSync(root).filter((name) => {
3344
+ try {
3345
+ return statSync2(join3(root, name)).isDirectory();
3346
+ } catch {
3347
+ return false;
3348
+ }
3349
+ });
3350
+ }
3339
3351
  function conversationFilePath(platformAccountId, remoteJid) {
3340
3352
  return conversationFile(platformAccountId, remoteJid);
3341
3353
  }
@@ -4207,6 +4219,9 @@ var whatsAppConfig = {};
4207
4219
  var onInboundMessage = null;
4208
4220
  var initialized = false;
4209
4221
  var messageStore = /* @__PURE__ */ new Map();
4222
+ function messageStoreKey(accountId, remoteJid) {
4223
+ return `${accountId}:${remoteJid}`;
4224
+ }
4210
4225
  function storeMessage(storeKey, entry) {
4211
4226
  let entries = messageStore.get(storeKey);
4212
4227
  if (!entries) {
@@ -4370,6 +4385,9 @@ function selectConnection(conns, accountId) {
4370
4385
  function resolveSocket(accountId) {
4371
4386
  return selectConnection(Array.from(connections.values()), accountId);
4372
4387
  }
4388
+ function listConnectionPlatformAccountIds() {
4389
+ return [...connections.values()].map((conn) => conn.platformAccountId);
4390
+ }
4373
4391
  async function registerLoginSocket(accountId, sock, authDir) {
4374
4392
  if (!configDir) throw new Error("WhatsApp manager not initialized");
4375
4393
  let platformAccountId;
@@ -4460,11 +4478,11 @@ function reloadConfig(accountConfig) {
4460
4478
  loadConfig(accountConfig);
4461
4479
  }
4462
4480
  function getMessages(accountId, jid, limit) {
4463
- const entries = messageStore.get(`${accountId}:${jid}`) ?? [];
4481
+ const entries = messageStore.get(messageStoreKey(accountId, jid)) ?? [];
4464
4482
  return limit ? entries.slice(-limit) : entries.slice();
4465
4483
  }
4466
4484
  function listConversationJids(accountId) {
4467
- const prefix = `${accountId}:`;
4485
+ const prefix = messageStoreKey(accountId, "");
4468
4486
  const jids = [];
4469
4487
  for (const key of messageStore.keys()) {
4470
4488
  if (key.startsWith(prefix)) {
@@ -4473,6 +4491,14 @@ function listConversationJids(accountId) {
4473
4491
  }
4474
4492
  return jids;
4475
4493
  }
4494
+ function listStoreAccountKeys() {
4495
+ const accounts = /* @__PURE__ */ new Set();
4496
+ for (const key of messageStore.keys()) {
4497
+ const i = key.indexOf(":");
4498
+ if (i > 0) accounts.add(key.slice(0, i));
4499
+ }
4500
+ return [...accounts];
4501
+ }
4476
4502
  async function shutdown() {
4477
4503
  await drainCredsSaveQueue();
4478
4504
  const ids = Array.from(connections.keys());
@@ -4682,7 +4708,7 @@ function monitorInbound(conn) {
4682
4708
  const senderJid = isGroup ? msg.key.participant ?? remoteJid : remoteJid;
4683
4709
  const senderPhone = await resolveJidToE164(senderJid, conn.lidMapping) ?? senderJid;
4684
4710
  const ts = msg.messageTimestamp ? Number(msg.messageTimestamp) : Math.floor(Date.now() / 1e3);
4685
- const storeKey = `${conn.accountId}:${remoteJid}`;
4711
+ const storeKey = messageStoreKey(conn.platformAccountId, remoteJid);
4686
4712
  storeMessage(storeKey, {
4687
4713
  id: msg.key.id ?? `${remoteJid}-${ts}`,
4688
4714
  sender: senderPhone,
@@ -4694,7 +4720,7 @@ function monitorInbound(conn) {
4694
4720
  });
4695
4721
  const entries = messageStore.get(storeKey);
4696
4722
  console.error(
4697
- `${TAG13} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) account=${conn.accountId}`
4723
+ `${TAG13} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) account=${conn.platformAccountId}`
4698
4724
  );
4699
4725
  recordActivity({
4700
4726
  accountId: conn.accountId,
@@ -5910,8 +5936,8 @@ function webchatTurnTimeoutMs() {
5910
5936
  return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
5911
5937
  }
5912
5938
  function createChatRoutes(deps) {
5913
- const app57 = new Hono();
5914
- app57.post("/", async (c) => {
5939
+ const app61 = new Hono();
5940
+ app61.post("/", async (c) => {
5915
5941
  console.log(`[chat-route] entered route=public method=POST`);
5916
5942
  const contentType = c.req.header("content-type") ?? "";
5917
5943
  const account = resolveAccount();
@@ -6174,7 +6200,7 @@ ${result.result.text}` : result.result.text;
6174
6200
  }
6175
6201
  });
6176
6202
  });
6177
- return app57;
6203
+ return app61;
6178
6204
  }
6179
6205
 
6180
6206
  // app/lib/channel-pty-bridge/admin-session-id.ts
@@ -6189,14 +6215,28 @@ function adminSessionIdFor(accountId, senderId, personId) {
6189
6215
  return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
6190
6216
  }
6191
6217
 
6218
+ // app/lib/channel-pty-bridge/schedule-provenance.ts
6219
+ function parseScheduleProvenance(v) {
6220
+ if (!v || typeof v !== "object") return void 0;
6221
+ const o = v;
6222
+ if (typeof o.accountId !== "string" || typeof o.eventId !== "string" || typeof o.dispatchedAt !== "string") {
6223
+ return void 0;
6224
+ }
6225
+ if (!Array.isArray(o.authoredBy)) return void 0;
6226
+ const authoredBy = o.authoredBy.filter((u) => typeof u === "string" && u.length > 0);
6227
+ const createdByTool = typeof o.createdByTool === "string" && o.createdByTool.length > 0 ? o.createdByTool : null;
6228
+ return { accountId: o.accountId, eventId: o.eventId, authoredBy, createdByTool, dispatchedAt: o.dispatchedAt };
6229
+ }
6230
+
6192
6231
  // server/routes/channel/schedule-inject.ts
6193
6232
  var TAG16 = "[schedule-inject]";
6233
+ var UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
6194
6234
  function isLoopbackAddr(addr) {
6195
6235
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
6196
6236
  }
6197
6237
  function createScheduleInjectRoutes(deps) {
6198
- const app57 = new Hono();
6199
- app57.post("/", async (c) => {
6238
+ const app61 = new Hono();
6239
+ app61.post("/", async (c) => {
6200
6240
  const env = c.env;
6201
6241
  const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
6202
6242
  if (!isLoopbackAddr(remoteAddr)) {
@@ -6222,6 +6262,8 @@ function createScheduleInjectRoutes(deps) {
6222
6262
  const destination = typeof body.destination === "string" ? body.destination : "";
6223
6263
  const prompt = typeof body.prompt === "string" ? body.prompt : "";
6224
6264
  const eventId = typeof body.eventId === "string" ? body.eventId : "";
6265
+ const scheduleProvenance = parseScheduleProvenance(body.scheduleProvenance);
6266
+ const overrideSessionId = typeof body.sessionId === "string" && UUID_V4.test(body.sessionId) ? body.sessionId : void 0;
6225
6267
  if (channel !== "whatsapp" && channel !== "telegram" || !destination || !prompt) {
6226
6268
  console.error(`${TAG16} reject reason=bad-request channel=${String(channel)} hasDestination=${Boolean(destination)} hasPrompt=${Boolean(prompt)}`);
6227
6269
  return c.json({ ok: false, error: "schedule-inject-bad-request" }, 400);
@@ -6240,7 +6282,7 @@ function createScheduleInjectRoutes(deps) {
6240
6282
  return c.json({ ok: false, error: "account-manager-unresolved" }, 403);
6241
6283
  }
6242
6284
  console.error(`${TAG16} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount2}`);
6243
- const sessionId2 = adminSessionIdFor(effectiveAccount2, destination);
6285
+ const sessionId2 = overrideSessionId ?? adminSessionIdFor(effectiveAccount2, destination);
6244
6286
  const reply2 = (text) => deps.sendWhatsAppText(houseAccountId, destination, text);
6245
6287
  try {
6246
6288
  await deps.waHandleInbound({
@@ -6257,6 +6299,8 @@ function createScheduleInjectRoutes(deps) {
6257
6299
  text: prompt,
6258
6300
  media: [],
6259
6301
  source: "schedule",
6302
+ scheduleProvenance,
6303
+ scheduledSessionId: overrideSessionId,
6260
6304
  reply: reply2
6261
6305
  });
6262
6306
  } catch (err) {
@@ -6274,7 +6318,7 @@ function createScheduleInjectRoutes(deps) {
6274
6318
  return c.json({ ok: false, error: "no-admin-bot-token" }, 400);
6275
6319
  }
6276
6320
  const chatId = Number(destination);
6277
- const sessionId = adminSessionIdFor(effectiveAccount, destination);
6321
+ const sessionId = overrideSessionId ?? adminSessionIdFor(effectiveAccount, destination);
6278
6322
  const reply = (text) => deps.sendTelegramText(botToken, chatId, text);
6279
6323
  try {
6280
6324
  await deps.tgHandleInbound({
@@ -6285,6 +6329,8 @@ function createScheduleInjectRoutes(deps) {
6285
6329
  personId: null,
6286
6330
  text: prompt,
6287
6331
  source: "schedule",
6332
+ scheduleProvenance,
6333
+ scheduledSessionId: overrideSessionId,
6288
6334
  reply
6289
6335
  });
6290
6336
  } catch (err) {
@@ -6294,7 +6340,7 @@ function createScheduleInjectRoutes(deps) {
6294
6340
  console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
6295
6341
  return c.json({ ok: true }, 200);
6296
6342
  });
6297
- return app57;
6343
+ return app61;
6298
6344
  }
6299
6345
 
6300
6346
  // server/index.ts
@@ -7054,6 +7100,13 @@ function listActiveLoginAccountIds() {
7054
7100
  return ids;
7055
7101
  }
7056
7102
 
7103
+ // app/lib/whatsapp/store-key-reconcile.ts
7104
+ function reconcileMessageStoreAccountKeys(input) {
7105
+ const reachable = new Set(input.reachableAccountIds);
7106
+ const orphanLiveKeys = input.liveAccountKeys.filter((k) => !reachable.has(k));
7107
+ return { ok: orphanLiveKeys.length === 0, orphanLiveKeys };
7108
+ }
7109
+
7057
7110
  // app/lib/whatsapp/outbound/send-document.ts
7058
7111
  import { realpathSync as realpathSync3 } from "fs";
7059
7112
  import { readFile, stat as stat2 } from "fs/promises";
@@ -7380,6 +7433,19 @@ function filterConversationsForSubAccount(conversations, managerPhones) {
7380
7433
  return out;
7381
7434
  }
7382
7435
 
7436
+ // app/lib/whatsapp/authorize-recall-read.ts
7437
+ function authorizeRecallRead(input) {
7438
+ const { requestedAccountId } = input;
7439
+ const callerAccountId = input.callerAccountId && input.callerAccountId.length > 0 ? input.callerAccountId : null;
7440
+ const houseAdminScope = input.houseAdminScope && input.houseAdminScope.length > 0 ? input.houseAdminScope : null;
7441
+ if (houseAdminScope) return { authorized: true };
7442
+ if (callerAccountId && requestedAccountId === callerAccountId) return { authorized: true };
7443
+ return {
7444
+ authorized: false,
7445
+ reason: `Not authorized to read WhatsApp history for account "${requestedAccountId}". This session may only read its own account.`
7446
+ };
7447
+ }
7448
+
7383
7449
  // server/routes/whatsapp.ts
7384
7450
  var TAG21 = "[whatsapp:api]";
7385
7451
  var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT || "";
@@ -7401,6 +7467,14 @@ function projectionFor(requestedAccountId) {
7401
7467
  houseAccountManagers
7402
7468
  });
7403
7469
  }
7470
+ function callerScopeDenial(c, requestedAccountId) {
7471
+ const callerAccountId = c.req.header("x-maxy-caller-account")?.trim() || null;
7472
+ const houseAdminScope = c.req.header("x-maxy-house-admin-scope")?.trim() || null;
7473
+ const decision = authorizeRecallRead({ requestedAccountId, callerAccountId, houseAdminScope });
7474
+ if (decision.authorized) return null;
7475
+ console.error(`[whatsapp-read-tool] op=authz-deny requested=${requestedAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
7476
+ return c.json({ error: decision.reason }, 403);
7477
+ }
7404
7478
  var app2 = new Hono();
7405
7479
  app2.get("/status", (c) => {
7406
7480
  try {
@@ -7413,7 +7487,17 @@ app2.get("/status", (c) => {
7413
7487
  const accounts = [...live, ...reconciled];
7414
7488
  const summary = accounts.map((a) => `${a.accountId}:${a.connected ? "up" : a.linkedUnconfigured ? "linked-unconfigured" : "down"}`).join(", ");
7415
7489
  console.error(`${TAG21} status accounts=${accounts.length} [${summary}]`);
7416
- return c.json({ accounts });
7490
+ const reachableAccountIds = [
7491
+ .../* @__PURE__ */ new Set([...listStoredAccountIds(), ...listConnectionPlatformAccountIds()])
7492
+ ];
7493
+ const storeKeyReconcile = reconcileMessageStoreAccountKeys({
7494
+ liveAccountKeys: listStoreAccountKeys(),
7495
+ reachableAccountIds
7496
+ });
7497
+ if (!storeKeyReconcile.ok) {
7498
+ console.warn(`${TAG21} store-key-drift orphanLiveKeys=[${storeKeyReconcile.orphanLiveKeys.join(",")}] \u2014 in-memory cache keyed by a value with no disk account; read tools will miss`);
7499
+ }
7500
+ return c.json({ accounts, storeKeyReconcile });
7417
7501
  } catch (err) {
7418
7502
  console.error(`${TAG21} status error: ${String(err)}`);
7419
7503
  return c.json({ error: String(err) }, 500);
@@ -7705,6 +7789,8 @@ app2.get("/activity", (c) => {
7705
7789
  app2.get("/conversations", (c) => {
7706
7790
  try {
7707
7791
  const accountId = validateAccountId(c.req.query("accountId") ?? null);
7792
+ const denial = callerScopeDenial(c, accountId);
7793
+ if (denial) return denial;
7708
7794
  const jids = listConversationJids(accountId);
7709
7795
  const conversations = jids.map((jid) => {
7710
7796
  const messages = getMessages(accountId, jid);
@@ -7717,7 +7803,7 @@ app2.get("/conversations", (c) => {
7717
7803
  };
7718
7804
  });
7719
7805
  conversations.sort((a, b) => (b.lastMessageTimestamp ?? 0) - (a.lastMessageTimestamp ?? 0));
7720
- console.error(`${TAG21} conversations account=${accountId} count=${conversations.length}`);
7806
+ console.error(`${TAG21} conversations account=${accountId} storeKeyFound=${jids.length > 0} count=${conversations.length}`);
7721
7807
  return c.json({ conversations });
7722
7808
  } catch (err) {
7723
7809
  console.error(`${TAG21} conversations error: ${String(err)}`);
@@ -7727,6 +7813,8 @@ app2.get("/conversations", (c) => {
7727
7813
  app2.get("/messages", (c) => {
7728
7814
  try {
7729
7815
  const accountId = validateAccountId(c.req.query("accountId") ?? null);
7816
+ const denial = callerScopeDenial(c, accountId);
7817
+ if (denial) return denial;
7730
7818
  const jid = c.req.query("jid");
7731
7819
  if (!jid) {
7732
7820
  return c.json({ error: "Missing required parameter: jid" }, 400);
@@ -7735,7 +7823,8 @@ app2.get("/messages", (c) => {
7735
7823
  const limit = limitParam ? parseInt(limitParam, 10) : void 0;
7736
7824
  const effectiveLimit = limit && !Number.isNaN(limit) && limit > 0 ? limit : void 0;
7737
7825
  const messages = getMessages(accountId, jid, effectiveLimit);
7738
- console.error(`${TAG21} messages account=${accountId} jid=${jid} limit=${effectiveLimit ?? "all"} returned=${messages.length}`);
7826
+ const storeKeyFound = listConversationJids(accountId).length > 0;
7827
+ console.error(`${TAG21} messages account=${accountId} jid=${jid} storeKeyFound=${storeKeyFound} limit=${effectiveLimit ?? "all"} returned=${messages.length}`);
7739
7828
  return c.json({ messages });
7740
7829
  } catch (err) {
7741
7830
  console.error(`${TAG21} messages error: ${String(err)}`);
@@ -7748,6 +7837,8 @@ app2.get("/conversation-graph-state", async (c) => {
7748
7837
  const jid = c.req.query("jid");
7749
7838
  const accountIdQuery = c.req.query("accountId");
7750
7839
  const t0 = Date.now();
7840
+ const denial = callerScopeDenial(c, validateAccountId(accountIdQuery ?? null));
7841
+ if (denial) return denial;
7751
7842
  if (!directCacheKey && !jid) {
7752
7843
  const requestedAccountId = validateAccountId(accountIdQuery ?? null);
7753
7844
  const projection2 = projectionFor(requestedAccountId);
@@ -8616,6 +8707,18 @@ function pickActivity(entries, grown, nowMs, concurrencyWindowMs) {
8616
8707
  return { hex: newest.hex, lastEmitAt: newest.mtimeMs, count };
8617
8708
  }
8618
8709
 
8710
+ // app/admin-types.ts
8711
+ var ACCEPT_MIME = "image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,application/zip,application/x-zip-compressed,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.text,text/rtf,application/rtf,audio/ogg,audio/opus,audio/mp4,audio/x-m4a,audio/mpeg,audio/webm,audio/wav,video/mp4,.docx,.odt,.rtf,.opus,.ogg,.m4a,.mp4,.mp3,.wav,.webm";
8712
+ var SUPPORTED_MIME_SET = new Set(ACCEPT_MIME.split(",").filter((t) => !t.startsWith(".")));
8713
+ var MAX_ATTACHMENTS = 5;
8714
+ var MAX_FILE_BYTES = 50 * 1024 * 1024;
8715
+
8716
+ // app/lib/audio-attachment-mime.ts
8717
+ function isMimeAdmitted(mimeType, supportedSet) {
8718
+ const bare = mimeType.split(";")[0].trim().toLowerCase();
8719
+ return supportedSet.has(bare);
8720
+ }
8721
+
8619
8722
  // server/routes/whatsapp-reader.ts
8620
8723
  var app4 = new Hono();
8621
8724
  app4.get("/conversations", requireAdminSession, async (c) => {
@@ -9093,7 +9196,8 @@ app4.get("/store-stream", requireAdminSession, (c) => {
9093
9196
  text: r.body,
9094
9197
  ts: r.dateSent,
9095
9198
  fromMe: r.fromMe,
9096
- senderName: r.senderName
9199
+ senderName: r.senderName,
9200
+ origin: r.origin
9097
9201
  });
9098
9202
  const readable = new ReadableStream({
9099
9203
  start(controller) {
@@ -9186,6 +9290,167 @@ data: ${JSON.stringify(turn)}
9186
9290
  headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" }
9187
9291
  });
9188
9292
  });
9293
+ var MANUAL_TAG = "[wa-manual-send]";
9294
+ function mediaTypeForMime(mime) {
9295
+ if (mime.startsWith("image/")) return "image";
9296
+ if (mime.startsWith("audio/")) return "audio";
9297
+ if (mime.startsWith("video/")) return "video";
9298
+ return null;
9299
+ }
9300
+ app4.post("/reply", requireAdminSession, async (c) => {
9301
+ const sendId = process.hrtime.bigint().toString(36).slice(-8);
9302
+ const t0 = Date.now();
9303
+ const exit = (outcome) => console.log(`${MANUAL_TAG} op=exit sendId=${sendId} ranMs=${Date.now() - t0} outcome=${outcome}`);
9304
+ try {
9305
+ const ct = c.req.header("content-type") ?? "";
9306
+ let accountIdRaw;
9307
+ let remoteJid;
9308
+ let text;
9309
+ let files = [];
9310
+ if (ct.includes("multipart/form-data")) {
9311
+ const form = await c.req.formData();
9312
+ accountIdRaw = form.get("accountId")?.toString();
9313
+ remoteJid = form.get("remoteJid")?.toString();
9314
+ const t = form.get("text")?.toString();
9315
+ text = t && t.trim().length ? t : void 0;
9316
+ files = form.getAll("files").filter((f) => f instanceof File);
9317
+ } else {
9318
+ const body = await c.req.json().catch(() => ({}));
9319
+ accountIdRaw = typeof body.accountId === "string" ? body.accountId : void 0;
9320
+ remoteJid = typeof body.remoteJid === "string" ? body.remoteJid : void 0;
9321
+ text = typeof body.text === "string" && body.text.trim().length ? body.text : void 0;
9322
+ }
9323
+ console.log(`${MANUAL_TAG} op=request sendId=${sendId} accountId=${accountIdRaw ?? ""} remoteJid=${remoteJid ?? ""} textLen=${text?.length ?? 0} fileCount=${files.length}`);
9324
+ if (!accountIdRaw || !remoteJid) {
9325
+ exit("rejected");
9326
+ return c.json({ error: "accountId and remoteJid are required" }, 400);
9327
+ }
9328
+ if (!text && files.length === 0) {
9329
+ exit("rejected");
9330
+ return c.json({ error: "nothing to send: provide text or attachments" }, 400);
9331
+ }
9332
+ if (files.length > MAX_ATTACHMENTS) {
9333
+ exit("rejected");
9334
+ return c.json({ error: `at most ${MAX_ATTACHMENTS} attachments` }, 400);
9335
+ }
9336
+ let accountId;
9337
+ try {
9338
+ accountId = validateAccountId(accountIdRaw);
9339
+ } catch {
9340
+ exit("rejected");
9341
+ return c.json({ error: "invalid accountId" }, 400);
9342
+ }
9343
+ const validAccount = isValidAccountId(accountId);
9344
+ console.log(`${MANUAL_TAG} op=scope sendId=${sendId} accountId=${accountId} validAccount=${validAccount}`);
9345
+ if (!validAccount) {
9346
+ exit("rejected");
9347
+ return c.json({ error: "unknown account" }, 400);
9348
+ }
9349
+ if (isGroupJid(remoteJid)) {
9350
+ console.log(`${MANUAL_TAG} op=reject sendId=${sendId} reason=group-send-blocked`);
9351
+ exit("rejected");
9352
+ return c.json({ error: "group conversations are read-only", reason: "group-send-blocked" }, 403);
9353
+ }
9354
+ if (!isUserJid(remoteJid)) {
9355
+ exit("rejected");
9356
+ return c.json({ error: "invalid remoteJid" }, 400);
9357
+ }
9358
+ const convo = readConversation(accountId, remoteJid);
9359
+ const hasConversation = convo.length > 0;
9360
+ console.log(`${MANUAL_TAG} op=guard sendId=${sendId} remoteJid=${remoteJid} hasConversation=${hasConversation}`);
9361
+ if (!hasConversation) {
9362
+ console.log(`${MANUAL_TAG} op=reject sendId=${sendId} reason=no-existing-conversation`);
9363
+ exit("rejected");
9364
+ return c.json({ error: "no existing conversation with this contact", reason: "no-existing-conversation" }, 403);
9365
+ }
9366
+ const template = convo[convo.length - 1];
9367
+ for (const f of files) {
9368
+ if (!isMimeAdmitted(f.type, SUPPORTED_MIME_SET)) {
9369
+ exit("rejected");
9370
+ return c.json({ error: `unsupported file type: ${f.type}` }, 400);
9371
+ }
9372
+ if (f.size > MAX_FILE_BYTES) {
9373
+ exit("rejected");
9374
+ return c.json({ error: `"${f.name}" exceeds the 50 MB limit` }, 400);
9375
+ }
9376
+ }
9377
+ const res = resolveSocket(accountId);
9378
+ if (!res.ok) {
9379
+ console.log(`${MANUAL_TAG} op=socket sendId=${sendId} accountId=${accountId} result=${res.reason} presentKeys=${res.presentKeys.join(",") || "none"}`);
9380
+ exit("error");
9381
+ if (res.reason === "key-miss") return c.json({ error: `No WhatsApp socket is registered for account "${accountId}" (present: ${res.presentKeys.join(", ") || "none"}). This is an account-keying mismatch, not a dropped connection.` }, 503);
9382
+ return c.json({ error: `WhatsApp account "${accountId}" is registered but its socket is disconnected.` }, 503);
9383
+ }
9384
+ console.log(`${MANUAL_TAG} op=socket sendId=${sendId} accountId=${accountId} result=ok socketAccountId=${res.accountId}`);
9385
+ const record = (waMessageId, body) => {
9386
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
9387
+ const rec = {
9388
+ messageId: `whatsapp-live:${res.accountId}:${remoteJid}:${waMessageId}`,
9389
+ sessionId: template.sessionId,
9390
+ dateSent: nowIso,
9391
+ body,
9392
+ fromMe: true,
9393
+ senderTelephone: template.fromMe ? template.senderTelephone : "",
9394
+ senderName: null,
9395
+ remoteJid,
9396
+ msgKeyId: waMessageId,
9397
+ quotedId: null,
9398
+ quotedSender: null,
9399
+ scope: template.scope,
9400
+ origin: "operator-manual",
9401
+ createdAt: nowIso
9402
+ };
9403
+ appendMessage(accountId, rec);
9404
+ const present = readConversation(accountId, remoteJid).some((r) => r.messageId === rec.messageId);
9405
+ console.log(`${MANUAL_TAG} op=recorded sendId=${sendId} waMessageId=${waMessageId} present=${present}`);
9406
+ };
9407
+ let sent = 0;
9408
+ if (text) {
9409
+ const r = await sendTextMessage(res.sock, remoteJid, text, { accountId: res.accountId });
9410
+ if (!r.success) {
9411
+ console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=text error=${r.error ?? ""}`);
9412
+ exit("error");
9413
+ return c.json({ error: r.error ?? "send failed" }, 500);
9414
+ }
9415
+ console.log(`${MANUAL_TAG} op=sent sendId=${sendId} kind=text waMessageId=${r.messageId ?? ""}`);
9416
+ if (r.messageId) record(r.messageId, text);
9417
+ sent++;
9418
+ }
9419
+ for (let i = 0; i < files.length; i++) {
9420
+ const stored = await storeAttachment(accountId, files[i]);
9421
+ console.log(`${MANUAL_TAG} op=staged sendId=${sendId} idx=${i} bytes=${stored.sizeBytes} mime=${stored.mimeType}`);
9422
+ const kind = mediaTypeForMime(stored.mimeType);
9423
+ let mid;
9424
+ if (kind) {
9425
+ const buffer = Buffer.from(await files[i].arrayBuffer());
9426
+ const r = await sendMediaMessage(res.sock, remoteJid, { type: kind, buffer, mimetype: stored.mimeType, filename: stored.filename, ptt: kind === "audio" }, { accountId: res.accountId });
9427
+ if (!r.success) {
9428
+ console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=${kind} idx=${i} error=${r.error ?? ""}`);
9429
+ exit("error");
9430
+ return c.json({ error: r.error ?? "media send failed" }, 500);
9431
+ }
9432
+ mid = r.messageId;
9433
+ } else {
9434
+ const r = await sendWhatsAppDocument({ to: remoteJid, filePath: stored.storagePath, accountId: res.accountId, maxyAccountId: accountId, platformRoot: PLATFORM_ROOT });
9435
+ if (!r.ok) {
9436
+ console.log(`${MANUAL_TAG} op=send-fail sendId=${sendId} kind=document idx=${i} error=${r.error}`);
9437
+ exit("error");
9438
+ return c.json({ error: r.error }, r.status);
9439
+ }
9440
+ mid = r.messageId;
9441
+ }
9442
+ console.log(`${MANUAL_TAG} op=sent sendId=${sendId} kind=${kind ?? "document"} idx=${i} waMessageId=${mid ?? ""}`);
9443
+ if (mid) record(mid, `[sent ${stored.filename}]`);
9444
+ sent++;
9445
+ }
9446
+ exit("delivered");
9447
+ return c.json({ success: true, sent });
9448
+ } catch (err) {
9449
+ console.error(`${MANUAL_TAG} op=error sendId=${sendId} error=${String(err)}`);
9450
+ exit("error");
9451
+ return c.json({ error: String(err) }, 500);
9452
+ }
9453
+ });
9189
9454
  var whatsapp_reader_default = app4;
9190
9455
 
9191
9456
  // server/routes/public-reader.ts
@@ -9942,8 +10207,8 @@ async function reapplyLeversViaManager() {
9942
10207
  var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
9943
10208
  var sendSeq = 0;
9944
10209
  function createWebchatRoutes(deps) {
9945
- const app57 = new Hono();
9946
- app57.post("/send", requireAdminSession, async (c) => {
10210
+ const app61 = new Hono();
10211
+ app61.post("/send", requireAdminSession, async (c) => {
9947
10212
  let accountId;
9948
10213
  try {
9949
10214
  accountId = resolvePlatformAccountId();
@@ -10143,7 +10408,7 @@ ${note}` : note;
10143
10408
  if (turnTimer.unref) turnTimer.unref();
10144
10409
  return c.json({ ok: true });
10145
10410
  });
10146
- app57.post("/interrupt", requireAdminSession, async (c) => {
10411
+ app61.post("/interrupt", requireAdminSession, async (c) => {
10147
10412
  const cacheKey = c.get("cacheKey");
10148
10413
  const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
10149
10414
  const primaryUserId = resolvePrimaryAdminUserId();
@@ -10171,7 +10436,7 @@ ${note}` : note;
10171
10436
  }
10172
10437
  return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
10173
10438
  });
10174
- app57.post("/settings", requireAdminSession, async (c) => {
10439
+ app61.post("/settings", requireAdminSession, async (c) => {
10175
10440
  const body = await c.req.json().catch(() => null);
10176
10441
  const op = body?.op;
10177
10442
  const value = body?.value;
@@ -10211,7 +10476,7 @@ ${note}` : note;
10211
10476
  console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
10212
10477
  return c.json({ ok: true, settingsApplied });
10213
10478
  });
10214
- app57.get("/session", requireAdminSession, async (c) => {
10479
+ app61.get("/session", requireAdminSession, async (c) => {
10215
10480
  let accountId;
10216
10481
  try {
10217
10482
  accountId = resolvePlatformAccountId();
@@ -10289,7 +10554,7 @@ ${note}` : note;
10289
10554
  const indicators = await fetchComposerIndicators(sessionId);
10290
10555
  return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
10291
10556
  });
10292
- app57.post("/permission-verdict", requireAdminSession, async (c) => {
10557
+ app61.post("/permission-verdict", requireAdminSession, async (c) => {
10293
10558
  const body = await c.req.json().catch(() => null);
10294
10559
  const sessionId = body?.sessionId;
10295
10560
  const requestId = body?.request_id;
@@ -10306,7 +10571,7 @@ ${note}` : note;
10306
10571
  const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
10307
10572
  return c.json({ ok });
10308
10573
  });
10309
- return app57;
10574
+ return app61;
10310
10575
  }
10311
10576
 
10312
10577
  // server/routes/webchat-greeting.ts
@@ -13343,18 +13608,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
13343
13608
  ]);
13344
13609
  var app20 = new Hono();
13345
13610
  app20.post("/", async (c) => {
13346
- const TAG39 = "[admin:events]";
13611
+ const TAG44 = "[admin:events]";
13347
13612
  let body;
13348
13613
  try {
13349
13614
  body = await c.req.json();
13350
13615
  } catch (err) {
13351
13616
  const detail = err instanceof Error ? err.message : String(err);
13352
- console.error(`${TAG39} reject reason=body-not-json detail=${detail}`);
13617
+ console.error(`${TAG44} reject reason=body-not-json detail=${detail}`);
13353
13618
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
13354
13619
  }
13355
13620
  const event = typeof body.event === "string" ? body.event : "";
13356
13621
  if (!ALLOWED_EVENTS.has(event)) {
13357
- console.error(`${TAG39} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
13622
+ console.error(`${TAG44} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
13358
13623
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
13359
13624
  }
13360
13625
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -19289,52 +19554,307 @@ app45.get("/booking-link", requireAdminSession, (c) => {
19289
19554
  });
19290
19555
  var calendar_default = app45;
19291
19556
 
19292
- // server/routes/admin/index.ts
19557
+ // app/lib/time-entry-format.ts
19558
+ function secondsBetween(startIso, endIso) {
19559
+ const s = Date.parse(startIso);
19560
+ const e = Date.parse(endIso);
19561
+ if (!Number.isFinite(s) || !Number.isFinite(e)) return 0;
19562
+ return Math.max(0, Math.round((e - s) / 1e3));
19563
+ }
19564
+ function toNum(v) {
19565
+ if (v == null) return 0;
19566
+ if (typeof v === "number") return v;
19567
+ if (typeof v === "object" && typeof v.toNumber === "function") {
19568
+ return v.toNumber();
19569
+ }
19570
+ const n = Number(v);
19571
+ return Number.isFinite(n) ? n : 0;
19572
+ }
19573
+
19574
+ // server/routes/admin/tasks-list.ts
19575
+ var TAG33 = "[task-timer]";
19576
+ var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
19577
+ var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
19293
19578
  var app46 = new Hono();
19294
- app46.route("/session", session_default);
19295
- app46.route("/accounts", accounts_default);
19296
- app46.route("/logs", logs_default);
19297
- app46.route("/claude-info", claude_info_default);
19298
- app46.route("/attachment", attachment_default);
19299
- app46.route("/agents", agents_default);
19300
- app46.route("/sessions", sessions_default);
19301
- app46.route("/claude-sessions", claude_sessions_default);
19302
- app46.route("/log-ingest", log_ingest_default);
19303
- app46.route("/events", events_default);
19304
- app46.route("/files", files_default);
19305
- app46.route("/graph-search", graph_search_default);
19306
- app46.route("/graph-subgraph", graph_subgraph_default);
19307
- app46.route("/graph-delete", graph_delete_default);
19308
- app46.route("/graph-restore", graph_restore_default);
19309
- app46.route("/graph-labels-in-graph", graph_labels_in_graph_default);
19310
- app46.route("/graph-default-view", graph_default_view_default);
19311
- app46.route("/sidebar-artefacts", sidebar_artefacts_default);
19312
- app46.route("/sidebar-sessions", sidebar_sessions_default);
19313
- app46.route("/session-delete", session_delete_default);
19314
- app46.route("/session-stop", session_stop_default);
19315
- app46.route("/session-archive", session_archive_default);
19316
- app46.route("/session-rename", session_rename_default);
19317
- app46.route("/session-usage", session_usage_default);
19318
- app46.route("/browser", browser_default);
19319
- app46.route("/session-rc-spawn", session_rc_spawn_default);
19320
- app46.route("/session-reseat", session_reseat_default);
19321
- app46.route("/system-stats", system_stats_default);
19322
- app46.route("/health-brand", health_default2);
19323
- app46.route("/linkedin-ingest", linkedin_ingest_default);
19324
- app46.route("/post-turn-context", post_turn_context_default);
19325
- app46.route("/public-session-context", public_session_context_default);
19326
- app46.route("/public-session-exit", public_session_exit_default);
19327
- app46.route("/access-session-evict", access_session_evict_default);
19328
- app46.route("/enrol-person", enrol_person_default);
19329
- app46.route("/calendar", calendar_default);
19330
- var admin_default = app46;
19579
+ app46.get("/", requireAdminSession, async (c) => {
19580
+ const cacheKey = c.var.cacheKey;
19581
+ const accountId = getAccountIdForSession(cacheKey);
19582
+ if (!accountId) {
19583
+ console.error(`${TAG33} op=list auth-rejected reason="no account for session"`);
19584
+ return c.json({ error: "Account not found for session" }, 401);
19585
+ }
19586
+ const session = getSession();
19587
+ try {
19588
+ const result = await session.run(
19589
+ `MATCH (t:Task {accountId: $accountId})
19590
+ OPTIONAL MATCH (te:TimeEntry {taskId: t.taskId, accountId: $accountId})
19591
+ WHERE te.endedAt IS NULL
19592
+ WITH t, te ORDER BY te.startedAt
19593
+ WITH t, head(collect(te)) AS openTe
19594
+ RETURN t.taskId AS taskId, t.name AS name, t.clientName AS clientName,
19595
+ t.propertyAddress AS propertyAddress, t.fee AS fee, t.status AS status,
19596
+ coalesce(t.secondsLogged, 0) AS secondsLogged,
19597
+ openTe.startedAt AS runningStartedAt
19598
+ ORDER BY t.createdAt DESC`,
19599
+ { accountId }
19600
+ );
19601
+ const open = [];
19602
+ const completed = [];
19603
+ for (const rec of result.records) {
19604
+ const status = rec.get("status") ?? "pending";
19605
+ const runningStartedAt = rec.get("runningStartedAt") ?? null;
19606
+ const fee = rec.get("fee");
19607
+ const row = {
19608
+ taskId: rec.get("taskId"),
19609
+ name: rec.get("name") ?? "",
19610
+ clientName: rec.get("clientName") ?? null,
19611
+ propertyAddress: rec.get("propertyAddress") ?? null,
19612
+ fee: fee == null ? null : toNum(fee),
19613
+ status,
19614
+ secondsLogged: toNum(rec.get("secondsLogged")),
19615
+ running: runningStartedAt !== null,
19616
+ runningStartedAt
19617
+ };
19618
+ if (COMPLETED.has(status)) completed.push(row);
19619
+ else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
19620
+ }
19621
+ console.log(`${TAG33} op=list account=${accountId} open=${open.length} completed=${completed.length}`);
19622
+ return c.json({ open, completed });
19623
+ } catch (err) {
19624
+ console.error(`${TAG33} op=list error="${err instanceof Error ? err.message : String(err)}"`);
19625
+ return c.json({ error: "tasks-list-failed" }, 500);
19626
+ } finally {
19627
+ await session.close();
19628
+ }
19629
+ });
19630
+ var tasks_list_default = app46;
19631
+
19632
+ // server/routes/admin/task-timer-start.ts
19633
+ import { randomUUID as randomUUID13 } from "crypto";
19634
+ import neo4j5 from "neo4j-driver";
19635
+ var TAG34 = "[task-timer]";
19636
+ var app47 = new Hono();
19637
+ app47.post("/", requireAdminSession, async (c) => {
19638
+ const cacheKey = c.var.cacheKey;
19639
+ const accountId = getAccountIdForSession(cacheKey);
19640
+ if (!accountId) return c.json({ error: "Account not found for session" }, 401);
19641
+ let body;
19642
+ try {
19643
+ body = await c.req.json();
19644
+ } catch {
19645
+ return c.json({ error: "invalid-json" }, 400);
19646
+ }
19647
+ const taskId = typeof body.taskId === "string" ? body.taskId : "";
19648
+ if (!taskId) return c.json({ error: "taskId required" }, 400);
19649
+ const now = (/* @__PURE__ */ new Date()).toISOString();
19650
+ const session = getSession();
19651
+ try {
19652
+ const target = await session.run(
19653
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId}) RETURN t.taskId AS taskId LIMIT 1`,
19654
+ { taskId, accountId }
19655
+ );
19656
+ if (target.records.length === 0) {
19657
+ console.error(`${TAG34} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
19658
+ return c.json({ error: "task-not-found" }, 404);
19659
+ }
19660
+ const open = await session.run(
19661
+ `MATCH (te:TimeEntry {accountId: $accountId}) WHERE te.endedAt IS NULL
19662
+ RETURN te.entryId AS entryId, te.taskId AS taskId, te.startedAt AS startedAt
19663
+ ORDER BY te.startedAt LIMIT 1`,
19664
+ { accountId }
19665
+ );
19666
+ const priorEntryId = open.records[0]?.get("entryId");
19667
+ const priorTaskId = open.records[0]?.get("taskId");
19668
+ const priorStartedAt = open.records[0]?.get("startedAt");
19669
+ console.log(`${TAG34} op=start taskId=${taskId} accountId=${accountId} priorOpen=${priorTaskId ?? "none"}`);
19670
+ if (priorEntryId && priorTaskId === taskId) {
19671
+ return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
19672
+ }
19673
+ if (priorEntryId && priorStartedAt && priorTaskId) {
19674
+ const seconds = secondsBetween(priorStartedAt, now);
19675
+ await session.run(
19676
+ `MATCH (te:TimeEntry {entryId: $priorEntryId}) WHERE te.endedAt IS NULL
19677
+ SET te.endedAt = $now, te.seconds = $seconds
19678
+ WITH te
19679
+ MATCH (t:Task {taskId: $priorTaskId, accountId: $accountId})
19680
+ SET t.secondsLogged = coalesce(t.secondsLogged, 0) + $seconds`,
19681
+ { priorEntryId, priorTaskId, accountId, now, seconds: neo4j5.int(seconds) }
19682
+ );
19683
+ console.log(`${TAG34} op=autostop taskId=${priorTaskId} entryId=${priorEntryId} seconds=${seconds}`);
19684
+ }
19685
+ const entryId = randomUUID13();
19686
+ await session.run(
19687
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19688
+ CREATE (te:TimeEntry {entryId: $entryId, taskId: $taskId, accountId: $accountId, startedAt: $now, endedAt: null})
19689
+ CREATE (te)-[:LOGGED_AGAINST]->(t)`,
19690
+ { taskId, accountId, entryId, now }
19691
+ );
19692
+ console.log(`${TAG34} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
19693
+ return c.json({ ok: true, running: true, entryId, startedAt: now });
19694
+ } catch (err) {
19695
+ console.error(`${TAG34} op=start error="${err instanceof Error ? err.message : String(err)}"`);
19696
+ return c.json({ error: "task-timer-start-failed" }, 500);
19697
+ } finally {
19698
+ await session.close();
19699
+ }
19700
+ });
19701
+ var task_timer_start_default = app47;
19702
+
19703
+ // server/routes/admin/task-timer-stop.ts
19704
+ import neo4j6 from "neo4j-driver";
19705
+ var TAG35 = "[task-timer]";
19706
+ var app48 = new Hono();
19707
+ app48.post("/", requireAdminSession, async (c) => {
19708
+ const cacheKey = c.var.cacheKey;
19709
+ const accountId = getAccountIdForSession(cacheKey);
19710
+ if (!accountId) return c.json({ error: "Account not found for session" }, 401);
19711
+ let body;
19712
+ try {
19713
+ body = await c.req.json();
19714
+ } catch {
19715
+ return c.json({ error: "invalid-json" }, 400);
19716
+ }
19717
+ const taskId = typeof body.taskId === "string" ? body.taskId : "";
19718
+ if (!taskId) return c.json({ error: "taskId required" }, 400);
19719
+ const now = (/* @__PURE__ */ new Date()).toISOString();
19720
+ const session = getSession();
19721
+ try {
19722
+ const open = await session.run(
19723
+ `MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NULL
19724
+ RETURN te.entryId AS entryId, te.startedAt AS startedAt
19725
+ ORDER BY te.startedAt LIMIT 1`,
19726
+ { taskId, accountId }
19727
+ );
19728
+ const entryId = open.records[0]?.get("entryId");
19729
+ const startedAt = open.records[0]?.get("startedAt");
19730
+ if (!entryId || !startedAt) {
19731
+ const cur = await session.run(
19732
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19733
+ RETURN coalesce(t.secondsLogged, 0) AS secondsLogged`,
19734
+ { taskId, accountId }
19735
+ );
19736
+ const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
19737
+ console.log(`${TAG35} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
19738
+ return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
19739
+ }
19740
+ const seconds = secondsBetween(startedAt, now);
19741
+ await session.run(
19742
+ `MATCH (te:TimeEntry {entryId: $entryId}) WHERE te.endedAt IS NULL
19743
+ SET te.endedAt = $now, te.seconds = $seconds
19744
+ WITH te
19745
+ MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19746
+ SET t.secondsLogged = coalesce(t.secondsLogged, 0) + $seconds`,
19747
+ { entryId, taskId, accountId, now, seconds: neo4j6.int(seconds) }
19748
+ );
19749
+ const verify = await session.run(
19750
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19751
+ OPTIONAL MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NOT NULL
19752
+ RETURN coalesce(sum(te.seconds), 0) AS sumEntries, coalesce(t.secondsLogged, 0) AS secondsLogged`,
19753
+ { taskId, accountId }
19754
+ );
19755
+ const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
19756
+ const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
19757
+ console.log(`${TAG35} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
19758
+ console.log(`${TAG35} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} secondsLogged=${secondsLogged}`);
19759
+ return c.json({ ok: true, running: false, seconds, secondsLogged });
19760
+ } catch (err) {
19761
+ console.error(`${TAG35} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
19762
+ return c.json({ error: "task-timer-stop-failed" }, 500);
19763
+ } finally {
19764
+ await session.close();
19765
+ }
19766
+ });
19767
+ var task_timer_stop_default = app48;
19768
+
19769
+ // server/routes/admin/task-complete.ts
19770
+ var TAG36 = "[task-timer]";
19771
+ var app49 = new Hono();
19772
+ app49.post("/", requireAdminSession, async (c) => {
19773
+ const cacheKey = c.var.cacheKey;
19774
+ const accountId = getAccountIdForSession(cacheKey);
19775
+ if (!accountId) return c.json({ error: "Account not found for session" }, 401);
19776
+ let body;
19777
+ try {
19778
+ body = await c.req.json();
19779
+ } catch {
19780
+ return c.json({ error: "invalid-json" }, 400);
19781
+ }
19782
+ const taskId = typeof body.taskId === "string" ? body.taskId : "";
19783
+ if (!taskId) return c.json({ error: "taskId required" }, 400);
19784
+ const now = (/* @__PURE__ */ new Date()).toISOString();
19785
+ const session = getSession();
19786
+ try {
19787
+ const result = await session.run(
19788
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19789
+ SET t.status = 'completed', t.updatedAt = $now
19790
+ RETURN t.taskId AS taskId, coalesce(t.secondsLogged, 0) AS secondsLogged`,
19791
+ { taskId, accountId, now }
19792
+ );
19793
+ if (result.records.length === 0) {
19794
+ return c.json({ error: "task-not-found" }, 404);
19795
+ }
19796
+ const secondsLogged = toNum(result.records[0].get("secondsLogged"));
19797
+ console.log(`${TAG36} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
19798
+ return c.json({ ok: true, status: "completed", secondsLogged });
19799
+ } catch (err) {
19800
+ console.error(`${TAG36} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
19801
+ return c.json({ error: "task-complete-failed" }, 500);
19802
+ } finally {
19803
+ await session.close();
19804
+ }
19805
+ });
19806
+ var task_complete_default = app49;
19807
+
19808
+ // server/routes/admin/index.ts
19809
+ var app50 = new Hono();
19810
+ app50.route("/session", session_default);
19811
+ app50.route("/accounts", accounts_default);
19812
+ app50.route("/logs", logs_default);
19813
+ app50.route("/claude-info", claude_info_default);
19814
+ app50.route("/attachment", attachment_default);
19815
+ app50.route("/agents", agents_default);
19816
+ app50.route("/sessions", sessions_default);
19817
+ app50.route("/claude-sessions", claude_sessions_default);
19818
+ app50.route("/log-ingest", log_ingest_default);
19819
+ app50.route("/events", events_default);
19820
+ app50.route("/files", files_default);
19821
+ app50.route("/graph-search", graph_search_default);
19822
+ app50.route("/graph-subgraph", graph_subgraph_default);
19823
+ app50.route("/graph-delete", graph_delete_default);
19824
+ app50.route("/graph-restore", graph_restore_default);
19825
+ app50.route("/graph-labels-in-graph", graph_labels_in_graph_default);
19826
+ app50.route("/graph-default-view", graph_default_view_default);
19827
+ app50.route("/sidebar-artefacts", sidebar_artefacts_default);
19828
+ app50.route("/sidebar-sessions", sidebar_sessions_default);
19829
+ app50.route("/session-delete", session_delete_default);
19830
+ app50.route("/session-stop", session_stop_default);
19831
+ app50.route("/session-archive", session_archive_default);
19832
+ app50.route("/session-rename", session_rename_default);
19833
+ app50.route("/session-usage", session_usage_default);
19834
+ app50.route("/browser", browser_default);
19835
+ app50.route("/session-rc-spawn", session_rc_spawn_default);
19836
+ app50.route("/session-reseat", session_reseat_default);
19837
+ app50.route("/system-stats", system_stats_default);
19838
+ app50.route("/health-brand", health_default2);
19839
+ app50.route("/linkedin-ingest", linkedin_ingest_default);
19840
+ app50.route("/post-turn-context", post_turn_context_default);
19841
+ app50.route("/public-session-context", public_session_context_default);
19842
+ app50.route("/public-session-exit", public_session_exit_default);
19843
+ app50.route("/access-session-evict", access_session_evict_default);
19844
+ app50.route("/enrol-person", enrol_person_default);
19845
+ app50.route("/calendar", calendar_default);
19846
+ app50.route("/tasks-list", tasks_list_default);
19847
+ app50.route("/task-timer-start", task_timer_start_default);
19848
+ app50.route("/task-timer-stop", task_timer_stop_default);
19849
+ app50.route("/task-complete", task_complete_default);
19850
+ var admin_default = app50;
19331
19851
 
19332
19852
  // server/routes/access/verify-token.ts
19333
- var TAG33 = "[access-verify]";
19853
+ var TAG37 = "[access-verify]";
19334
19854
  var MINT_TAG = "[access-session-mint]";
19335
19855
  var COOKIE_NAME = "__access_session";
19336
- var app47 = new Hono();
19337
- app47.post("/", async (c) => {
19856
+ var app51 = new Hono();
19857
+ app51.post("/", async (c) => {
19338
19858
  const ip = c.var.clientIp || "unknown";
19339
19859
  let body;
19340
19860
  try {
@@ -19349,39 +19869,39 @@ app47.post("/", async (c) => {
19349
19869
  }
19350
19870
  const rateMsg = checkAccessRateLimit(ip, agentSlug);
19351
19871
  if (rateMsg) {
19352
- console.error(`${TAG33} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
19872
+ console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
19353
19873
  return c.json({ error: rateMsg }, 429);
19354
19874
  }
19355
19875
  const grant = await findGrantByMagicToken(token);
19356
19876
  if (!grant) {
19357
19877
  recordAccessFailedAttempt(ip, agentSlug);
19358
- console.error(`${TAG33} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
19878
+ console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
19359
19879
  return c.json({ error: "invalid-or-expired-link" }, 401);
19360
19880
  }
19361
19881
  if (grant.agentSlug !== agentSlug) {
19362
19882
  recordAccessFailedAttempt(ip, agentSlug);
19363
19883
  console.error(
19364
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
19884
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
19365
19885
  );
19366
19886
  return c.json({ error: "invalid-or-expired-link" }, 401);
19367
19887
  }
19368
19888
  if (grant.status === "expired" || grant.status === "revoked") {
19369
19889
  recordAccessFailedAttempt(ip, agentSlug);
19370
19890
  console.error(
19371
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
19891
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
19372
19892
  );
19373
19893
  return c.json({ error: "access-no-longer-valid" }, 401);
19374
19894
  }
19375
19895
  if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
19376
19896
  recordAccessFailedAttempt(ip, agentSlug);
19377
19897
  console.error(
19378
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
19898
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
19379
19899
  );
19380
19900
  return c.json({ error: "access-no-longer-valid" }, 401);
19381
19901
  }
19382
19902
  if (!grant.sliceToken) {
19383
19903
  console.error(
19384
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
19904
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
19385
19905
  );
19386
19906
  return c.json({ error: "grant-misconfigured" }, 500);
19387
19907
  }
@@ -19397,12 +19917,12 @@ app47.post("/", async (c) => {
19397
19917
  await consumeMagicTokenAndActivate(grant.grantId);
19398
19918
  } catch (err) {
19399
19919
  console.error(
19400
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
19920
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
19401
19921
  );
19402
19922
  return c.json({ error: "verification-failed" }, 500);
19403
19923
  }
19404
19924
  clearAccessRateLimit(ip, agentSlug);
19405
- console.log(`${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
19925
+ console.log(`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
19406
19926
  console.log(
19407
19927
  `${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
19408
19928
  );
@@ -19416,7 +19936,7 @@ app47.post("/", async (c) => {
19416
19936
  displayName: grant.displayName
19417
19937
  });
19418
19938
  });
19419
- var verify_token_default = app47;
19939
+ var verify_token_default = app51;
19420
19940
 
19421
19941
  // app/lib/access-email.ts
19422
19942
  import { spawn as spawn2 } from "child_process";
@@ -19478,10 +19998,10 @@ async function sendMagicLinkEmail(payload) {
19478
19998
  }
19479
19999
 
19480
20000
  // server/routes/access/request-magic-link.ts
19481
- var TAG34 = "[access-request-link]";
19482
- var app48 = new Hono();
20001
+ var TAG38 = "[access-request-link]";
20002
+ var app52 = new Hono();
19483
20003
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
19484
- app48.post("/", async (c) => {
20004
+ app52.post("/", async (c) => {
19485
20005
  let body;
19486
20006
  try {
19487
20007
  body = await c.req.json();
@@ -19495,18 +20015,18 @@ app48.post("/", async (c) => {
19495
20015
  }
19496
20016
  const rateMsg = checkRequestLinkRateLimit(contactValue);
19497
20017
  if (rateMsg) {
19498
- console.error(`${TAG34} contactValue=${maskContact(contactValue)} result=rate-limited`);
20018
+ console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=rate-limited`);
19499
20019
  return c.json({ error: rateMsg }, 429);
19500
20020
  }
19501
20021
  recordRequestLinkAttempt(contactValue);
19502
20022
  const accountId = process.env.ACCOUNT_ID ?? "";
19503
20023
  if (!accountId) {
19504
- console.error(`${TAG34} contactValue=${maskContact(contactValue)} result=no-account-id`);
20024
+ console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=no-account-id`);
19505
20025
  return c.json({ message: VISITOR_MESSAGE }, 200);
19506
20026
  }
19507
20027
  const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
19508
20028
  if (!grant) {
19509
- console.log(`${TAG34} contactValue=${maskContact(contactValue)} result=notfound`);
20029
+ console.log(`${TAG38} contactValue=${maskContact(contactValue)} result=notfound`);
19510
20030
  return c.json({ message: VISITOR_MESSAGE }, 200);
19511
20031
  }
19512
20032
  let token;
@@ -19514,7 +20034,7 @@ app48.post("/", async (c) => {
19514
20034
  token = await generateNewMagicToken(grant.grantId);
19515
20035
  } catch (err) {
19516
20036
  console.error(
19517
- `${TAG34} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
20037
+ `${TAG38} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
19518
20038
  );
19519
20039
  return c.json({ message: VISITOR_MESSAGE }, 200);
19520
20040
  }
@@ -19546,22 +20066,22 @@ app48.post("/", async (c) => {
19546
20066
  });
19547
20067
  if (!sendResult.ok) {
19548
20068
  console.error(
19549
- `${TAG34} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
20069
+ `${TAG38} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
19550
20070
  );
19551
20071
  return c.json({ message: VISITOR_MESSAGE }, 200);
19552
20072
  }
19553
20073
  console.log(
19554
- `${TAG34} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
20074
+ `${TAG38} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
19555
20075
  );
19556
20076
  return c.json({ message: VISITOR_MESSAGE }, 200);
19557
20077
  });
19558
- var request_magic_link_default = app48;
20078
+ var request_magic_link_default = app52;
19559
20079
 
19560
20080
  // server/routes/access/index.ts
19561
- var app49 = new Hono();
19562
- app49.route("/verify-token", verify_token_default);
19563
- app49.route("/request-magic-link", request_magic_link_default);
19564
- var access_default = app49;
20081
+ var app53 = new Hono();
20082
+ app53.route("/verify-token", verify_token_default);
20083
+ app53.route("/request-magic-link", request_magic_link_default);
20084
+ var access_default = app53;
19565
20085
 
19566
20086
  // server/routes/sites.ts
19567
20087
  import { existsSync as existsSync28, readFileSync as readFileSync31, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
@@ -19596,8 +20116,8 @@ function getExt(p) {
19596
20116
  if (idx < p.lastIndexOf("/")) return "";
19597
20117
  return p.slice(idx).toLowerCase();
19598
20118
  }
19599
- var app50 = new Hono();
19600
- app50.get("/:rel{.*}", (c) => {
20119
+ var app54 = new Hono();
20120
+ app54.get("/:rel{.*}", (c) => {
19601
20121
  const reqPath = c.req.path;
19602
20122
  const rawRel = c.req.param("rel") ?? "";
19603
20123
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -19700,7 +20220,7 @@ app50.get("/:rel{.*}", (c) => {
19700
20220
  "X-Content-Type-Options": "nosniff"
19701
20221
  });
19702
20222
  });
19703
- var sites_default = app50;
20223
+ var sites_default = app54;
19704
20224
 
19705
20225
  // app/lib/visitor-token.ts
19706
20226
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
@@ -19800,7 +20320,7 @@ function readBrandConfig() {
19800
20320
  }
19801
20321
 
19802
20322
  // server/routes/visitor-consent.ts
19803
- var app51 = new Hono();
20323
+ var app55 = new Hono();
19804
20324
  var CONSENT_COOKIE_NAME = "mxy_consent";
19805
20325
  var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
19806
20326
  var DEFAULT_CONSENT_COPY = {
@@ -19845,17 +20365,17 @@ function siteSlugFromReferer(referer) {
19845
20365
  return "";
19846
20366
  }
19847
20367
  }
19848
- app51.options("/consent", (c) => {
20368
+ app55.options("/consent", (c) => {
19849
20369
  const origin = getOrigin(c);
19850
20370
  setCorsHeaders(c, origin);
19851
20371
  return c.body(null, 204);
19852
20372
  });
19853
- app51.options("/brand-config", (c) => {
20373
+ app55.options("/brand-config", (c) => {
19854
20374
  const origin = getOrigin(c);
19855
20375
  setCorsHeaders(c, origin);
19856
20376
  return c.body(null, 204);
19857
20377
  });
19858
- app51.post("/consent", async (c) => {
20378
+ app55.post("/consent", async (c) => {
19859
20379
  const origin = getOrigin(c);
19860
20380
  setCorsHeaders(c, origin);
19861
20381
  let raw;
@@ -19895,7 +20415,7 @@ app51.post("/consent", async (c) => {
19895
20415
  console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
19896
20416
  return c.body(null, 204);
19897
20417
  });
19898
- app51.get("/brand-config", (c) => {
20418
+ app55.get("/brand-config", (c) => {
19899
20419
  const origin = getOrigin(c);
19900
20420
  setCorsHeaders(c, origin);
19901
20421
  const brand = readBrandConfig();
@@ -19905,7 +20425,7 @@ app51.get("/brand-config", (c) => {
19905
20425
  c.header("Cache-Control", "public, max-age=300");
19906
20426
  return c.json({ consent: { copy, palette } });
19907
20427
  });
19908
- var visitor_consent_default = app51;
20428
+ var visitor_consent_default = app55;
19909
20429
 
19910
20430
  // server/routes/listings.ts
19911
20431
  function getCookie(headerValue, name) {
@@ -19932,8 +20452,8 @@ function appendConsentParams(pageUrl, token) {
19932
20452
  }
19933
20453
  var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
19934
20454
  var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
19935
- var app52 = new Hono();
19936
- app52.get("/:slug/click", async (c) => {
20455
+ var app56 = new Hono();
20456
+ app56.get("/:slug/click", async (c) => {
19937
20457
  const slug = c.req.param("slug") ?? "";
19938
20458
  const rawSession = c.req.query("session") ?? "";
19939
20459
  const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
@@ -19997,10 +20517,10 @@ app52.get("/:slug/click", async (c) => {
19997
20517
  console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
19998
20518
  return c.redirect(redirectUrl, 302);
19999
20519
  });
20000
- var listings_default = app52;
20520
+ var listings_default = app56;
20001
20521
 
20002
20522
  // server/routes/visitor-event.ts
20003
- var app53 = new Hono();
20523
+ var app57 = new Hono();
20004
20524
  var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
20005
20525
  var buckets = /* @__PURE__ */ new Map();
20006
20526
  var RATE_LIMIT = 60;
@@ -20067,12 +20587,12 @@ function originAllowed(origin, allowlist) {
20067
20587
  return false;
20068
20588
  }
20069
20589
  }
20070
- app53.options("/event", (c) => {
20590
+ app57.options("/event", (c) => {
20071
20591
  const origin = getOrigin2(c);
20072
20592
  setCorsHeaders2(c, origin);
20073
20593
  return c.body(null, 204);
20074
20594
  });
20075
- app53.post("/event", async (c) => {
20595
+ app57.post("/event", async (c) => {
20076
20596
  const origin = getOrigin2(c);
20077
20597
  setCorsHeaders2(c, origin);
20078
20598
  const ua = c.req.header("user-agent") ?? "";
@@ -20277,7 +20797,7 @@ async function writeEvent(opts) {
20277
20797
  );
20278
20798
  }
20279
20799
  }
20280
- var visitor_event_default = app53;
20800
+ var visitor_event_default = app57;
20281
20801
 
20282
20802
  // server/routes/session.ts
20283
20803
  import { resolve as resolve27 } from "path";
@@ -20323,8 +20843,8 @@ function withVisitorCookie(response, visitorId) {
20323
20843
  headers
20324
20844
  });
20325
20845
  }
20326
- var app54 = new Hono();
20327
- app54.post("/", async (c) => {
20846
+ var app58 = new Hono();
20847
+ app58.post("/", async (c) => {
20328
20848
  let body;
20329
20849
  try {
20330
20850
  body = await c.req.json();
@@ -20471,7 +20991,7 @@ app54.post("/", async (c) => {
20471
20991
  newVisitorId
20472
20992
  );
20473
20993
  });
20474
- var session_default2 = app54;
20994
+ var session_default2 = app58;
20475
20995
 
20476
20996
  // server/lib/calendar-slots.ts
20477
20997
  var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
@@ -20554,17 +21074,17 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
20554
21074
  }
20555
21075
 
20556
21076
  // server/routes/calendar-public.ts
20557
- var app55 = new Hono();
21077
+ var app59 = new Hono();
20558
21078
  function setCors(c) {
20559
21079
  c.header("Access-Control-Allow-Origin", "*");
20560
21080
  c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
20561
21081
  c.header("Access-Control-Allow-Headers", "content-type");
20562
21082
  }
20563
- app55.options("/free-busy", (c) => {
21083
+ app59.options("/free-busy", (c) => {
20564
21084
  setCors(c);
20565
21085
  return c.body(null, 204);
20566
21086
  });
20567
- app55.get("/free-busy", async (c) => {
21087
+ app59.get("/free-busy", async (c) => {
20568
21088
  setCors(c);
20569
21089
  const from = c.req.query("from");
20570
21090
  const to = c.req.query("to");
@@ -20606,7 +21126,79 @@ app55.get("/free-busy", async (c) => {
20606
21126
  await session.close();
20607
21127
  }
20608
21128
  });
20609
- var calendar_public_default = app55;
21129
+ var calendar_public_default = app59;
21130
+
21131
+ // app/lib/timeentry-census.ts
21132
+ var TAG39 = "[timeentry-census]";
21133
+ function reconcileTimeEntries(rows, now, horizonMs) {
21134
+ const openEntries = rows.openEntries.length;
21135
+ let oldestOpenAgeMs = 0;
21136
+ const perAccount = /* @__PURE__ */ new Map();
21137
+ for (const e of rows.openEntries) {
21138
+ oldestOpenAgeMs = Math.max(oldestOpenAgeMs, now - e.startedAtMs);
21139
+ perAccount.set(e.accountId, (perAccount.get(e.accountId) ?? 0) + 1);
21140
+ }
21141
+ const maxOpenPerAccount = perAccount.size === 0 ? 0 : Math.max(...perAccount.values());
21142
+ const driftTasks = rows.taskSums.filter((t) => t.secondsLogged !== t.sumEntries).length;
21143
+ const oldestOpenAgeMin = Math.floor(oldestOpenAgeMs / 6e4);
21144
+ const alarm = oldestOpenAgeMs > horizonMs || maxOpenPerAccount > 1 || driftTasks > 0;
21145
+ return { openEntries, oldestOpenAgeMin, maxOpenPerAccount, driftTasks, alarm };
21146
+ }
21147
+ async function runTimeEntryCensusOnce(session, now, horizonMs) {
21148
+ try {
21149
+ const openRes = await session.run(
21150
+ `MATCH (te:TimeEntry) WHERE te.endedAt IS NULL
21151
+ RETURN te.accountId AS accountId, te.startedAt AS startedAt`
21152
+ );
21153
+ const openEntries = openRes.records.map((r) => ({
21154
+ accountId: r.get("accountId") ?? "unknown",
21155
+ startedAtMs: Date.parse(r.get("startedAt") ?? "") || now
21156
+ }));
21157
+ const sumRes = await session.run(
21158
+ `MATCH (t:Task) WHERE t.secondsLogged IS NOT NULL
21159
+ OPTIONAL MATCH (te:TimeEntry {taskId: t.taskId}) WHERE te.endedAt IS NOT NULL
21160
+ RETURN t.taskId AS taskId, coalesce(t.secondsLogged, 0) AS secondsLogged, coalesce(sum(te.seconds), 0) AS sumEntries`
21161
+ );
21162
+ const taskSums = sumRes.records.map((r) => ({
21163
+ taskId: r.get("taskId") ?? "",
21164
+ secondsLogged: toNum(r.get("secondsLogged")),
21165
+ sumEntries: toNum(r.get("sumEntries"))
21166
+ }));
21167
+ const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
21168
+ const line = `${TAG39} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
21169
+ if (finding.alarm) console.error(`${line} alarm=true`);
21170
+ else console.log(line);
21171
+ return finding;
21172
+ } catch (err) {
21173
+ console.error(`${TAG39} error="${err instanceof Error ? err.message : String(err)}"`);
21174
+ return null;
21175
+ }
21176
+ }
21177
+ var DEFAULT_INTERVAL_MS = 15 * 60 * 1e3;
21178
+ var DEFAULT_HORIZON_MS = 8 * 60 * 60 * 1e3;
21179
+ function startTimeEntryCensus(openSession, opts = {}) {
21180
+ const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
21181
+ const horizonMs = opts.horizonMs ?? DEFAULT_HORIZON_MS;
21182
+ const tick = async () => {
21183
+ const session = openSession();
21184
+ try {
21185
+ await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
21186
+ } finally {
21187
+ try {
21188
+ await session.close();
21189
+ } catch {
21190
+ }
21191
+ }
21192
+ };
21193
+ void tick();
21194
+ const id = setInterval(() => {
21195
+ void tick();
21196
+ }, intervalMs);
21197
+ if (typeof id.unref === "function") {
21198
+ id.unref();
21199
+ }
21200
+ return () => clearInterval(id);
21201
+ }
20610
21202
 
20611
21203
  // app/lib/graph-health.ts
20612
21204
  var import_dist4 = __toESM(require_dist4(), 1);
@@ -21375,8 +21967,8 @@ var streamSSE = (c, cb, onError) => {
21375
21967
 
21376
21968
  // app/lib/whatsapp/gateway/routes.ts
21377
21969
  function createWaChannelRoutes(deps) {
21378
- const app57 = new Hono();
21379
- app57.get("/wa-channel/inbound", (c) => {
21970
+ const app61 = new Hono();
21971
+ app61.get("/wa-channel/inbound", (c) => {
21380
21972
  const senderId = c.req.query("senderId");
21381
21973
  if (!senderId) return c.json({ error: "senderId required" }, 400);
21382
21974
  return streamSSE(c, async (stream2) => {
@@ -21394,7 +21986,7 @@ function createWaChannelRoutes(deps) {
21394
21986
  }
21395
21987
  });
21396
21988
  });
21397
- app57.post("/wa-channel/reply", async (c) => {
21989
+ app61.post("/wa-channel/reply", async (c) => {
21398
21990
  const body = await c.req.json().catch(() => null);
21399
21991
  const senderId = body?.senderId;
21400
21992
  const text = body?.text;
@@ -21415,7 +22007,7 @@ function createWaChannelRoutes(deps) {
21415
22007
  console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
21416
22008
  return c.json({ ok: true });
21417
22009
  });
21418
- app57.post("/wa-channel/reply-document", async (c) => {
22010
+ app61.post("/wa-channel/reply-document", async (c) => {
21419
22011
  const body = await c.req.json().catch(() => null);
21420
22012
  const senderId = body?.senderId;
21421
22013
  const files = body?.files;
@@ -21454,7 +22046,7 @@ function createWaChannelRoutes(deps) {
21454
22046
  }
21455
22047
  return c.json({ ok: true, results });
21456
22048
  });
21457
- app57.post("/wa-channel/ready", async (c) => {
22049
+ app61.post("/wa-channel/ready", async (c) => {
21458
22050
  const body = await c.req.json().catch(() => null);
21459
22051
  const senderId = body?.senderId;
21460
22052
  if (typeof senderId !== "string") {
@@ -21463,7 +22055,7 @@ function createWaChannelRoutes(deps) {
21463
22055
  deps.onReady?.(senderId);
21464
22056
  return c.json({ ok: true });
21465
22057
  });
21466
- app57.post("/wa-channel/received", async (c) => {
22058
+ app61.post("/wa-channel/received", async (c) => {
21467
22059
  const body = await c.req.json().catch(() => null);
21468
22060
  const senderId = body?.senderId;
21469
22061
  const waMessageId = body?.waMessageId;
@@ -21473,7 +22065,7 @@ function createWaChannelRoutes(deps) {
21473
22065
  deps.onReceived?.(senderId, waMessageId);
21474
22066
  return c.json({ ok: true });
21475
22067
  });
21476
- app57.post("/wa-channel/turn-end", async (c) => {
22068
+ app61.post("/wa-channel/turn-end", async (c) => {
21477
22069
  const body = await c.req.json().catch(() => null);
21478
22070
  const senderId = body?.senderId;
21479
22071
  const sessionId = body?.sessionId;
@@ -21489,7 +22081,7 @@ function createWaChannelRoutes(deps) {
21489
22081
  console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=none`);
21490
22082
  return c.json({ ok: true, delivered: "none" });
21491
22083
  });
21492
- return app57;
22084
+ return app61;
21493
22085
  }
21494
22086
 
21495
22087
  // app/lib/whatsapp/gateway/wa-gateway.ts
@@ -21594,7 +22186,8 @@ var WaGateway = class {
21594
22186
  waMessageId: `wa-${++this.seq}`,
21595
22187
  media: input.media,
21596
22188
  source,
21597
- standingRules
22189
+ standingRules,
22190
+ scheduleProvenance: input.scheduleProvenance
21598
22191
  },
21599
22192
  Date.now()
21600
22193
  );
@@ -21612,7 +22205,9 @@ var WaGateway = class {
21612
22205
  role: input.role ?? "admin",
21613
22206
  personId: input.personId ?? null,
21614
22207
  gatewayUrl: this.deps.gatewayUrl,
21615
- serverPath: this.deps.serverPath
22208
+ serverPath: this.deps.serverPath,
22209
+ // Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
22210
+ sessionIdOverride: input.scheduledSessionId
21616
22211
  });
21617
22212
  } finally {
21618
22213
  this.spawning.delete(input.senderId);
@@ -21638,7 +22233,7 @@ var WaGateway = class {
21638
22233
  function buildWaSpawnRequest(input) {
21639
22234
  const personId = input.role === "public" && input.personId ? input.personId : void 0;
21640
22235
  return {
21641
- sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
22236
+ sessionId: input.sessionIdOverride && input.sessionIdOverride.length > 0 ? input.sessionIdOverride : adminSessionIdFor(input.accountId, input.senderId, personId),
21642
22237
  role: input.role,
21643
22238
  channel: "whatsapp",
21644
22239
  personId,
@@ -21822,8 +22417,8 @@ var import_dist6 = __toESM(require_dist(), 1);
21822
22417
 
21823
22418
  // app/lib/webchat/gateway/routes.ts
21824
22419
  function createWebchatChannelRoutes(deps) {
21825
- const app57 = new Hono();
21826
- app57.get("/webchat-channel/inbound", (c) => {
22420
+ const app61 = new Hono();
22421
+ app61.get("/webchat-channel/inbound", (c) => {
21827
22422
  const key = c.req.query("key");
21828
22423
  if (!key) return c.json({ error: "key required" }, 400);
21829
22424
  return streamSSE(c, async (stream2) => {
@@ -21841,7 +22436,7 @@ function createWebchatChannelRoutes(deps) {
21841
22436
  }
21842
22437
  });
21843
22438
  });
21844
- app57.post("/webchat-channel/reply", async (c) => {
22439
+ app61.post("/webchat-channel/reply", async (c) => {
21845
22440
  const body = await c.req.json().catch(() => null);
21846
22441
  const key = body?.key;
21847
22442
  const text = body?.text;
@@ -21851,7 +22446,7 @@ function createWebchatChannelRoutes(deps) {
21851
22446
  deps.onReply?.(key, text);
21852
22447
  return c.json({ ok: true });
21853
22448
  });
21854
- app57.post("/webchat-channel/connector-auth", async (c) => {
22449
+ app61.post("/webchat-channel/connector-auth", async (c) => {
21855
22450
  const body = await c.req.json().catch(() => null);
21856
22451
  const key = body?.key;
21857
22452
  const sessionId = body?.sessionId;
@@ -21864,7 +22459,7 @@ function createWebchatChannelRoutes(deps) {
21864
22459
  const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
21865
22460
  return c.json(result);
21866
22461
  });
21867
- app57.post("/webchat-channel/ready", async (c) => {
22462
+ app61.post("/webchat-channel/ready", async (c) => {
21868
22463
  const body = await c.req.json().catch(() => null);
21869
22464
  const key = body?.key;
21870
22465
  if (typeof key !== "string") {
@@ -21873,7 +22468,7 @@ function createWebchatChannelRoutes(deps) {
21873
22468
  deps.onReady?.(key);
21874
22469
  return c.json({ ok: true });
21875
22470
  });
21876
- app57.post("/webchat-channel/permission-request", async (c) => {
22471
+ app61.post("/webchat-channel/permission-request", async (c) => {
21877
22472
  const body = await c.req.json().catch(() => null);
21878
22473
  const key = body?.key;
21879
22474
  const requestId = body?.request_id;
@@ -21887,7 +22482,7 @@ function createWebchatChannelRoutes(deps) {
21887
22482
  const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
21888
22483
  return c.json(verdict);
21889
22484
  });
21890
- app57.post("/webchat-channel/received", async (c) => {
22485
+ app61.post("/webchat-channel/received", async (c) => {
21891
22486
  const body = await c.req.json().catch(() => null);
21892
22487
  const key = body?.key;
21893
22488
  const messageId = body?.messageId;
@@ -21897,7 +22492,7 @@ function createWebchatChannelRoutes(deps) {
21897
22492
  deps.onReceived?.(key, messageId);
21898
22493
  return c.json({ ok: true });
21899
22494
  });
21900
- app57.post("/webchat-channel/turn-end", async (c) => {
22495
+ app61.post("/webchat-channel/turn-end", async (c) => {
21901
22496
  const body = await c.req.json().catch(() => null);
21902
22497
  const key = body?.key;
21903
22498
  const sessionId = body?.sessionId;
@@ -21917,7 +22512,7 @@ function createWebchatChannelRoutes(deps) {
21917
22512
  console.error(`[webchat-native] op=turn-undelivered channel=webchat key=${k} sessionId=${sid} bytes=${finalBytes}`);
21918
22513
  return c.json({ ok: true, delivered: "undelivered" });
21919
22514
  });
21920
- return app57;
22515
+ return app61;
21921
22516
  }
21922
22517
 
21923
22518
  // app/lib/webchat/gateway/webchat-gateway.ts
@@ -22548,7 +23143,7 @@ function makeFileDelivery(opts) {
22548
23143
  }
22549
23144
 
22550
23145
  // app/lib/whatsapp/inbound/file-delivery-bridge.ts
22551
- var TAG35 = "[whatsapp-adaptor]";
23146
+ var TAG40 = "[whatsapp-adaptor]";
22552
23147
  var SEND_USER_FILE2 = "SendUserFile";
22553
23148
  var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
22554
23149
  function platformRoot() {
@@ -22566,7 +23161,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
22566
23161
  });
22567
23162
  if (result.ok) return { ok: true };
22568
23163
  console.error(
22569
- `${TAG35} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
23164
+ `${TAG40} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
22570
23165
  );
22571
23166
  return { ok: false, error: result.error };
22572
23167
  };
@@ -22574,7 +23169,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
22574
23169
  function makeWhatsAppFileDelivery(entry, maxyAccountId) {
22575
23170
  const shared = makeFileDelivery({
22576
23171
  entry,
22577
- tag: TAG35,
23172
+ tag: TAG40,
22578
23173
  channel: "whatsapp",
22579
23174
  sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
22580
23175
  });
@@ -22609,7 +23204,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
22609
23204
  if (!delivered) {
22610
23205
  const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
22611
23206
  console.error(
22612
- `${TAG35} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
23207
+ `${TAG40} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
22613
23208
  );
22614
23209
  }
22615
23210
  }
@@ -22786,8 +23381,8 @@ var import_dist7 = __toESM(require_dist(), 1);
22786
23381
 
22787
23382
  // app/lib/telegram/gateway/routes.ts
22788
23383
  function createTelegramChannelRoutes(deps) {
22789
- const app57 = new Hono();
22790
- app57.get("/tg-channel/inbound", (c) => {
23384
+ const app61 = new Hono();
23385
+ app61.get("/tg-channel/inbound", (c) => {
22791
23386
  const key = c.req.query("key");
22792
23387
  if (!key) return c.json({ error: "key required" }, 400);
22793
23388
  return streamSSE(c, async (stream2) => {
@@ -22805,7 +23400,7 @@ function createTelegramChannelRoutes(deps) {
22805
23400
  }
22806
23401
  });
22807
23402
  });
22808
- app57.post("/tg-channel/reply", async (c) => {
23403
+ app61.post("/tg-channel/reply", async (c) => {
22809
23404
  const body = await c.req.json().catch(() => null);
22810
23405
  const key = body?.key;
22811
23406
  const text = body?.text;
@@ -22821,7 +23416,7 @@ function createTelegramChannelRoutes(deps) {
22821
23416
  console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
22822
23417
  return c.json({ ok: true });
22823
23418
  });
22824
- app57.post("/tg-channel/ready", async (c) => {
23419
+ app61.post("/tg-channel/ready", async (c) => {
22825
23420
  const body = await c.req.json().catch(() => null);
22826
23421
  const key = body?.key;
22827
23422
  if (typeof key !== "string") {
@@ -22830,7 +23425,7 @@ function createTelegramChannelRoutes(deps) {
22830
23425
  deps.onReady?.(key);
22831
23426
  return c.json({ ok: true });
22832
23427
  });
22833
- app57.post("/tg-channel/received", async (c) => {
23428
+ app61.post("/tg-channel/received", async (c) => {
22834
23429
  const body = await c.req.json().catch(() => null);
22835
23430
  const key = body?.key;
22836
23431
  const messageId = body?.messageId;
@@ -22840,7 +23435,7 @@ function createTelegramChannelRoutes(deps) {
22840
23435
  deps.onReceived?.(key, messageId);
22841
23436
  return c.json({ ok: true });
22842
23437
  });
22843
- app57.post("/tg-channel/turn-end", async (c) => {
23438
+ app61.post("/tg-channel/turn-end", async (c) => {
22844
23439
  const body = await c.req.json().catch(() => null);
22845
23440
  const key = body?.key;
22846
23441
  const sessionId = body?.sessionId;
@@ -22856,7 +23451,7 @@ function createTelegramChannelRoutes(deps) {
22856
23451
  console.error(`[telegram-native] op=turn-end key=${key} sessionId=${sid} replied=no delivered=none`);
22857
23452
  return c.json({ ok: true, delivered: "none" });
22858
23453
  });
22859
- return app57;
23454
+ return app61;
22860
23455
  }
22861
23456
 
22862
23457
  // app/lib/telegram/gateway/telegram-gateway.ts
@@ -22923,7 +23518,7 @@ var TelegramGateway = class {
22923
23518
  );
22924
23519
  }
22925
23520
  this.hub.deliver(
22926
- { key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules },
23521
+ { key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
22927
23522
  Date.now()
22928
23523
  );
22929
23524
  console.error(
@@ -22940,7 +23535,9 @@ var TelegramGateway = class {
22940
23535
  personId: input.personId ?? null,
22941
23536
  chatId: input.chatId,
22942
23537
  gatewayUrl: this.deps.gatewayUrl,
22943
- serverPath: this.deps.serverPath
23538
+ serverPath: this.deps.serverPath,
23539
+ // Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
23540
+ sessionIdOverride: input.scheduledSessionId
22944
23541
  });
22945
23542
  } finally {
22946
23543
  this.spawning.delete(input.senderId);
@@ -22958,7 +23555,7 @@ var TelegramGateway = class {
22958
23555
  function buildTelegramSpawnRequest(input) {
22959
23556
  const personId = input.role === "public" && input.personId ? input.personId : void 0;
22960
23557
  return {
22961
- sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
23558
+ sessionId: input.sessionIdOverride && input.sessionIdOverride.length > 0 ? input.sessionIdOverride : adminSessionIdFor(input.accountId, input.senderId, personId),
22962
23559
  role: input.role,
22963
23560
  channel: "telegram",
22964
23561
  personId,
@@ -22977,7 +23574,7 @@ function buildTelegramSpawnRequest(input) {
22977
23574
  import { realpathSync as realpathSync7 } from "fs";
22978
23575
  import { readFile as readFile7, stat as stat7 } from "fs/promises";
22979
23576
  import { resolve as resolve30, basename as basename12 } from "path";
22980
- var TAG36 = "[telegram:outbound]";
23577
+ var TAG41 = "[telegram:outbound]";
22981
23578
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
22982
23579
  async function sendTelegramDocument(input) {
22983
23580
  const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot3 } = input;
@@ -22993,16 +23590,16 @@ async function sendTelegramDocument(input) {
22993
23590
  resolvedPath = realpathSync7(filePath);
22994
23591
  const accountResolved = realpathSync7(accountDir);
22995
23592
  if (!resolvedPath.startsWith(accountResolved + "/")) {
22996
- console.error(`${TAG36} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
23593
+ console.error(`${TAG41} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
22997
23594
  return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
22998
23595
  }
22999
23596
  } catch (err) {
23000
23597
  const code = err.code;
23001
23598
  if (code === "ENOENT") {
23002
- console.error(`${TAG36} document ENOENT path=${filePath}`);
23599
+ console.error(`${TAG41} document ENOENT path=${filePath}`);
23003
23600
  return { ok: false, status: 404, error: `File not found: ${filePath}` };
23004
23601
  }
23005
- console.error(`${TAG36} document path error: ${String(err)}`);
23602
+ console.error(`${TAG41} document path error: ${String(err)}`);
23006
23603
  return { ok: false, status: 500, error: String(err) };
23007
23604
  }
23008
23605
  const fileStat = await stat7(resolvedPath);
@@ -23035,13 +23632,13 @@ async function sendTelegramDocument(input) {
23035
23632
  error = e instanceof Error ? e.message : String(e);
23036
23633
  }
23037
23634
  console.error(
23038
- `${TAG36} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
23635
+ `${TAG41} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
23039
23636
  );
23040
23637
  return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
23041
23638
  }
23042
23639
 
23043
23640
  // app/lib/telegram/outbound/file-delivery.ts
23044
- var TAG37 = "[telegram:outbound]";
23641
+ var TAG42 = "[telegram:outbound]";
23045
23642
  function platformRoot2() {
23046
23643
  return process.env.MAXY_PLATFORM_ROOT || "";
23047
23644
  }
@@ -23053,11 +23650,11 @@ function makeTelegramSendFile(entry) {
23053
23650
  botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
23054
23651
  }
23055
23652
  if (!botToken) {
23056
- console.error(`${TAG37} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
23653
+ console.error(`${TAG42} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
23057
23654
  return { ok: false, error: "no-bot-token" };
23058
23655
  }
23059
23656
  if (entry.replyTarget == null) {
23060
- console.error(`${TAG37} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
23657
+ console.error(`${TAG42} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
23061
23658
  return { ok: false, error: "no-reply-target" };
23062
23659
  }
23063
23660
  const result = await sendTelegramDocument({
@@ -23074,7 +23671,7 @@ function makeTelegramSendFile(entry) {
23074
23671
  function makeTelegramFileDelivery(entry) {
23075
23672
  return makeFileDelivery({
23076
23673
  entry,
23077
- tag: TAG37,
23674
+ tag: TAG42,
23078
23675
  channel: "telegram",
23079
23676
  sendFile: makeTelegramSendFile(entry)
23080
23677
  });
@@ -23123,8 +23720,8 @@ function telegramServerPath() {
23123
23720
  }
23124
23721
 
23125
23722
  // app/lib/channel-pty-bridge/public-session-end-review.ts
23126
- import { randomUUID as randomUUID13 } from "crypto";
23127
- var TAG38 = "[public-session-review]";
23723
+ import { randomUUID as randomUUID14 } from "crypto";
23724
+ var TAG43 = "[public-session-review]";
23128
23725
  var CONSUMED_CAP = 500;
23129
23726
  var consumed = /* @__PURE__ */ new Set();
23130
23727
  function consumeOnce(sessionId) {
@@ -23151,7 +23748,7 @@ async function fetchJsonl(sessionId) {
23151
23748
  return await res.text();
23152
23749
  } catch (err) {
23153
23750
  console.error(
23154
- `${TAG38} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
23751
+ `${TAG43} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
23155
23752
  );
23156
23753
  return null;
23157
23754
  }
@@ -23175,7 +23772,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
23175
23772
  const res = await fetch(url);
23176
23773
  if (!res.ok) {
23177
23774
  console.error(
23178
- `${TAG38} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
23775
+ `${TAG43} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
23179
23776
  );
23180
23777
  return [];
23181
23778
  }
@@ -23183,7 +23780,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
23183
23780
  return Array.isArray(body.writes) ? body.writes : [];
23184
23781
  } catch (err) {
23185
23782
  console.error(
23186
- `${TAG38} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
23783
+ `${TAG43} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
23187
23784
  );
23188
23785
  return [];
23189
23786
  }
@@ -23211,8 +23808,8 @@ function composeInitialMessage(input) {
23211
23808
  ].join("\n");
23212
23809
  }
23213
23810
  async function dispatchReviewer(input, initialMessage) {
23214
- const sessionId = randomUUID13();
23215
- console.log(`${TAG38} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
23811
+ const sessionId = randomUUID14();
23812
+ console.log(`${TAG43} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
23216
23813
  const spawned = await managerRcSpawn({
23217
23814
  sessionId,
23218
23815
  initialMessage,
@@ -23232,21 +23829,21 @@ async function firePublicSessionEndReview(input) {
23232
23829
  const dispatchedAt = Date.now();
23233
23830
  if (consumed.has(input.sessionId)) {
23234
23831
  console.log(
23235
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
23832
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
23236
23833
  );
23237
23834
  return;
23238
23835
  }
23239
23836
  const jsonl = await fetchJsonl(input.sessionId);
23240
23837
  if (!jsonl) {
23241
23838
  console.log(
23242
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
23839
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
23243
23840
  );
23244
23841
  return;
23245
23842
  }
23246
23843
  const operatorTurns = countOperatorTurns(jsonl);
23247
23844
  if (operatorTurns === 0) {
23248
23845
  console.log(
23249
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
23846
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
23250
23847
  );
23251
23848
  return;
23252
23849
  }
@@ -23260,19 +23857,19 @@ async function firePublicSessionEndReview(input) {
23260
23857
  });
23261
23858
  if (!consumeOnce(input.sessionId)) {
23262
23859
  console.log(
23263
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
23860
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
23264
23861
  );
23265
23862
  return;
23266
23863
  }
23267
23864
  const dispatched = await dispatchReviewer(input, initialMessage);
23268
23865
  if (!dispatched.ok) {
23269
23866
  console.error(
23270
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
23867
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
23271
23868
  );
23272
23869
  return;
23273
23870
  }
23274
23871
  console.log(
23275
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
23872
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
23276
23873
  );
23277
23874
  }
23278
23875
 
@@ -23687,7 +24284,7 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
23687
24284
  function isPublicHost(host) {
23688
24285
  return host.startsWith("public.") || aliasDomains.has(host);
23689
24286
  }
23690
- var app56 = new Hono();
24287
+ var app60 = new Hono();
23691
24288
  var nativeFileFollowers = /* @__PURE__ */ new Map();
23692
24289
  async function fetchAccountStandingRules(accountId) {
23693
24290
  const session = getSession();
@@ -23745,7 +24342,7 @@ var waGateway = new WaGateway({
23745
24342
  });
23746
24343
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
23747
24344
  },
23748
- ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId }) => {
24345
+ ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, sessionIdOverride }) => {
23749
24346
  if (passive) {
23750
24347
  const phoneHash = createHash6("sha256").update(senderId).digest("hex").slice(0, 12);
23751
24348
  const prompt = (text ?? "").trim();
@@ -23793,7 +24390,7 @@ var waGateway = new WaGateway({
23793
24390
  const managesAccount = effectiveAccountId !== accountId ? effectiveAccountId : "none";
23794
24391
  console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
23795
24392
  }
23796
- const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath });
24393
+ const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
23797
24394
  const userId = role === "admin" ? resolveAdminUserId({ accountId: effectiveAccountId, senderPhone: senderId }) ?? void 0 : void 0;
23798
24395
  if (role === "admin") {
23799
24396
  console.error(`[whatsapp-native] op=admin-identity senderId=${senderId} userId=${userId ?? "owner-fallback"}`);
@@ -23822,7 +24419,7 @@ var waGateway = new WaGateway({
23822
24419
  nativeFileFollowers.set(senderId, ac);
23823
24420
  }
23824
24421
  });
23825
- app56.route("/", waGateway.routes());
24422
+ app60.route("/", waGateway.routes());
23826
24423
  waGateway.startSweeper();
23827
24424
  var webchatGateway = new WebchatGateway({
23828
24425
  fetchStandingRules: fetchAccountStandingRules,
@@ -23906,7 +24503,7 @@ var webchatGateway = new WebchatGateway({
23906
24503
  firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
23907
24504
  });
23908
24505
  setWebchatGateway(webchatGateway);
23909
- app56.route("/", webchatGateway.routes());
24506
+ app60.route("/", webchatGateway.routes());
23910
24507
  webchatGateway.startSweeper();
23911
24508
  webchatGateway.startPublicReaper();
23912
24509
  var telegramFileFollowers = /* @__PURE__ */ new Map();
@@ -23914,8 +24511,8 @@ var telegramGateway = new TelegramGateway({
23914
24511
  fetchStandingRules: fetchAccountStandingRules,
23915
24512
  gatewayUrl: telegramGatewayUrl(),
23916
24513
  serverPath: telegramServerPath(),
23917
- ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath }) => {
23918
- const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath });
24514
+ ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath, sessionIdOverride }) => {
24515
+ const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
23919
24516
  const result = await managerRcSpawn(req);
23920
24517
  if ("error" in result) {
23921
24518
  console.error(`[telegram-native] spawn-failed senderId=${senderId} role=${role} error=${result.error} status=${result.status}`);
@@ -23940,7 +24537,7 @@ var telegramGateway = new TelegramGateway({
23940
24537
  }
23941
24538
  });
23942
24539
  setTelegramGateway(telegramGateway);
23943
- app56.route("/", telegramGateway.routes());
24540
+ app60.route("/", telegramGateway.routes());
23944
24541
  telegramGateway.startSweeper();
23945
24542
  var chatRoutes = createChatRoutes({
23946
24543
  handleInbound: (input) => webchatGateway.handleInbound(input),
@@ -23973,19 +24570,19 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
23973
24570
  return managed.account;
23974
24571
  }
23975
24572
  });
23976
- app56.route("/api/channel/schedule-inject", scheduleInjectRoutes);
23977
- app56.use("*", clientIpMiddleware);
24573
+ app60.route("/api/channel/schedule-inject", scheduleInjectRoutes);
24574
+ app60.use("*", clientIpMiddleware);
23978
24575
  function allowsSameOriginFraming(path2) {
23979
24576
  return path2 === "/vnc-viewer.html" || path2.startsWith("/api/admin/attachment/") || path2.startsWith("/api/public-reader/attachment/") || path2 === "/api/admin/files/download";
23980
24577
  }
23981
- app56.use("*", async (c, next) => {
24578
+ app60.use("*", async (c, next) => {
23982
24579
  await next();
23983
24580
  c.header("X-Content-Type-Options", "nosniff");
23984
24581
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
23985
24582
  c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
23986
24583
  });
23987
24584
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
23988
- app56.use("*", async (c, next) => {
24585
+ app60.use("*", async (c, next) => {
23989
24586
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
23990
24587
  await next();
23991
24588
  return;
@@ -24003,7 +24600,7 @@ app56.use("*", async (c, next) => {
24003
24600
  });
24004
24601
  }
24005
24602
  });
24006
- app56.use("*", async (c, next) => {
24603
+ app60.use("*", async (c, next) => {
24007
24604
  const host = (c.req.header("host") ?? "").split(":")[0];
24008
24605
  if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
24009
24606
  await next();
@@ -24041,7 +24638,7 @@ function resolveRemoteAuthOpts(c) {
24041
24638
  return { ...brandLoginOpts, origin };
24042
24639
  }
24043
24640
  var MAX_LOGIN_BODY = 8 * 1024;
24044
- app56.post("/__remote-auth/login", async (c) => {
24641
+ app60.post("/__remote-auth/login", async (c) => {
24045
24642
  const client = clientFrom(c);
24046
24643
  const clientIp = client.ip || "unknown";
24047
24644
  if (!requestIsTlsTerminated(c)) {
@@ -24086,7 +24683,7 @@ app56.post("/__remote-auth/login", async (c) => {
24086
24683
  }
24087
24684
  });
24088
24685
  });
24089
- app56.get("/__remote-auth/logout", (c) => {
24686
+ app60.get("/__remote-auth/logout", (c) => {
24090
24687
  const client = clientFrom(c);
24091
24688
  const clientIp = client.ip || "unknown";
24092
24689
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -24099,7 +24696,7 @@ app56.get("/__remote-auth/logout", (c) => {
24099
24696
  }
24100
24697
  });
24101
24698
  });
24102
- app56.post("/__remote-auth/change-password", async (c) => {
24699
+ app60.post("/__remote-auth/change-password", async (c) => {
24103
24700
  const client = clientFrom(c);
24104
24701
  const clientIp = client.ip || "unknown";
24105
24702
  const rateLimited = checkRateLimit(client);
@@ -24158,13 +24755,13 @@ app56.post("/__remote-auth/change-password", async (c) => {
24158
24755
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
24159
24756
  }
24160
24757
  });
24161
- app56.get("/__remote-auth/setup", (c) => {
24758
+ app60.get("/__remote-auth/setup", (c) => {
24162
24759
  if (isRemoteAuthConfigured()) {
24163
24760
  return c.redirect("/");
24164
24761
  }
24165
24762
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
24166
24763
  });
24167
- app56.post("/__remote-auth/set-initial-password", async (c) => {
24764
+ app60.post("/__remote-auth/set-initial-password", async (c) => {
24168
24765
  if (isRemoteAuthConfigured()) {
24169
24766
  return c.redirect("/");
24170
24767
  }
@@ -24202,10 +24799,10 @@ app56.post("/__remote-auth/set-initial-password", async (c) => {
24202
24799
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
24203
24800
  }
24204
24801
  });
24205
- app56.get("/api/remote-auth/status", (c) => {
24802
+ app60.get("/api/remote-auth/status", (c) => {
24206
24803
  return c.json({ configured: isRemoteAuthConfigured() });
24207
24804
  });
24208
- app56.post("/api/remote-auth/set-password", async (c) => {
24805
+ app60.post("/api/remote-auth/set-password", async (c) => {
24209
24806
  let body;
24210
24807
  try {
24211
24808
  body = await c.req.json();
@@ -24244,10 +24841,10 @@ app56.post("/api/remote-auth/set-password", async (c) => {
24244
24841
  return c.json({ error: "Failed to save password" }, 500);
24245
24842
  }
24246
24843
  });
24247
- app56.route("/api/_client-error", client_error_default);
24844
+ app60.route("/api/_client-error", client_error_default);
24248
24845
  console.log("[client-error-route] mounted");
24249
24846
  var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
24250
- app56.use("*", async (c, next) => {
24847
+ app60.use("*", async (c, next) => {
24251
24848
  const host = (c.req.header("host") ?? "").split(":")[0];
24252
24849
  const path2 = c.req.path;
24253
24850
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
@@ -24291,26 +24888,26 @@ app56.use("*", async (c, next) => {
24291
24888
  }
24292
24889
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path2 }), 200);
24293
24890
  });
24294
- app56.route("/api/health", health_default);
24295
- app56.route("/api/chat", chatRoutes);
24296
- app56.route("/api/whatsapp", whatsapp_default);
24297
- app56.route("/api/whatsapp-reader", whatsapp_reader_default);
24298
- app56.route("/api/public-reader", public_reader_default);
24299
- app56.route("/api/webchat", createWebchatRoutes({
24891
+ app60.route("/api/health", health_default);
24892
+ app60.route("/api/chat", chatRoutes);
24893
+ app60.route("/api/whatsapp", whatsapp_default);
24894
+ app60.route("/api/whatsapp-reader", whatsapp_reader_default);
24895
+ app60.route("/api/public-reader", public_reader_default);
24896
+ app60.route("/api/webchat", createWebchatRoutes({
24300
24897
  handleInbound: (input) => webchatGateway.handleInbound(input),
24301
24898
  // Task 940 — the permission relay's pointer read + verdict write.
24302
24899
  pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
24303
24900
  deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
24304
24901
  resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
24305
24902
  }));
24306
- app56.route("/api/webchat/greeting", webchat_greeting_default);
24307
- app56.route("/api/telegram", telegram_default);
24308
- app56.route("/api/quickbooks", quickbooks_default);
24309
- app56.route("/api/onboarding", onboarding_default);
24310
- app56.route("/api/admin", admin_default);
24311
- app56.route("/api/access", access_default);
24312
- app56.route("/api/session", session_default2);
24313
- app56.route("/api/calendar", calendar_public_default);
24903
+ app60.route("/api/webchat/greeting", webchat_greeting_default);
24904
+ app60.route("/api/telegram", telegram_default);
24905
+ app60.route("/api/quickbooks", quickbooks_default);
24906
+ app60.route("/api/onboarding", onboarding_default);
24907
+ app60.route("/api/admin", admin_default);
24908
+ app60.route("/api/access", access_default);
24909
+ app60.route("/api/session", session_default2);
24910
+ app60.route("/api/calendar", calendar_public_default);
24314
24911
  var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
24315
24912
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
24316
24913
  var IMAGE_MIME = {
@@ -24322,7 +24919,7 @@ var IMAGE_MIME = {
24322
24919
  ".svg": "image/svg+xml",
24323
24920
  ".ico": "image/x-icon"
24324
24921
  };
24325
- app56.get("/agent-assets/:slug/:filename", (c) => {
24922
+ app60.get("/agent-assets/:slug/:filename", (c) => {
24326
24923
  const slug = c.req.param("slug");
24327
24924
  const filename = c.req.param("filename");
24328
24925
  if (!SAFE_SLUG_RE2.test(slug)) {
@@ -24357,7 +24954,7 @@ app56.get("/agent-assets/:slug/:filename", (c) => {
24357
24954
  "Cache-Control": "public, max-age=3600"
24358
24955
  });
24359
24956
  });
24360
- app56.get("/generated/:filename", (c) => {
24957
+ app60.get("/generated/:filename", (c) => {
24361
24958
  const filename = c.req.param("filename");
24362
24959
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
24363
24960
  console.error(`[generated] serve file=${filename} status=403`);
@@ -24387,10 +24984,10 @@ app56.get("/generated/:filename", (c) => {
24387
24984
  "Cache-Control": "public, max-age=86400"
24388
24985
  });
24389
24986
  });
24390
- app56.route("/sites", sites_default);
24391
- app56.route("/listings", listings_default);
24392
- app56.route("/v", visitor_event_default);
24393
- app56.route("/v", visitor_consent_default);
24987
+ app60.route("/sites", sites_default);
24988
+ app60.route("/listings", listings_default);
24989
+ app60.route("/v", visitor_event_default);
24990
+ app60.route("/v", visitor_consent_default);
24394
24991
  var htmlCache = /* @__PURE__ */ new Map();
24395
24992
  var brandLogoPath = "/brand/maxy-monochrome.png";
24396
24993
  var brandIconPath = "/brand/maxy-monochrome.png";
@@ -24545,7 +25142,7 @@ function brandedPublicHtml(agentSlug) {
24545
25142
  function agentUnavailableHtml() {
24546
25143
  return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
24547
25144
  }
24548
- app56.get("/", (c) => {
25145
+ app60.get("/", (c) => {
24549
25146
  const host = (c.req.header("host") ?? "").split(":")[0];
24550
25147
  const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
24551
25148
  if (klass === "operator") {
@@ -24567,12 +25164,12 @@ app56.get("/", (c) => {
24567
25164
  console.log(`[host-class] host=${host} class=admin served=index.html`);
24568
25165
  return c.html(cachedHtml("index.html"));
24569
25166
  });
24570
- app56.get("/public", (c) => {
25167
+ app60.get("/public", (c) => {
24571
25168
  const host = (c.req.header("host") ?? "").split(":")[0];
24572
25169
  if (isPublicHost(host)) return c.text("Not found", 404);
24573
25170
  return c.html(cachedHtml("public.html"));
24574
25171
  });
24575
- app56.get("/public-chat", (c) => {
25172
+ app60.get("/public-chat", (c) => {
24576
25173
  const host = (c.req.header("host") ?? "").split(":")[0];
24577
25174
  if (isPublicHost(host)) return c.text("Not found", 404);
24578
25175
  return c.html(cachedHtml("public.html"));
@@ -24591,9 +25188,9 @@ async function logViewerFetch(c, next) {
24591
25188
  duration_ms: Date.now() - start
24592
25189
  });
24593
25190
  }
24594
- app56.use("/vnc-viewer.html", logViewerFetch);
24595
- app56.use("/vnc-popout.html", logViewerFetch);
24596
- app56.get("/vnc-popout.html", (c) => {
25191
+ app60.use("/vnc-viewer.html", logViewerFetch);
25192
+ app60.use("/vnc-popout.html", logViewerFetch);
25193
+ app60.get("/vnc-popout.html", (c) => {
24597
25194
  let html = htmlCache.get("vnc-popout.html");
24598
25195
  if (!html) {
24599
25196
  html = readFileSync35(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
@@ -24606,7 +25203,7 @@ app56.get("/vnc-popout.html", (c) => {
24606
25203
  }
24607
25204
  return c.html(html);
24608
25205
  });
24609
- app56.post("/api/vnc/client-event", async (c) => {
25206
+ app60.post("/api/vnc/client-event", async (c) => {
24610
25207
  let body;
24611
25208
  try {
24612
25209
  body = await c.req.json();
@@ -24627,11 +25224,11 @@ app56.post("/api/vnc/client-event", async (c) => {
24627
25224
  });
24628
25225
  return c.json({ ok: true });
24629
25226
  });
24630
- app56.get("/g/:slug", (c) => {
25227
+ app60.get("/g/:slug", (c) => {
24631
25228
  return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
24632
25229
  });
24633
25230
  for (const pwa of PWA_SURFACES) {
24634
- app56.get(pwa.manifestPath, (c) => {
25231
+ app60.get(pwa.manifestPath, (c) => {
24635
25232
  const manifest = buildManifest(pwa, {
24636
25233
  productName: BRAND.productName,
24637
25234
  appIcon192: brandAppIcon192Path,
@@ -24647,7 +25244,7 @@ for (const pwa of PWA_SURFACES) {
24647
25244
  return c.body(JSON.stringify(manifest));
24648
25245
  });
24649
25246
  }
24650
- app56.get("/sw.js", (c) => {
25247
+ app60.get("/sw.js", (c) => {
24651
25248
  if (SW_SOURCE == null) {
24652
25249
  console.error("[pwa] op=sw status=500 reason=sw-source-missing");
24653
25250
  return c.text("Service worker unavailable", 500);
@@ -24656,12 +25253,12 @@ app56.get("/sw.js", (c) => {
24656
25253
  console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
24657
25254
  return c.body(SW_SOURCE);
24658
25255
  });
24659
- app56.get("/graph", (c) => {
25256
+ app60.get("/graph", (c) => {
24660
25257
  const host = (c.req.header("host") ?? "").split(":")[0];
24661
25258
  if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
24662
25259
  return c.html(cachedHtml("graph.html"));
24663
25260
  });
24664
- app56.get("/chat", (c) => {
25261
+ app60.get("/chat", (c) => {
24665
25262
  const host = (c.req.header("host") ?? "").split(":")[0];
24666
25263
  if (isOperatorHost(host, getOperatorDomains())) {
24667
25264
  console.log(`[host-class] host=${host} class=operator served=operator.html`);
@@ -24670,22 +25267,22 @@ app56.get("/chat", (c) => {
24670
25267
  if (isPublicHost(host)) return c.text("Not found", 404);
24671
25268
  return c.html(cachedHtml("chat.html"));
24672
25269
  });
24673
- app56.get("/data", (c) => {
25270
+ app60.get("/data", (c) => {
24674
25271
  const host = (c.req.header("host") ?? "").split(":")[0];
24675
25272
  if (isPublicHost(host)) return c.text("Not found", 404);
24676
25273
  return c.html(cachedHtml("data.html"));
24677
25274
  });
24678
- app56.get("/calendar", (c) => {
25275
+ app60.get("/calendar", (c) => {
24679
25276
  const host = (c.req.header("host") ?? "").split(":")[0];
24680
25277
  if (isPublicHost(host)) return c.text("Not found", 404);
24681
25278
  return c.html(cachedHtml("calendar.html"));
24682
25279
  });
24683
- app56.get("/browser", (c) => {
25280
+ app60.get("/browser", (c) => {
24684
25281
  const host = (c.req.header("host") ?? "").split(":")[0];
24685
25282
  if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
24686
25283
  return c.html(cachedHtml("browser.html"));
24687
25284
  });
24688
- app56.get("/:slug", async (c, next) => {
25285
+ app60.get("/:slug", async (c, next) => {
24689
25286
  const slug = c.req.param("slug");
24690
25287
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
24691
25288
  const account = resolveAccount();
@@ -24700,13 +25297,13 @@ app56.get("/:slug", async (c, next) => {
24700
25297
  await next();
24701
25298
  });
24702
25299
  if (brandFaviconPath !== "/favicon.ico") {
24703
- app56.get("/favicon.ico", (c) => {
25300
+ app60.get("/favicon.ico", (c) => {
24704
25301
  c.header("Cache-Control", "public, max-age=300");
24705
25302
  return c.redirect(brandFaviconPath, 302);
24706
25303
  });
24707
25304
  }
24708
- app56.use("/*", serveStatic({ root: "./public" }));
24709
- app56.all("*", (c) => {
25305
+ app60.use("/*", serveStatic({ root: "./public" }));
25306
+ app60.all("*", (c) => {
24710
25307
  const host = (c.req.header("host") ?? "").split(":")[0];
24711
25308
  const path2 = c.req.path;
24712
25309
  if (isPublicHost(host)) {
@@ -24720,7 +25317,7 @@ app56.all("*", (c) => {
24720
25317
  });
24721
25318
  var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
24722
25319
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
24723
- var httpServer = serve({ fetch: app56.fetch, port, hostname });
25320
+ var httpServer = serve({ fetch: app60.fetch, port, hostname });
24724
25321
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
24725
25322
  {
24726
25323
  const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, "..");
@@ -24744,6 +25341,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
24744
25341
  const loop = setInterval(runReconcile, RECONCILE_INTERVAL_MS);
24745
25342
  loop.unref();
24746
25343
  }
25344
+ startTimeEntryCensus(() => getSession());
24747
25345
  {
24748
25346
  const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, "..");
24749
25347
  const auditScript = resolve33(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
@@ -24820,7 +25418,7 @@ for (const m of SUBAPP_MANIFEST) {
24820
25418
  }
24821
25419
  try {
24822
25420
  const registered = [];
24823
- for (const r of app56.routes ?? []) {
25421
+ for (const r of app60.routes ?? []) {
24824
25422
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
24825
25423
  if (AGENT_SLUG_PATTERN.test(r.path)) {
24826
25424
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -24971,6 +25569,7 @@ for (const acct of listValidAccounts()) {
24971
25569
  cleanupLeakedPremiumSubs(acct.accountDir, acct.config, acct.accountId);
24972
25570
  }
24973
25571
  purgeNonSocketAdminPhonesAtBoot();
25572
+ void preloadEmbedModel();
24974
25573
  warnOnChannelAdminBindingDrift();
24975
25574
  var bootEnabled = Array.isArray(bootAccountConfig?.enabledPlugins) ? bootAccountConfig.enabledPlugins : [];
24976
25575
  var bootDelivered = [];