@rubytech/create-maxy-code 0.1.423 → 0.1.427

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 (306) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +13 -0
  3. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  4. package/payload/platform/plugins/admin/PLUGIN.md +5 -1
  5. package/payload/platform/plugins/admin/hooks/__tests__/datetime-inject.test.sh +119 -0
  6. package/payload/platform/plugins/admin/hooks/datetime-inject.sh +115 -0
  7. package/payload/platform/plugins/admin/mcp/dist/index.js +62 -4
  8. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  9. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +44 -0
  10. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
  11. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +96 -0
  12. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
  13. package/payload/platform/plugins/admin/skills/datetime/SKILL.md +9 -2
  14. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +14 -2
  15. package/payload/platform/plugins/docs/references/cross-account-authority.md +8 -0
  16. package/payload/platform/plugins/docs/references/internals.md +4 -0
  17. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  18. package/payload/platform/plugins/email/PLUGIN.md +2 -2
  19. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +73 -4
  20. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -1
  21. package/payload/platform/plugins/email/mcp/dist/__tests__/mailbox-resolve.test.js +42 -1
  22. package/payload/platform/plugins/email/mcp/dist/__tests__/mailbox-resolve.test.js.map +1 -1
  23. package/payload/platform/plugins/email/mcp/dist/index.js +1 -0
  24. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  25. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +4 -0
  26. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -1
  27. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +5 -0
  28. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -1
  29. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +25 -3
  30. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  31. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +67 -12
  32. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  33. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts +1 -0
  34. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  35. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +1 -0
  36. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  37. package/payload/platform/plugins/email/references/email-reference.md +8 -0
  38. package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
  39. package/payload/platform/plugins/scheduling/mcp/dist/index.js +5 -2
  40. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  41. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js +50 -1
  42. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js.map +1 -1
  43. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts +2 -0
  44. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts.map +1 -0
  45. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js +22 -0
  46. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js.map +1 -0
  47. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts +35 -0
  48. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts.map +1 -1
  49. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js +36 -0
  50. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js.map +1 -1
  51. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts +11 -0
  52. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts.map +1 -0
  53. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js +19 -0
  54. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js.map +1 -0
  55. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +85 -3
  56. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
  57. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js +32 -1
  58. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js.map +1 -1
  59. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +14 -1
  60. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  61. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +94 -4
  62. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  63. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +23 -7
  64. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  65. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.d.ts +2 -0
  66. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.d.ts.map +1 -0
  67. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js +30 -0
  68. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-cancel.test.js.map +1 -0
  69. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts +29 -0
  70. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -1
  71. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +47 -2
  72. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -1
  73. package/payload/platform/plugins/whatsapp/PLUGIN.md +2 -0
  74. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.d.ts +2 -0
  75. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.d.ts.map +1 -0
  76. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.js +20 -0
  77. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/caller-scope-headers.test.js.map +1 -0
  78. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts +1 -1
  79. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts.map +1 -1
  80. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js +5 -2
  81. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js.map +1 -1
  82. package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.d.ts +9 -0
  83. package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.d.ts.map +1 -0
  84. package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.js +18 -0
  85. package/payload/platform/plugins/whatsapp/mcp/dist/caller-scope-headers.js.map +1 -0
  86. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +13 -11
  87. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  88. package/payload/platform/plugins/work/PLUGIN.md +1 -1
  89. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.d.ts +2 -0
  90. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.d.ts.map +1 -0
  91. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js +72 -0
  92. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-assigned-admin-env.test.js.map +1 -0
  93. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.d.ts +2 -0
  94. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.d.ts.map +1 -0
  95. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.js +67 -0
  96. package/payload/platform/plugins/work/mcp/dist/__tests__/work-create-client-fields.test.js.map +1 -0
  97. package/payload/platform/plugins/work/mcp/dist/index.js +3 -0
  98. package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
  99. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts +6 -0
  100. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts.map +1 -1
  101. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js +34 -1
  102. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -1
  103. package/payload/platform/scripts/lib/provision-account-dir.sh +2 -1
  104. package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts +39 -0
  105. package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts.map +1 -0
  106. package/payload/platform/services/claude-session-manager/dist/account-admin-census.js +122 -0
  107. package/payload/platform/services/claude-session-manager/dist/account-admin-census.js.map +1 -0
  108. package/payload/platform/services/claude-session-manager/dist/account-timezone.d.ts +40 -0
  109. package/payload/platform/services/claude-session-manager/dist/account-timezone.d.ts.map +1 -0
  110. package/payload/platform/services/claude-session-manager/dist/account-timezone.js +126 -0
  111. package/payload/platform/services/claude-session-manager/dist/account-timezone.js.map +1 -0
  112. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  113. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  114. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  115. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  116. package/payload/platform/services/claude-session-manager/dist/http-server.js +18 -1
  117. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  118. package/payload/platform/services/claude-session-manager/dist/index.js +13 -0
  119. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  120. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +11 -0
  121. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  122. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +28 -0
  123. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  124. package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
  125. package/payload/platform/services/telegram-channel/dist/instructions.js +8 -1
  126. package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
  127. package/payload/platform/services/telegram-channel/dist/notification.d.ts +22 -0
  128. package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
  129. package/payload/platform/services/telegram-channel/dist/notification.js +22 -1
  130. package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
  131. package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
  132. package/payload/platform/services/webchat-channel/dist/instructions.js +8 -1
  133. package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
  134. package/payload/platform/services/webchat-channel/dist/notification.d.ts +22 -0
  135. package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
  136. package/payload/platform/services/webchat-channel/dist/notification.js +22 -1
  137. package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
  138. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +28 -2
  139. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  140. package/payload/platform/services/whatsapp-channel/dist/notification.js +32 -3
  141. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  142. package/payload/platform/templates/account.json +2 -1
  143. package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
  144. package/payload/server/public/assets/{AdminLoginScreens-B1P6PrZ3.js → AdminLoginScreens-yAIhWcGc.js} +1 -1
  145. package/payload/server/public/assets/AdminShell-Bk1AFQ4D.js +2 -0
  146. package/payload/server/public/assets/{Checkbox-CgCqOslz.js → Checkbox-B_lfjsqd.js} +1 -1
  147. package/payload/server/public/assets/Transcript-D67OZnVM.js +2 -0
  148. package/payload/server/public/assets/admin-DuOhkvrZ.js +1 -0
  149. package/payload/server/public/assets/{arc-DyzjCWmw.js → arc-dVLpR-ec.js} +1 -1
  150. package/payload/server/public/assets/architecture-YZFGNWBL-CgeA3HPD.js +1 -0
  151. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-qWfElD16.js → architectureDiagram-Q4EWVU46-C6u_CVzb.js} +1 -1
  152. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DO2fFHC3.js → blockDiagram-DXYQGD6D-Cy8F5b8O.js} +1 -1
  153. package/payload/server/public/assets/browser-CCWufeXr.js +1 -0
  154. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Ca-q5gDe.js → c4Diagram-AHTNJAMY-DRXrlepj.js} +1 -1
  155. package/payload/server/public/assets/calendar-CNk1iPrA.js +1 -0
  156. package/payload/server/public/assets/channel-B04VBWf7.js +1 -0
  157. package/payload/server/public/assets/chat-7qB-dwBq.js +1 -0
  158. package/payload/server/public/assets/chevron-left-CpcDbHIz.js +1 -0
  159. package/payload/server/public/assets/{chunk-2KRD3SAO-CX2PxuDw.js → chunk-2KRD3SAO-fEyfhRLz.js} +1 -1
  160. package/payload/server/public/assets/{chunk-336JU56O-D8l6U4Ne.js → chunk-336JU56O-NUWO4y7q.js} +2 -2
  161. package/payload/server/public/assets/chunk-426QAEUC-DZkHcXRA.js +1 -0
  162. package/payload/server/public/assets/{chunk-4BX2VUAB-CG32Lkbh.js → chunk-4BX2VUAB-BnfiNR3l.js} +1 -1
  163. package/payload/server/public/assets/{chunk-4TB4RGXK-BnAQbO-v.js → chunk-4TB4RGXK-Bj_aJOz8.js} +1 -1
  164. package/payload/server/public/assets/{chunk-55IACEB6-ejqRH2M5.js → chunk-55IACEB6-aK0DNSKb.js} +1 -1
  165. package/payload/server/public/assets/{chunk-5FUZZQ4R-ClkicQ-T.js → chunk-5FUZZQ4R-DeqAkq5C.js} +1 -1
  166. package/payload/server/public/assets/{chunk-5PVQY5BW-Be-mE_rx.js → chunk-5PVQY5BW-SShlujAQ.js} +1 -1
  167. package/payload/server/public/assets/{chunk-67CJDMHE-DPsemed2.js → chunk-67CJDMHE-CZpzQ0DL.js} +1 -1
  168. package/payload/server/public/assets/{chunk-7N4EOEYR-BQRQJETl.js → chunk-7N4EOEYR-COnjO6jy.js} +1 -1
  169. package/payload/server/public/assets/{chunk-AA7GKIK3-B1wcAVCK.js → chunk-AA7GKIK3-C9V31L2z.js} +1 -1
  170. package/payload/server/public/assets/{chunk-BSJP7CBP-DIua053h.js → chunk-BSJP7CBP-DSwnSGe3.js} +1 -1
  171. package/payload/server/public/assets/{chunk-CIAEETIT-C9GHSCS9.js → chunk-CIAEETIT-CnRUTuta.js} +1 -1
  172. package/payload/server/public/assets/{chunk-EDXVE4YY-C1T3l1xj.js → chunk-EDXVE4YY-BexiL2LH.js} +1 -1
  173. package/payload/server/public/assets/{chunk-ENJZ2VHE-8kPcXEQC.js → chunk-ENJZ2VHE-aTklWdJQ.js} +1 -1
  174. package/payload/server/public/assets/{chunk-FMBD7UC4-Bhoeq9sD.js → chunk-FMBD7UC4-svcEBQzs.js} +1 -1
  175. package/payload/server/public/assets/{chunk-FOC6F5B3-BIBpJi8I.js → chunk-FOC6F5B3-CG7R7Xri.js} +1 -1
  176. package/payload/server/public/assets/{chunk-ICPOFSXX-DELXp6fj.js → chunk-ICPOFSXX-CGN7Z4x9.js} +2 -2
  177. package/payload/server/public/assets/{chunk-K5T4RW27-DdckXldP.js → chunk-K5T4RW27-CWBh78jw.js} +1 -1
  178. package/payload/server/public/assets/{chunk-KGLVRYIC-BJhXejKT.js → chunk-KGLVRYIC-Ctiq4q-5.js} +1 -1
  179. package/payload/server/public/assets/{chunk-LIHQZDEY-BSd8nyM2.js → chunk-LIHQZDEY-BII77Q7K.js} +1 -1
  180. package/payload/server/public/assets/{chunk-ORNJ4GCN-CBi55uxq.js → chunk-ORNJ4GCN-DT7R01H8.js} +1 -1
  181. package/payload/server/public/assets/{chunk-OYMX7WX6-Dfbzl8xh.js → chunk-OYMX7WX6-y-Jkbd4C.js} +1 -1
  182. package/payload/server/public/assets/chunk-QZHKN3VN-D9Mwgzti.js +1 -0
  183. package/payload/server/public/assets/{chunk-U2HBQHQK-BN1w8_Cq.js → chunk-U2HBQHQK-DzFo6KbQ.js} +1 -1
  184. package/payload/server/public/assets/{chunk-X2U36JSP-CrRay1NJ.js → chunk-X2U36JSP-CYSwgtLV.js} +1 -1
  185. package/payload/server/public/assets/{chunk-XPW4576I-C_ZE776O.js → chunk-XPW4576I-DHlM4tOn.js} +1 -1
  186. package/payload/server/public/assets/{chunk-YZCP3GAM-CUSlqWBY.js → chunk-YZCP3GAM-B20rTmLl.js} +1 -1
  187. package/payload/server/public/assets/{chunk-ZZ45TVLE-BdPUfSiD.js → chunk-ZZ45TVLE-C7hP4J8m.js} +1 -1
  188. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CIo_TzfF.js +1 -0
  189. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-SzQYvAUZ.js +1 -0
  190. package/payload/server/public/assets/clone-BVjcjsBA.js +1 -0
  191. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-D4E9htTz.js → cose-bilkent-S5V4N54A-nKjTv9sR.js} +1 -1
  192. package/payload/server/public/assets/{dagre-D1B5TQL1.js → dagre-Cx8LiiUZ.js} +1 -1
  193. package/payload/server/public/assets/{dagre-KV5264BT-ByuvYV7N.js → dagre-KV5264BT-BNJYTnls.js} +1 -1
  194. package/payload/server/public/assets/data-BnHcS27X.js +1 -0
  195. package/payload/server/public/assets/{diagram-5BDNPKRD-B-0KduTa.js → diagram-5BDNPKRD-CoAN5_f9.js} +1 -1
  196. package/payload/server/public/assets/{diagram-G4DWMVQ6-CSQmo3eB.js → diagram-G4DWMVQ6-pRmsN4_x.js} +1 -1
  197. package/payload/server/public/assets/{diagram-MMDJMWI5-DK0kWiB3.js → diagram-MMDJMWI5-CRoylyp4.js} +1 -1
  198. package/payload/server/public/assets/{diagram-TYMM5635-CYbK2reZ.js → diagram-TYMM5635-BT3ZtG5b.js} +1 -1
  199. package/payload/server/public/assets/{dist-CADCHk0t.js → dist-CRpLAnCP.js} +1 -1
  200. package/payload/server/public/assets/{erDiagram-SMLLAGMA-C-JQHvJF.js → erDiagram-SMLLAGMA-DSKws1ZV.js} +1 -1
  201. package/payload/server/public/assets/file-download-Hf_UILaA.js +1 -0
  202. package/payload/server/public/assets/{flatten-ROVzlo1u.js → flatten-jn8bZgcI.js} +1 -1
  203. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-OTOd2czg.js → flowDiagram-DWJPFMVM-C2L38ZE5.js} +1 -1
  204. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BWJ778ou.js → ganttDiagram-T4ZO3ILL-Bm2h-vjm.js} +1 -1
  205. package/payload/server/public/assets/gitGraph-7Q5UKJZL-DzQ18i0T.js +1 -0
  206. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CkNcyISe.js → gitGraphDiagram-UUTBAWPF-BoowbF7u.js} +1 -1
  207. package/payload/server/public/assets/graph-klLugHEK.js +51 -0
  208. package/payload/server/public/assets/{graph-labels-BfG6FO25.js → graph-labels-BLx-0vyT.js} +1 -1
  209. package/payload/server/public/assets/{graphlib-8z59Ng6C.js → graphlib-BvT2s_o1.js} +1 -1
  210. package/payload/server/public/assets/info-OMHHGYJF-CwsoaVzV.js +1 -0
  211. package/payload/server/public/assets/infoDiagram-42DDH7IO-ieNsH2bV.js +2 -0
  212. package/payload/server/public/assets/{isEmpty-DXf_sApt.js → isEmpty-Dkk6_L-B.js} +1 -1
  213. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-Cg7pRRGp.js → ishikawaDiagram-UXIWVN3A-nxcmj-IX.js} +1 -1
  214. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CZT_4r_Z.js → journeyDiagram-VCZTEJTY-q5SNIvmS.js} +1 -1
  215. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Dp1Vd5YM.js → kanban-definition-6JOO6SKY-BugG9Q1o.js} +1 -1
  216. package/payload/server/public/assets/{line-UPAcwY66.js → line-MZCQLR-q.js} +1 -1
  217. package/payload/server/public/assets/{linear-BeeahLKw.js → linear-DmQGNk-g.js} +1 -1
  218. package/payload/server/public/assets/{maximize-2-DrBaKD3z.js → maximize-2-CnNQnj_v.js} +1 -1
  219. package/payload/server/public/assets/{mermaid-parser.core-CLKle8df.js → mermaid-parser.core-DvoeqLxw.js} +2 -2
  220. package/payload/server/public/assets/{mermaid.core-CwRj5rL5.js → mermaid.core-BLaw7iG4.js} +3 -3
  221. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CNQUY9UJ.js → mindmap-definition-QFDTVHPH-DMkt10Vc.js} +1 -1
  222. package/payload/server/public/assets/operator-CRcySYv9.js +1 -0
  223. package/payload/server/public/assets/{ordinal-B2r5L1v4.js → ordinal-DuJYM7p1.js} +1 -1
  224. package/payload/server/public/assets/packet-4T2RLAQJ-DxB-bO4L.js +1 -0
  225. package/payload/server/public/assets/page-CVo3CWIY.js +1 -0
  226. package/payload/server/public/assets/page-DPTbZRwl.js +32 -0
  227. package/payload/server/public/assets/{pdf-render-m08Xm2Nm.js → pdf-render-riHufgrn.js} +1 -1
  228. package/payload/server/public/assets/pie-ZZUOXDRM-PSdKvB8-.js +1 -0
  229. package/payload/server/public/assets/{pieDiagram-DEJITSTG-Scnq58FX.js → pieDiagram-DEJITSTG-DRp4lD2B.js} +1 -1
  230. package/payload/server/public/assets/play-yEkd7ouW.js +1 -0
  231. package/payload/server/public/assets/public-Fi6ccYaE.js +1 -0
  232. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-wPfZo_vs.js → quadrantDiagram-34T5L4WZ-DkT63Dn4.js} +1 -1
  233. package/payload/server/public/assets/radar-PYXPWWZC-D8FqRiWq.js +1 -0
  234. package/payload/server/public/assets/{reduce-CFlDlJf5.js → reduce-COyotL2V.js} +1 -1
  235. package/payload/server/public/assets/{requirementDiagram-MS252O5E-yYkH12K2.js → requirementDiagram-MS252O5E-65GGtDkc.js} +1 -1
  236. package/payload/server/public/assets/rotate-ccw-xHksz9mr.js +1 -0
  237. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-fVWRBzzV.js → sankeyDiagram-XADWPNL6-D1vRwLWd.js} +1 -1
  238. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-Dbap3X6h.js → sequenceDiagram-FGHM5R23-Bp47ZSN2.js} +1 -1
  239. package/payload/server/public/assets/square-BZqaxg7D.js +1 -0
  240. package/payload/server/public/assets/{src-Bi0fLV9t.js → src-xN1oULc8.js} +1 -1
  241. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DkPLAqIh.js → stateDiagram-FHFEXIEX-BZHHcP_e.js} +1 -1
  242. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-qVtoGx56.js +1 -0
  243. package/payload/server/public/assets/tasks-COWmfts8.js +1 -0
  244. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DabKBJyd.js → timeline-definition-GMOUNBTQ-DZ1wUyj-.js} +1 -1
  245. package/payload/server/public/assets/treeView-SZITEDCU-i-w4rJmQ.js +1 -0
  246. package/payload/server/public/assets/treemap-W4RFUUIX-Dij6AlAj.js +1 -0
  247. package/payload/server/public/assets/useSubAccountSwitcher-DADvGnr1.js +9 -0
  248. package/payload/server/public/assets/useSubAccountSwitcher-ayajZz8T.css +1 -0
  249. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CaKT7c-c.js → vennDiagram-DHZGUBPP-CttBahsn.js} +1 -1
  250. package/payload/server/public/assets/wardley-RL74JXVD-BJhOQVqW.js +1 -0
  251. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BZ5TTSOL.js → wardleyDiagram-NUSXRM2D-Y5tWieZg.js} +1 -1
  252. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CLfeklJ9.js → xychartDiagram-5P7HB3ND-C78A9qbe.js} +1 -1
  253. package/payload/server/public/browser.html +7 -5
  254. package/payload/server/public/calendar.html +8 -6
  255. package/payload/server/public/chat.html +15 -12
  256. package/payload/server/public/data.html +11 -10
  257. package/payload/server/public/graph.html +12 -10
  258. package/payload/server/public/index.html +16 -14
  259. package/payload/server/public/operator.html +17 -14
  260. package/payload/server/public/public.html +15 -12
  261. package/payload/server/public/tasks.html +18 -0
  262. package/payload/server/server.js +604 -224
  263. package/payload/server/public/assets/AdminShell-Y1fHQApK.js +0 -2
  264. package/payload/server/public/assets/Transcript-DZzFjhoq.js +0 -2
  265. package/payload/server/public/assets/admin-BRBjJEci.js +0 -1
  266. package/payload/server/public/assets/architecture-YZFGNWBL-XiVs-N7Z.js +0 -1
  267. package/payload/server/public/assets/browser-ID7iqIi4.js +0 -1
  268. package/payload/server/public/assets/calendar-BEQPMTtd.js +0 -1
  269. package/payload/server/public/assets/channel-CYBkRz7E.js +0 -1
  270. package/payload/server/public/assets/chat-D0GDSWM-.js +0 -1
  271. package/payload/server/public/assets/chevron-left-A0HYKwGY.js +0 -1
  272. package/payload/server/public/assets/chunk-426QAEUC-CPhOHriU.js +0 -1
  273. package/payload/server/public/assets/chunk-QZHKN3VN-CDnAAZVJ.js +0 -1
  274. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BdXUKVrS.js +0 -1
  275. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DAq-uJr_.js +0 -1
  276. package/payload/server/public/assets/clone-DQl28-jK.js +0 -1
  277. package/payload/server/public/assets/data-CV38dClT.js +0 -1
  278. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BM-KaDZy.js +0 -1
  279. package/payload/server/public/assets/graph-BK0MjKRy.js +0 -51
  280. package/payload/server/public/assets/info-OMHHGYJF-CtZajyAB.js +0 -1
  281. package/payload/server/public/assets/infoDiagram-42DDH7IO-C-_WYlmI.js +0 -2
  282. package/payload/server/public/assets/operator-CnpNyIJ8.js +0 -1
  283. package/payload/server/public/assets/packet-4T2RLAQJ-T-SYedp7.js +0 -1
  284. package/payload/server/public/assets/page-DC_L-IS1.js +0 -32
  285. package/payload/server/public/assets/page-DKHLflh7.js +0 -1
  286. package/payload/server/public/assets/pie-ZZUOXDRM-BWECFVVd.js +0 -1
  287. package/payload/server/public/assets/public-ByUJr48E.js +0 -1
  288. package/payload/server/public/assets/radar-PYXPWWZC-Dx0YUklX.js +0 -1
  289. package/payload/server/public/assets/rotate-ccw-D45TbeAI.js +0 -1
  290. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DceWO1u6.js +0 -1
  291. package/payload/server/public/assets/treeView-SZITEDCU-C3197Rac.js +0 -1
  292. package/payload/server/public/assets/treemap-W4RFUUIX-BPrpx29h.js +0 -1
  293. package/payload/server/public/assets/useSubAccountSwitcher-CCn22f98.css +0 -1
  294. package/payload/server/public/assets/useSubAccountSwitcher-CprHkBnZ.js +0 -9
  295. package/payload/server/public/assets/wardley-RL74JXVD-DW4Jlbhw.js +0 -1
  296. /package/payload/server/public/assets/{_baseFor-BVuIxZJh.js → _baseFor-Bjj9It3Q.js} +0 -0
  297. /package/payload/server/public/assets/{admin-types-hioowVct.js → admin-types-ClHBm0ni.js} +0 -0
  298. /package/payload/server/public/assets/{array-B9UHiPd-.js → array-BrrxEo12.js} +0 -0
  299. /package/payload/server/public/assets/{chunk-CAM3fms7.js → chunk-Ck5AOu5v.js} +0 -0
  300. /package/payload/server/public/assets/{cytoscape.esm-D5_TRwB-.js → cytoscape.esm-CTWJxUxo.js} +0 -0
  301. /package/payload/server/public/assets/{defaultLocale-5eAKkKJC.js → defaultLocale-CFDbRV4k.js} +0 -0
  302. /package/payload/server/public/assets/{init-DlZdxViB.js → init-dXCzGgLP.js} +0 -0
  303. /package/payload/server/public/assets/{katex-Xo0SyWvP.js → katex-CHA1JFYJ.js} +0 -0
  304. /package/payload/server/public/assets/{path-6uRLdFF7.js → path-CCRpdXhK.js} +0 -0
  305. /package/payload/server/public/assets/{preload-helper-CvXuAEud.js → preload-helper-CH6UZRzu.js} +0 -0
  306. /package/payload/server/public/assets/{rough.esm-Djo4Abte.js → rough.esm-Bud4g4fh.js} +0 -0
@@ -5910,8 +5910,8 @@ function webchatTurnTimeoutMs() {
5910
5910
  return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
5911
5911
  }
5912
5912
  function createChatRoutes(deps) {
5913
- const app57 = new Hono();
5914
- app57.post("/", async (c) => {
5913
+ const app61 = new Hono();
5914
+ app61.post("/", async (c) => {
5915
5915
  console.log(`[chat-route] entered route=public method=POST`);
5916
5916
  const contentType = c.req.header("content-type") ?? "";
5917
5917
  const account = resolveAccount();
@@ -6174,7 +6174,7 @@ ${result.result.text}` : result.result.text;
6174
6174
  }
6175
6175
  });
6176
6176
  });
6177
- return app57;
6177
+ return app61;
6178
6178
  }
6179
6179
 
6180
6180
  // app/lib/channel-pty-bridge/admin-session-id.ts
@@ -6189,14 +6189,28 @@ function adminSessionIdFor(accountId, senderId, personId) {
6189
6189
  return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
6190
6190
  }
6191
6191
 
6192
+ // app/lib/channel-pty-bridge/schedule-provenance.ts
6193
+ function parseScheduleProvenance(v) {
6194
+ if (!v || typeof v !== "object") return void 0;
6195
+ const o = v;
6196
+ if (typeof o.accountId !== "string" || typeof o.eventId !== "string" || typeof o.dispatchedAt !== "string") {
6197
+ return void 0;
6198
+ }
6199
+ if (!Array.isArray(o.authoredBy)) return void 0;
6200
+ const authoredBy = o.authoredBy.filter((u) => typeof u === "string" && u.length > 0);
6201
+ const createdByTool = typeof o.createdByTool === "string" && o.createdByTool.length > 0 ? o.createdByTool : null;
6202
+ return { accountId: o.accountId, eventId: o.eventId, authoredBy, createdByTool, dispatchedAt: o.dispatchedAt };
6203
+ }
6204
+
6192
6205
  // server/routes/channel/schedule-inject.ts
6193
6206
  var TAG16 = "[schedule-inject]";
6207
+ 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
6208
  function isLoopbackAddr(addr) {
6195
6209
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
6196
6210
  }
6197
6211
  function createScheduleInjectRoutes(deps) {
6198
- const app57 = new Hono();
6199
- app57.post("/", async (c) => {
6212
+ const app61 = new Hono();
6213
+ app61.post("/", async (c) => {
6200
6214
  const env = c.env;
6201
6215
  const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
6202
6216
  if (!isLoopbackAddr(remoteAddr)) {
@@ -6222,6 +6236,8 @@ function createScheduleInjectRoutes(deps) {
6222
6236
  const destination = typeof body.destination === "string" ? body.destination : "";
6223
6237
  const prompt = typeof body.prompt === "string" ? body.prompt : "";
6224
6238
  const eventId = typeof body.eventId === "string" ? body.eventId : "";
6239
+ const scheduleProvenance = parseScheduleProvenance(body.scheduleProvenance);
6240
+ const overrideSessionId = typeof body.sessionId === "string" && UUID_V4.test(body.sessionId) ? body.sessionId : void 0;
6225
6241
  if (channel !== "whatsapp" && channel !== "telegram" || !destination || !prompt) {
6226
6242
  console.error(`${TAG16} reject reason=bad-request channel=${String(channel)} hasDestination=${Boolean(destination)} hasPrompt=${Boolean(prompt)}`);
6227
6243
  return c.json({ ok: false, error: "schedule-inject-bad-request" }, 400);
@@ -6240,7 +6256,7 @@ function createScheduleInjectRoutes(deps) {
6240
6256
  return c.json({ ok: false, error: "account-manager-unresolved" }, 403);
6241
6257
  }
6242
6258
  console.error(`${TAG16} op=effective-account eventId=${eventId} effectiveAccount=${effectiveAccount2}`);
6243
- const sessionId2 = adminSessionIdFor(effectiveAccount2, destination);
6259
+ const sessionId2 = overrideSessionId ?? adminSessionIdFor(effectiveAccount2, destination);
6244
6260
  const reply2 = (text) => deps.sendWhatsAppText(houseAccountId, destination, text);
6245
6261
  try {
6246
6262
  await deps.waHandleInbound({
@@ -6257,6 +6273,8 @@ function createScheduleInjectRoutes(deps) {
6257
6273
  text: prompt,
6258
6274
  media: [],
6259
6275
  source: "schedule",
6276
+ scheduleProvenance,
6277
+ scheduledSessionId: overrideSessionId,
6260
6278
  reply: reply2
6261
6279
  });
6262
6280
  } catch (err) {
@@ -6274,7 +6292,7 @@ function createScheduleInjectRoutes(deps) {
6274
6292
  return c.json({ ok: false, error: "no-admin-bot-token" }, 400);
6275
6293
  }
6276
6294
  const chatId = Number(destination);
6277
- const sessionId = adminSessionIdFor(effectiveAccount, destination);
6295
+ const sessionId = overrideSessionId ?? adminSessionIdFor(effectiveAccount, destination);
6278
6296
  const reply = (text) => deps.sendTelegramText(botToken, chatId, text);
6279
6297
  try {
6280
6298
  await deps.tgHandleInbound({
@@ -6285,6 +6303,8 @@ function createScheduleInjectRoutes(deps) {
6285
6303
  personId: null,
6286
6304
  text: prompt,
6287
6305
  source: "schedule",
6306
+ scheduleProvenance,
6307
+ scheduledSessionId: overrideSessionId,
6288
6308
  reply
6289
6309
  });
6290
6310
  } catch (err) {
@@ -6294,7 +6314,7 @@ function createScheduleInjectRoutes(deps) {
6294
6314
  console.error(`${TAG16} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
6295
6315
  return c.json({ ok: true }, 200);
6296
6316
  });
6297
- return app57;
6317
+ return app61;
6298
6318
  }
6299
6319
 
6300
6320
  // server/index.ts
@@ -7380,6 +7400,19 @@ function filterConversationsForSubAccount(conversations, managerPhones) {
7380
7400
  return out;
7381
7401
  }
7382
7402
 
7403
+ // app/lib/whatsapp/authorize-recall-read.ts
7404
+ function authorizeRecallRead(input) {
7405
+ const { requestedAccountId } = input;
7406
+ const callerAccountId = input.callerAccountId && input.callerAccountId.length > 0 ? input.callerAccountId : null;
7407
+ const houseAdminScope = input.houseAdminScope && input.houseAdminScope.length > 0 ? input.houseAdminScope : null;
7408
+ if (houseAdminScope) return { authorized: true };
7409
+ if (callerAccountId && requestedAccountId === callerAccountId) return { authorized: true };
7410
+ return {
7411
+ authorized: false,
7412
+ reason: `Not authorized to read WhatsApp history for account "${requestedAccountId}". This session may only read its own account.`
7413
+ };
7414
+ }
7415
+
7383
7416
  // server/routes/whatsapp.ts
7384
7417
  var TAG21 = "[whatsapp:api]";
7385
7418
  var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT || "";
@@ -7401,6 +7434,14 @@ function projectionFor(requestedAccountId) {
7401
7434
  houseAccountManagers
7402
7435
  });
7403
7436
  }
7437
+ function callerScopeDenial(c, requestedAccountId) {
7438
+ const callerAccountId = c.req.header("x-maxy-caller-account")?.trim() || null;
7439
+ const houseAdminScope = c.req.header("x-maxy-house-admin-scope")?.trim() || null;
7440
+ const decision = authorizeRecallRead({ requestedAccountId, callerAccountId, houseAdminScope });
7441
+ if (decision.authorized) return null;
7442
+ console.error(`[whatsapp-read-tool] op=authz-deny requested=${requestedAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
7443
+ return c.json({ error: decision.reason }, 403);
7444
+ }
7404
7445
  var app2 = new Hono();
7405
7446
  app2.get("/status", (c) => {
7406
7447
  try {
@@ -7705,6 +7746,8 @@ app2.get("/activity", (c) => {
7705
7746
  app2.get("/conversations", (c) => {
7706
7747
  try {
7707
7748
  const accountId = validateAccountId(c.req.query("accountId") ?? null);
7749
+ const denial = callerScopeDenial(c, accountId);
7750
+ if (denial) return denial;
7708
7751
  const jids = listConversationJids(accountId);
7709
7752
  const conversations = jids.map((jid) => {
7710
7753
  const messages = getMessages(accountId, jid);
@@ -7727,6 +7770,8 @@ app2.get("/conversations", (c) => {
7727
7770
  app2.get("/messages", (c) => {
7728
7771
  try {
7729
7772
  const accountId = validateAccountId(c.req.query("accountId") ?? null);
7773
+ const denial = callerScopeDenial(c, accountId);
7774
+ if (denial) return denial;
7730
7775
  const jid = c.req.query("jid");
7731
7776
  if (!jid) {
7732
7777
  return c.json({ error: "Missing required parameter: jid" }, 400);
@@ -7748,6 +7793,8 @@ app2.get("/conversation-graph-state", async (c) => {
7748
7793
  const jid = c.req.query("jid");
7749
7794
  const accountIdQuery = c.req.query("accountId");
7750
7795
  const t0 = Date.now();
7796
+ const denial = callerScopeDenial(c, validateAccountId(accountIdQuery ?? null));
7797
+ if (denial) return denial;
7751
7798
  if (!directCacheKey && !jid) {
7752
7799
  const requestedAccountId = validateAccountId(accountIdQuery ?? null);
7753
7800
  const projection2 = projectionFor(requestedAccountId);
@@ -9942,8 +9989,8 @@ async function reapplyLeversViaManager() {
9942
9989
  var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
9943
9990
  var sendSeq = 0;
9944
9991
  function createWebchatRoutes(deps) {
9945
- const app57 = new Hono();
9946
- app57.post("/send", requireAdminSession, async (c) => {
9992
+ const app61 = new Hono();
9993
+ app61.post("/send", requireAdminSession, async (c) => {
9947
9994
  let accountId;
9948
9995
  try {
9949
9996
  accountId = resolvePlatformAccountId();
@@ -10143,7 +10190,7 @@ ${note}` : note;
10143
10190
  if (turnTimer.unref) turnTimer.unref();
10144
10191
  return c.json({ ok: true });
10145
10192
  });
10146
- app57.post("/interrupt", requireAdminSession, async (c) => {
10193
+ app61.post("/interrupt", requireAdminSession, async (c) => {
10147
10194
  const cacheKey = c.get("cacheKey");
10148
10195
  const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
10149
10196
  const primaryUserId = resolvePrimaryAdminUserId();
@@ -10171,7 +10218,7 @@ ${note}` : note;
10171
10218
  }
10172
10219
  return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
10173
10220
  });
10174
- app57.post("/settings", requireAdminSession, async (c) => {
10221
+ app61.post("/settings", requireAdminSession, async (c) => {
10175
10222
  const body = await c.req.json().catch(() => null);
10176
10223
  const op = body?.op;
10177
10224
  const value = body?.value;
@@ -10211,7 +10258,7 @@ ${note}` : note;
10211
10258
  console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
10212
10259
  return c.json({ ok: true, settingsApplied });
10213
10260
  });
10214
- app57.get("/session", requireAdminSession, async (c) => {
10261
+ app61.get("/session", requireAdminSession, async (c) => {
10215
10262
  let accountId;
10216
10263
  try {
10217
10264
  accountId = resolvePlatformAccountId();
@@ -10289,7 +10336,7 @@ ${note}` : note;
10289
10336
  const indicators = await fetchComposerIndicators(sessionId);
10290
10337
  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
10338
  });
10292
- app57.post("/permission-verdict", requireAdminSession, async (c) => {
10339
+ app61.post("/permission-verdict", requireAdminSession, async (c) => {
10293
10340
  const body = await c.req.json().catch(() => null);
10294
10341
  const sessionId = body?.sessionId;
10295
10342
  const requestId = body?.request_id;
@@ -10306,7 +10353,7 @@ ${note}` : note;
10306
10353
  const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
10307
10354
  return c.json({ ok });
10308
10355
  });
10309
- return app57;
10356
+ return app61;
10310
10357
  }
10311
10358
 
10312
10359
  // server/routes/webchat-greeting.ts
@@ -13343,18 +13390,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
13343
13390
  ]);
13344
13391
  var app20 = new Hono();
13345
13392
  app20.post("/", async (c) => {
13346
- const TAG39 = "[admin:events]";
13393
+ const TAG44 = "[admin:events]";
13347
13394
  let body;
13348
13395
  try {
13349
13396
  body = await c.req.json();
13350
13397
  } catch (err) {
13351
13398
  const detail = err instanceof Error ? err.message : String(err);
13352
- console.error(`${TAG39} reject reason=body-not-json detail=${detail}`);
13399
+ console.error(`${TAG44} reject reason=body-not-json detail=${detail}`);
13353
13400
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
13354
13401
  }
13355
13402
  const event = typeof body.event === "string" ? body.event : "";
13356
13403
  if (!ALLOWED_EVENTS.has(event)) {
13357
- console.error(`${TAG39} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
13404
+ console.error(`${TAG44} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
13358
13405
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
13359
13406
  }
13360
13407
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -19289,52 +19336,307 @@ app45.get("/booking-link", requireAdminSession, (c) => {
19289
19336
  });
19290
19337
  var calendar_default = app45;
19291
19338
 
19292
- // server/routes/admin/index.ts
19339
+ // app/lib/time-entry-format.ts
19340
+ function secondsBetween(startIso, endIso) {
19341
+ const s = Date.parse(startIso);
19342
+ const e = Date.parse(endIso);
19343
+ if (!Number.isFinite(s) || !Number.isFinite(e)) return 0;
19344
+ return Math.max(0, Math.round((e - s) / 1e3));
19345
+ }
19346
+ function toNum(v) {
19347
+ if (v == null) return 0;
19348
+ if (typeof v === "number") return v;
19349
+ if (typeof v === "object" && typeof v.toNumber === "function") {
19350
+ return v.toNumber();
19351
+ }
19352
+ const n = Number(v);
19353
+ return Number.isFinite(n) ? n : 0;
19354
+ }
19355
+
19356
+ // server/routes/admin/tasks-list.ts
19357
+ var TAG33 = "[task-timer]";
19358
+ var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
19359
+ var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
19293
19360
  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;
19361
+ app46.get("/", requireAdminSession, async (c) => {
19362
+ const cacheKey = c.var.cacheKey;
19363
+ const accountId = getAccountIdForSession(cacheKey);
19364
+ if (!accountId) {
19365
+ console.error(`${TAG33} op=list auth-rejected reason="no account for session"`);
19366
+ return c.json({ error: "Account not found for session" }, 401);
19367
+ }
19368
+ const session = getSession();
19369
+ try {
19370
+ const result = await session.run(
19371
+ `MATCH (t:Task {accountId: $accountId})
19372
+ OPTIONAL MATCH (te:TimeEntry {taskId: t.taskId, accountId: $accountId})
19373
+ WHERE te.endedAt IS NULL
19374
+ WITH t, te ORDER BY te.startedAt
19375
+ WITH t, head(collect(te)) AS openTe
19376
+ RETURN t.taskId AS taskId, t.name AS name, t.clientName AS clientName,
19377
+ t.propertyAddress AS propertyAddress, t.fee AS fee, t.status AS status,
19378
+ coalesce(t.secondsLogged, 0) AS secondsLogged,
19379
+ openTe.startedAt AS runningStartedAt
19380
+ ORDER BY t.createdAt DESC`,
19381
+ { accountId }
19382
+ );
19383
+ const open = [];
19384
+ const completed = [];
19385
+ for (const rec of result.records) {
19386
+ const status = rec.get("status") ?? "pending";
19387
+ const runningStartedAt = rec.get("runningStartedAt") ?? null;
19388
+ const fee = rec.get("fee");
19389
+ const row = {
19390
+ taskId: rec.get("taskId"),
19391
+ name: rec.get("name") ?? "",
19392
+ clientName: rec.get("clientName") ?? null,
19393
+ propertyAddress: rec.get("propertyAddress") ?? null,
19394
+ fee: fee == null ? null : toNum(fee),
19395
+ status,
19396
+ secondsLogged: toNum(rec.get("secondsLogged")),
19397
+ running: runningStartedAt !== null,
19398
+ runningStartedAt
19399
+ };
19400
+ if (COMPLETED.has(status)) completed.push(row);
19401
+ else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
19402
+ }
19403
+ console.log(`${TAG33} op=list account=${accountId} open=${open.length} completed=${completed.length}`);
19404
+ return c.json({ open, completed });
19405
+ } catch (err) {
19406
+ console.error(`${TAG33} op=list error="${err instanceof Error ? err.message : String(err)}"`);
19407
+ return c.json({ error: "tasks-list-failed" }, 500);
19408
+ } finally {
19409
+ await session.close();
19410
+ }
19411
+ });
19412
+ var tasks_list_default = app46;
19413
+
19414
+ // server/routes/admin/task-timer-start.ts
19415
+ import { randomUUID as randomUUID13 } from "crypto";
19416
+ import neo4j5 from "neo4j-driver";
19417
+ var TAG34 = "[task-timer]";
19418
+ var app47 = new Hono();
19419
+ app47.post("/", requireAdminSession, async (c) => {
19420
+ const cacheKey = c.var.cacheKey;
19421
+ const accountId = getAccountIdForSession(cacheKey);
19422
+ if (!accountId) return c.json({ error: "Account not found for session" }, 401);
19423
+ let body;
19424
+ try {
19425
+ body = await c.req.json();
19426
+ } catch {
19427
+ return c.json({ error: "invalid-json" }, 400);
19428
+ }
19429
+ const taskId = typeof body.taskId === "string" ? body.taskId : "";
19430
+ if (!taskId) return c.json({ error: "taskId required" }, 400);
19431
+ const now = (/* @__PURE__ */ new Date()).toISOString();
19432
+ const session = getSession();
19433
+ try {
19434
+ const target = await session.run(
19435
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId}) RETURN t.taskId AS taskId LIMIT 1`,
19436
+ { taskId, accountId }
19437
+ );
19438
+ if (target.records.length === 0) {
19439
+ console.error(`${TAG34} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
19440
+ return c.json({ error: "task-not-found" }, 404);
19441
+ }
19442
+ const open = await session.run(
19443
+ `MATCH (te:TimeEntry {accountId: $accountId}) WHERE te.endedAt IS NULL
19444
+ RETURN te.entryId AS entryId, te.taskId AS taskId, te.startedAt AS startedAt
19445
+ ORDER BY te.startedAt LIMIT 1`,
19446
+ { accountId }
19447
+ );
19448
+ const priorEntryId = open.records[0]?.get("entryId");
19449
+ const priorTaskId = open.records[0]?.get("taskId");
19450
+ const priorStartedAt = open.records[0]?.get("startedAt");
19451
+ console.log(`${TAG34} op=start taskId=${taskId} accountId=${accountId} priorOpen=${priorTaskId ?? "none"}`);
19452
+ if (priorEntryId && priorTaskId === taskId) {
19453
+ return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
19454
+ }
19455
+ if (priorEntryId && priorStartedAt && priorTaskId) {
19456
+ const seconds = secondsBetween(priorStartedAt, now);
19457
+ await session.run(
19458
+ `MATCH (te:TimeEntry {entryId: $priorEntryId}) WHERE te.endedAt IS NULL
19459
+ SET te.endedAt = $now, te.seconds = $seconds
19460
+ WITH te
19461
+ MATCH (t:Task {taskId: $priorTaskId, accountId: $accountId})
19462
+ SET t.secondsLogged = coalesce(t.secondsLogged, 0) + $seconds`,
19463
+ { priorEntryId, priorTaskId, accountId, now, seconds: neo4j5.int(seconds) }
19464
+ );
19465
+ console.log(`${TAG34} op=autostop taskId=${priorTaskId} entryId=${priorEntryId} seconds=${seconds}`);
19466
+ }
19467
+ const entryId = randomUUID13();
19468
+ await session.run(
19469
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19470
+ CREATE (te:TimeEntry {entryId: $entryId, taskId: $taskId, accountId: $accountId, startedAt: $now, endedAt: null})
19471
+ CREATE (te)-[:LOGGED_AGAINST]->(t)`,
19472
+ { taskId, accountId, entryId, now }
19473
+ );
19474
+ console.log(`${TAG34} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
19475
+ return c.json({ ok: true, running: true, entryId, startedAt: now });
19476
+ } catch (err) {
19477
+ console.error(`${TAG34} op=start error="${err instanceof Error ? err.message : String(err)}"`);
19478
+ return c.json({ error: "task-timer-start-failed" }, 500);
19479
+ } finally {
19480
+ await session.close();
19481
+ }
19482
+ });
19483
+ var task_timer_start_default = app47;
19484
+
19485
+ // server/routes/admin/task-timer-stop.ts
19486
+ import neo4j6 from "neo4j-driver";
19487
+ var TAG35 = "[task-timer]";
19488
+ var app48 = new Hono();
19489
+ app48.post("/", requireAdminSession, async (c) => {
19490
+ const cacheKey = c.var.cacheKey;
19491
+ const accountId = getAccountIdForSession(cacheKey);
19492
+ if (!accountId) return c.json({ error: "Account not found for session" }, 401);
19493
+ let body;
19494
+ try {
19495
+ body = await c.req.json();
19496
+ } catch {
19497
+ return c.json({ error: "invalid-json" }, 400);
19498
+ }
19499
+ const taskId = typeof body.taskId === "string" ? body.taskId : "";
19500
+ if (!taskId) return c.json({ error: "taskId required" }, 400);
19501
+ const now = (/* @__PURE__ */ new Date()).toISOString();
19502
+ const session = getSession();
19503
+ try {
19504
+ const open = await session.run(
19505
+ `MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NULL
19506
+ RETURN te.entryId AS entryId, te.startedAt AS startedAt
19507
+ ORDER BY te.startedAt LIMIT 1`,
19508
+ { taskId, accountId }
19509
+ );
19510
+ const entryId = open.records[0]?.get("entryId");
19511
+ const startedAt = open.records[0]?.get("startedAt");
19512
+ if (!entryId || !startedAt) {
19513
+ const cur = await session.run(
19514
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19515
+ RETURN coalesce(t.secondsLogged, 0) AS secondsLogged`,
19516
+ { taskId, accountId }
19517
+ );
19518
+ const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
19519
+ console.log(`${TAG35} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
19520
+ return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
19521
+ }
19522
+ const seconds = secondsBetween(startedAt, now);
19523
+ await session.run(
19524
+ `MATCH (te:TimeEntry {entryId: $entryId}) WHERE te.endedAt IS NULL
19525
+ SET te.endedAt = $now, te.seconds = $seconds
19526
+ WITH te
19527
+ MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19528
+ SET t.secondsLogged = coalesce(t.secondsLogged, 0) + $seconds`,
19529
+ { entryId, taskId, accountId, now, seconds: neo4j6.int(seconds) }
19530
+ );
19531
+ const verify = await session.run(
19532
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19533
+ OPTIONAL MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NOT NULL
19534
+ RETURN coalesce(sum(te.seconds), 0) AS sumEntries, coalesce(t.secondsLogged, 0) AS secondsLogged`,
19535
+ { taskId, accountId }
19536
+ );
19537
+ const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
19538
+ const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
19539
+ console.log(`${TAG35} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
19540
+ console.log(`${TAG35} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} secondsLogged=${secondsLogged}`);
19541
+ return c.json({ ok: true, running: false, seconds, secondsLogged });
19542
+ } catch (err) {
19543
+ console.error(`${TAG35} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
19544
+ return c.json({ error: "task-timer-stop-failed" }, 500);
19545
+ } finally {
19546
+ await session.close();
19547
+ }
19548
+ });
19549
+ var task_timer_stop_default = app48;
19550
+
19551
+ // server/routes/admin/task-complete.ts
19552
+ var TAG36 = "[task-timer]";
19553
+ var app49 = new Hono();
19554
+ app49.post("/", requireAdminSession, async (c) => {
19555
+ const cacheKey = c.var.cacheKey;
19556
+ const accountId = getAccountIdForSession(cacheKey);
19557
+ if (!accountId) return c.json({ error: "Account not found for session" }, 401);
19558
+ let body;
19559
+ try {
19560
+ body = await c.req.json();
19561
+ } catch {
19562
+ return c.json({ error: "invalid-json" }, 400);
19563
+ }
19564
+ const taskId = typeof body.taskId === "string" ? body.taskId : "";
19565
+ if (!taskId) return c.json({ error: "taskId required" }, 400);
19566
+ const now = (/* @__PURE__ */ new Date()).toISOString();
19567
+ const session = getSession();
19568
+ try {
19569
+ const result = await session.run(
19570
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
19571
+ SET t.status = 'completed', t.updatedAt = $now
19572
+ RETURN t.taskId AS taskId, coalesce(t.secondsLogged, 0) AS secondsLogged`,
19573
+ { taskId, accountId, now }
19574
+ );
19575
+ if (result.records.length === 0) {
19576
+ return c.json({ error: "task-not-found" }, 404);
19577
+ }
19578
+ const secondsLogged = toNum(result.records[0].get("secondsLogged"));
19579
+ console.log(`${TAG36} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
19580
+ return c.json({ ok: true, status: "completed", secondsLogged });
19581
+ } catch (err) {
19582
+ console.error(`${TAG36} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
19583
+ return c.json({ error: "task-complete-failed" }, 500);
19584
+ } finally {
19585
+ await session.close();
19586
+ }
19587
+ });
19588
+ var task_complete_default = app49;
19589
+
19590
+ // server/routes/admin/index.ts
19591
+ var app50 = new Hono();
19592
+ app50.route("/session", session_default);
19593
+ app50.route("/accounts", accounts_default);
19594
+ app50.route("/logs", logs_default);
19595
+ app50.route("/claude-info", claude_info_default);
19596
+ app50.route("/attachment", attachment_default);
19597
+ app50.route("/agents", agents_default);
19598
+ app50.route("/sessions", sessions_default);
19599
+ app50.route("/claude-sessions", claude_sessions_default);
19600
+ app50.route("/log-ingest", log_ingest_default);
19601
+ app50.route("/events", events_default);
19602
+ app50.route("/files", files_default);
19603
+ app50.route("/graph-search", graph_search_default);
19604
+ app50.route("/graph-subgraph", graph_subgraph_default);
19605
+ app50.route("/graph-delete", graph_delete_default);
19606
+ app50.route("/graph-restore", graph_restore_default);
19607
+ app50.route("/graph-labels-in-graph", graph_labels_in_graph_default);
19608
+ app50.route("/graph-default-view", graph_default_view_default);
19609
+ app50.route("/sidebar-artefacts", sidebar_artefacts_default);
19610
+ app50.route("/sidebar-sessions", sidebar_sessions_default);
19611
+ app50.route("/session-delete", session_delete_default);
19612
+ app50.route("/session-stop", session_stop_default);
19613
+ app50.route("/session-archive", session_archive_default);
19614
+ app50.route("/session-rename", session_rename_default);
19615
+ app50.route("/session-usage", session_usage_default);
19616
+ app50.route("/browser", browser_default);
19617
+ app50.route("/session-rc-spawn", session_rc_spawn_default);
19618
+ app50.route("/session-reseat", session_reseat_default);
19619
+ app50.route("/system-stats", system_stats_default);
19620
+ app50.route("/health-brand", health_default2);
19621
+ app50.route("/linkedin-ingest", linkedin_ingest_default);
19622
+ app50.route("/post-turn-context", post_turn_context_default);
19623
+ app50.route("/public-session-context", public_session_context_default);
19624
+ app50.route("/public-session-exit", public_session_exit_default);
19625
+ app50.route("/access-session-evict", access_session_evict_default);
19626
+ app50.route("/enrol-person", enrol_person_default);
19627
+ app50.route("/calendar", calendar_default);
19628
+ app50.route("/tasks-list", tasks_list_default);
19629
+ app50.route("/task-timer-start", task_timer_start_default);
19630
+ app50.route("/task-timer-stop", task_timer_stop_default);
19631
+ app50.route("/task-complete", task_complete_default);
19632
+ var admin_default = app50;
19331
19633
 
19332
19634
  // server/routes/access/verify-token.ts
19333
- var TAG33 = "[access-verify]";
19635
+ var TAG37 = "[access-verify]";
19334
19636
  var MINT_TAG = "[access-session-mint]";
19335
19637
  var COOKIE_NAME = "__access_session";
19336
- var app47 = new Hono();
19337
- app47.post("/", async (c) => {
19638
+ var app51 = new Hono();
19639
+ app51.post("/", async (c) => {
19338
19640
  const ip = c.var.clientIp || "unknown";
19339
19641
  let body;
19340
19642
  try {
@@ -19349,39 +19651,39 @@ app47.post("/", async (c) => {
19349
19651
  }
19350
19652
  const rateMsg = checkAccessRateLimit(ip, agentSlug);
19351
19653
  if (rateMsg) {
19352
- console.error(`${TAG33} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
19654
+ console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
19353
19655
  return c.json({ error: rateMsg }, 429);
19354
19656
  }
19355
19657
  const grant = await findGrantByMagicToken(token);
19356
19658
  if (!grant) {
19357
19659
  recordAccessFailedAttempt(ip, agentSlug);
19358
- console.error(`${TAG33} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
19660
+ console.error(`${TAG37} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
19359
19661
  return c.json({ error: "invalid-or-expired-link" }, 401);
19360
19662
  }
19361
19663
  if (grant.agentSlug !== agentSlug) {
19362
19664
  recordAccessFailedAttempt(ip, agentSlug);
19363
19665
  console.error(
19364
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
19666
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
19365
19667
  );
19366
19668
  return c.json({ error: "invalid-or-expired-link" }, 401);
19367
19669
  }
19368
19670
  if (grant.status === "expired" || grant.status === "revoked") {
19369
19671
  recordAccessFailedAttempt(ip, agentSlug);
19370
19672
  console.error(
19371
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
19673
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
19372
19674
  );
19373
19675
  return c.json({ error: "access-no-longer-valid" }, 401);
19374
19676
  }
19375
19677
  if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
19376
19678
  recordAccessFailedAttempt(ip, agentSlug);
19377
19679
  console.error(
19378
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
19680
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
19379
19681
  );
19380
19682
  return c.json({ error: "access-no-longer-valid" }, 401);
19381
19683
  }
19382
19684
  if (!grant.sliceToken) {
19383
19685
  console.error(
19384
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
19686
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
19385
19687
  );
19386
19688
  return c.json({ error: "grant-misconfigured" }, 500);
19387
19689
  }
@@ -19397,12 +19699,12 @@ app47.post("/", async (c) => {
19397
19699
  await consumeMagicTokenAndActivate(grant.grantId);
19398
19700
  } catch (err) {
19399
19701
  console.error(
19400
- `${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
19702
+ `${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
19401
19703
  );
19402
19704
  return c.json({ error: "verification-failed" }, 500);
19403
19705
  }
19404
19706
  clearAccessRateLimit(ip, agentSlug);
19405
- console.log(`${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
19707
+ console.log(`${TAG37} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
19406
19708
  console.log(
19407
19709
  `${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
19408
19710
  );
@@ -19416,7 +19718,7 @@ app47.post("/", async (c) => {
19416
19718
  displayName: grant.displayName
19417
19719
  });
19418
19720
  });
19419
- var verify_token_default = app47;
19721
+ var verify_token_default = app51;
19420
19722
 
19421
19723
  // app/lib/access-email.ts
19422
19724
  import { spawn as spawn2 } from "child_process";
@@ -19478,10 +19780,10 @@ async function sendMagicLinkEmail(payload) {
19478
19780
  }
19479
19781
 
19480
19782
  // server/routes/access/request-magic-link.ts
19481
- var TAG34 = "[access-request-link]";
19482
- var app48 = new Hono();
19783
+ var TAG38 = "[access-request-link]";
19784
+ var app52 = new Hono();
19483
19785
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
19484
- app48.post("/", async (c) => {
19786
+ app52.post("/", async (c) => {
19485
19787
  let body;
19486
19788
  try {
19487
19789
  body = await c.req.json();
@@ -19495,18 +19797,18 @@ app48.post("/", async (c) => {
19495
19797
  }
19496
19798
  const rateMsg = checkRequestLinkRateLimit(contactValue);
19497
19799
  if (rateMsg) {
19498
- console.error(`${TAG34} contactValue=${maskContact(contactValue)} result=rate-limited`);
19800
+ console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=rate-limited`);
19499
19801
  return c.json({ error: rateMsg }, 429);
19500
19802
  }
19501
19803
  recordRequestLinkAttempt(contactValue);
19502
19804
  const accountId = process.env.ACCOUNT_ID ?? "";
19503
19805
  if (!accountId) {
19504
- console.error(`${TAG34} contactValue=${maskContact(contactValue)} result=no-account-id`);
19806
+ console.error(`${TAG38} contactValue=${maskContact(contactValue)} result=no-account-id`);
19505
19807
  return c.json({ message: VISITOR_MESSAGE }, 200);
19506
19808
  }
19507
19809
  const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
19508
19810
  if (!grant) {
19509
- console.log(`${TAG34} contactValue=${maskContact(contactValue)} result=notfound`);
19811
+ console.log(`${TAG38} contactValue=${maskContact(contactValue)} result=notfound`);
19510
19812
  return c.json({ message: VISITOR_MESSAGE }, 200);
19511
19813
  }
19512
19814
  let token;
@@ -19514,7 +19816,7 @@ app48.post("/", async (c) => {
19514
19816
  token = await generateNewMagicToken(grant.grantId);
19515
19817
  } catch (err) {
19516
19818
  console.error(
19517
- `${TAG34} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
19819
+ `${TAG38} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
19518
19820
  );
19519
19821
  return c.json({ message: VISITOR_MESSAGE }, 200);
19520
19822
  }
@@ -19546,22 +19848,22 @@ app48.post("/", async (c) => {
19546
19848
  });
19547
19849
  if (!sendResult.ok) {
19548
19850
  console.error(
19549
- `${TAG34} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
19851
+ `${TAG38} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
19550
19852
  );
19551
19853
  return c.json({ message: VISITOR_MESSAGE }, 200);
19552
19854
  }
19553
19855
  console.log(
19554
- `${TAG34} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
19856
+ `${TAG38} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
19555
19857
  );
19556
19858
  return c.json({ message: VISITOR_MESSAGE }, 200);
19557
19859
  });
19558
- var request_magic_link_default = app48;
19860
+ var request_magic_link_default = app52;
19559
19861
 
19560
19862
  // 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;
19863
+ var app53 = new Hono();
19864
+ app53.route("/verify-token", verify_token_default);
19865
+ app53.route("/request-magic-link", request_magic_link_default);
19866
+ var access_default = app53;
19565
19867
 
19566
19868
  // server/routes/sites.ts
19567
19869
  import { existsSync as existsSync28, readFileSync as readFileSync31, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
@@ -19596,8 +19898,8 @@ function getExt(p) {
19596
19898
  if (idx < p.lastIndexOf("/")) return "";
19597
19899
  return p.slice(idx).toLowerCase();
19598
19900
  }
19599
- var app50 = new Hono();
19600
- app50.get("/:rel{.*}", (c) => {
19901
+ var app54 = new Hono();
19902
+ app54.get("/:rel{.*}", (c) => {
19601
19903
  const reqPath = c.req.path;
19602
19904
  const rawRel = c.req.param("rel") ?? "";
19603
19905
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -19700,7 +20002,7 @@ app50.get("/:rel{.*}", (c) => {
19700
20002
  "X-Content-Type-Options": "nosniff"
19701
20003
  });
19702
20004
  });
19703
- var sites_default = app50;
20005
+ var sites_default = app54;
19704
20006
 
19705
20007
  // app/lib/visitor-token.ts
19706
20008
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
@@ -19800,7 +20102,7 @@ function readBrandConfig() {
19800
20102
  }
19801
20103
 
19802
20104
  // server/routes/visitor-consent.ts
19803
- var app51 = new Hono();
20105
+ var app55 = new Hono();
19804
20106
  var CONSENT_COOKIE_NAME = "mxy_consent";
19805
20107
  var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
19806
20108
  var DEFAULT_CONSENT_COPY = {
@@ -19845,17 +20147,17 @@ function siteSlugFromReferer(referer) {
19845
20147
  return "";
19846
20148
  }
19847
20149
  }
19848
- app51.options("/consent", (c) => {
20150
+ app55.options("/consent", (c) => {
19849
20151
  const origin = getOrigin(c);
19850
20152
  setCorsHeaders(c, origin);
19851
20153
  return c.body(null, 204);
19852
20154
  });
19853
- app51.options("/brand-config", (c) => {
20155
+ app55.options("/brand-config", (c) => {
19854
20156
  const origin = getOrigin(c);
19855
20157
  setCorsHeaders(c, origin);
19856
20158
  return c.body(null, 204);
19857
20159
  });
19858
- app51.post("/consent", async (c) => {
20160
+ app55.post("/consent", async (c) => {
19859
20161
  const origin = getOrigin(c);
19860
20162
  setCorsHeaders(c, origin);
19861
20163
  let raw;
@@ -19895,7 +20197,7 @@ app51.post("/consent", async (c) => {
19895
20197
  console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
19896
20198
  return c.body(null, 204);
19897
20199
  });
19898
- app51.get("/brand-config", (c) => {
20200
+ app55.get("/brand-config", (c) => {
19899
20201
  const origin = getOrigin(c);
19900
20202
  setCorsHeaders(c, origin);
19901
20203
  const brand = readBrandConfig();
@@ -19905,7 +20207,7 @@ app51.get("/brand-config", (c) => {
19905
20207
  c.header("Cache-Control", "public, max-age=300");
19906
20208
  return c.json({ consent: { copy, palette } });
19907
20209
  });
19908
- var visitor_consent_default = app51;
20210
+ var visitor_consent_default = app55;
19909
20211
 
19910
20212
  // server/routes/listings.ts
19911
20213
  function getCookie(headerValue, name) {
@@ -19932,8 +20234,8 @@ function appendConsentParams(pageUrl, token) {
19932
20234
  }
19933
20235
  var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
19934
20236
  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) => {
20237
+ var app56 = new Hono();
20238
+ app56.get("/:slug/click", async (c) => {
19937
20239
  const slug = c.req.param("slug") ?? "";
19938
20240
  const rawSession = c.req.query("session") ?? "";
19939
20241
  const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
@@ -19997,10 +20299,10 @@ app52.get("/:slug/click", async (c) => {
19997
20299
  console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
19998
20300
  return c.redirect(redirectUrl, 302);
19999
20301
  });
20000
- var listings_default = app52;
20302
+ var listings_default = app56;
20001
20303
 
20002
20304
  // server/routes/visitor-event.ts
20003
- var app53 = new Hono();
20305
+ var app57 = new Hono();
20004
20306
  var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
20005
20307
  var buckets = /* @__PURE__ */ new Map();
20006
20308
  var RATE_LIMIT = 60;
@@ -20067,12 +20369,12 @@ function originAllowed(origin, allowlist) {
20067
20369
  return false;
20068
20370
  }
20069
20371
  }
20070
- app53.options("/event", (c) => {
20372
+ app57.options("/event", (c) => {
20071
20373
  const origin = getOrigin2(c);
20072
20374
  setCorsHeaders2(c, origin);
20073
20375
  return c.body(null, 204);
20074
20376
  });
20075
- app53.post("/event", async (c) => {
20377
+ app57.post("/event", async (c) => {
20076
20378
  const origin = getOrigin2(c);
20077
20379
  setCorsHeaders2(c, origin);
20078
20380
  const ua = c.req.header("user-agent") ?? "";
@@ -20277,7 +20579,7 @@ async function writeEvent(opts) {
20277
20579
  );
20278
20580
  }
20279
20581
  }
20280
- var visitor_event_default = app53;
20582
+ var visitor_event_default = app57;
20281
20583
 
20282
20584
  // server/routes/session.ts
20283
20585
  import { resolve as resolve27 } from "path";
@@ -20323,8 +20625,8 @@ function withVisitorCookie(response, visitorId) {
20323
20625
  headers
20324
20626
  });
20325
20627
  }
20326
- var app54 = new Hono();
20327
- app54.post("/", async (c) => {
20628
+ var app58 = new Hono();
20629
+ app58.post("/", async (c) => {
20328
20630
  let body;
20329
20631
  try {
20330
20632
  body = await c.req.json();
@@ -20471,7 +20773,7 @@ app54.post("/", async (c) => {
20471
20773
  newVisitorId
20472
20774
  );
20473
20775
  });
20474
- var session_default2 = app54;
20776
+ var session_default2 = app58;
20475
20777
 
20476
20778
  // server/lib/calendar-slots.ts
20477
20779
  var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
@@ -20554,17 +20856,17 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
20554
20856
  }
20555
20857
 
20556
20858
  // server/routes/calendar-public.ts
20557
- var app55 = new Hono();
20859
+ var app59 = new Hono();
20558
20860
  function setCors(c) {
20559
20861
  c.header("Access-Control-Allow-Origin", "*");
20560
20862
  c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
20561
20863
  c.header("Access-Control-Allow-Headers", "content-type");
20562
20864
  }
20563
- app55.options("/free-busy", (c) => {
20865
+ app59.options("/free-busy", (c) => {
20564
20866
  setCors(c);
20565
20867
  return c.body(null, 204);
20566
20868
  });
20567
- app55.get("/free-busy", async (c) => {
20869
+ app59.get("/free-busy", async (c) => {
20568
20870
  setCors(c);
20569
20871
  const from = c.req.query("from");
20570
20872
  const to = c.req.query("to");
@@ -20606,7 +20908,79 @@ app55.get("/free-busy", async (c) => {
20606
20908
  await session.close();
20607
20909
  }
20608
20910
  });
20609
- var calendar_public_default = app55;
20911
+ var calendar_public_default = app59;
20912
+
20913
+ // app/lib/timeentry-census.ts
20914
+ var TAG39 = "[timeentry-census]";
20915
+ function reconcileTimeEntries(rows, now, horizonMs) {
20916
+ const openEntries = rows.openEntries.length;
20917
+ let oldestOpenAgeMs = 0;
20918
+ const perAccount = /* @__PURE__ */ new Map();
20919
+ for (const e of rows.openEntries) {
20920
+ oldestOpenAgeMs = Math.max(oldestOpenAgeMs, now - e.startedAtMs);
20921
+ perAccount.set(e.accountId, (perAccount.get(e.accountId) ?? 0) + 1);
20922
+ }
20923
+ const maxOpenPerAccount = perAccount.size === 0 ? 0 : Math.max(...perAccount.values());
20924
+ const driftTasks = rows.taskSums.filter((t) => t.secondsLogged !== t.sumEntries).length;
20925
+ const oldestOpenAgeMin = Math.floor(oldestOpenAgeMs / 6e4);
20926
+ const alarm = oldestOpenAgeMs > horizonMs || maxOpenPerAccount > 1 || driftTasks > 0;
20927
+ return { openEntries, oldestOpenAgeMin, maxOpenPerAccount, driftTasks, alarm };
20928
+ }
20929
+ async function runTimeEntryCensusOnce(session, now, horizonMs) {
20930
+ try {
20931
+ const openRes = await session.run(
20932
+ `MATCH (te:TimeEntry) WHERE te.endedAt IS NULL
20933
+ RETURN te.accountId AS accountId, te.startedAt AS startedAt`
20934
+ );
20935
+ const openEntries = openRes.records.map((r) => ({
20936
+ accountId: r.get("accountId") ?? "unknown",
20937
+ startedAtMs: Date.parse(r.get("startedAt") ?? "") || now
20938
+ }));
20939
+ const sumRes = await session.run(
20940
+ `MATCH (t:Task) WHERE t.secondsLogged IS NOT NULL
20941
+ OPTIONAL MATCH (te:TimeEntry {taskId: t.taskId}) WHERE te.endedAt IS NOT NULL
20942
+ RETURN t.taskId AS taskId, coalesce(t.secondsLogged, 0) AS secondsLogged, coalesce(sum(te.seconds), 0) AS sumEntries`
20943
+ );
20944
+ const taskSums = sumRes.records.map((r) => ({
20945
+ taskId: r.get("taskId") ?? "",
20946
+ secondsLogged: toNum(r.get("secondsLogged")),
20947
+ sumEntries: toNum(r.get("sumEntries"))
20948
+ }));
20949
+ const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
20950
+ const line = `${TAG39} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
20951
+ if (finding.alarm) console.error(`${line} alarm=true`);
20952
+ else console.log(line);
20953
+ return finding;
20954
+ } catch (err) {
20955
+ console.error(`${TAG39} error="${err instanceof Error ? err.message : String(err)}"`);
20956
+ return null;
20957
+ }
20958
+ }
20959
+ var DEFAULT_INTERVAL_MS = 15 * 60 * 1e3;
20960
+ var DEFAULT_HORIZON_MS = 8 * 60 * 60 * 1e3;
20961
+ function startTimeEntryCensus(openSession, opts = {}) {
20962
+ const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
20963
+ const horizonMs = opts.horizonMs ?? DEFAULT_HORIZON_MS;
20964
+ const tick = async () => {
20965
+ const session = openSession();
20966
+ try {
20967
+ await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
20968
+ } finally {
20969
+ try {
20970
+ await session.close();
20971
+ } catch {
20972
+ }
20973
+ }
20974
+ };
20975
+ void tick();
20976
+ const id = setInterval(() => {
20977
+ void tick();
20978
+ }, intervalMs);
20979
+ if (typeof id.unref === "function") {
20980
+ id.unref();
20981
+ }
20982
+ return () => clearInterval(id);
20983
+ }
20610
20984
 
20611
20985
  // app/lib/graph-health.ts
20612
20986
  var import_dist4 = __toESM(require_dist4(), 1);
@@ -21375,8 +21749,8 @@ var streamSSE = (c, cb, onError) => {
21375
21749
 
21376
21750
  // app/lib/whatsapp/gateway/routes.ts
21377
21751
  function createWaChannelRoutes(deps) {
21378
- const app57 = new Hono();
21379
- app57.get("/wa-channel/inbound", (c) => {
21752
+ const app61 = new Hono();
21753
+ app61.get("/wa-channel/inbound", (c) => {
21380
21754
  const senderId = c.req.query("senderId");
21381
21755
  if (!senderId) return c.json({ error: "senderId required" }, 400);
21382
21756
  return streamSSE(c, async (stream2) => {
@@ -21394,7 +21768,7 @@ function createWaChannelRoutes(deps) {
21394
21768
  }
21395
21769
  });
21396
21770
  });
21397
- app57.post("/wa-channel/reply", async (c) => {
21771
+ app61.post("/wa-channel/reply", async (c) => {
21398
21772
  const body = await c.req.json().catch(() => null);
21399
21773
  const senderId = body?.senderId;
21400
21774
  const text = body?.text;
@@ -21415,7 +21789,7 @@ function createWaChannelRoutes(deps) {
21415
21789
  console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
21416
21790
  return c.json({ ok: true });
21417
21791
  });
21418
- app57.post("/wa-channel/reply-document", async (c) => {
21792
+ app61.post("/wa-channel/reply-document", async (c) => {
21419
21793
  const body = await c.req.json().catch(() => null);
21420
21794
  const senderId = body?.senderId;
21421
21795
  const files = body?.files;
@@ -21454,7 +21828,7 @@ function createWaChannelRoutes(deps) {
21454
21828
  }
21455
21829
  return c.json({ ok: true, results });
21456
21830
  });
21457
- app57.post("/wa-channel/ready", async (c) => {
21831
+ app61.post("/wa-channel/ready", async (c) => {
21458
21832
  const body = await c.req.json().catch(() => null);
21459
21833
  const senderId = body?.senderId;
21460
21834
  if (typeof senderId !== "string") {
@@ -21463,7 +21837,7 @@ function createWaChannelRoutes(deps) {
21463
21837
  deps.onReady?.(senderId);
21464
21838
  return c.json({ ok: true });
21465
21839
  });
21466
- app57.post("/wa-channel/received", async (c) => {
21840
+ app61.post("/wa-channel/received", async (c) => {
21467
21841
  const body = await c.req.json().catch(() => null);
21468
21842
  const senderId = body?.senderId;
21469
21843
  const waMessageId = body?.waMessageId;
@@ -21473,7 +21847,7 @@ function createWaChannelRoutes(deps) {
21473
21847
  deps.onReceived?.(senderId, waMessageId);
21474
21848
  return c.json({ ok: true });
21475
21849
  });
21476
- app57.post("/wa-channel/turn-end", async (c) => {
21850
+ app61.post("/wa-channel/turn-end", async (c) => {
21477
21851
  const body = await c.req.json().catch(() => null);
21478
21852
  const senderId = body?.senderId;
21479
21853
  const sessionId = body?.sessionId;
@@ -21489,7 +21863,7 @@ function createWaChannelRoutes(deps) {
21489
21863
  console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=none`);
21490
21864
  return c.json({ ok: true, delivered: "none" });
21491
21865
  });
21492
- return app57;
21866
+ return app61;
21493
21867
  }
21494
21868
 
21495
21869
  // app/lib/whatsapp/gateway/wa-gateway.ts
@@ -21594,7 +21968,8 @@ var WaGateway = class {
21594
21968
  waMessageId: `wa-${++this.seq}`,
21595
21969
  media: input.media,
21596
21970
  source,
21597
- standingRules
21971
+ standingRules,
21972
+ scheduleProvenance: input.scheduleProvenance
21598
21973
  },
21599
21974
  Date.now()
21600
21975
  );
@@ -21612,7 +21987,9 @@ var WaGateway = class {
21612
21987
  role: input.role ?? "admin",
21613
21988
  personId: input.personId ?? null,
21614
21989
  gatewayUrl: this.deps.gatewayUrl,
21615
- serverPath: this.deps.serverPath
21990
+ serverPath: this.deps.serverPath,
21991
+ // Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
21992
+ sessionIdOverride: input.scheduledSessionId
21616
21993
  });
21617
21994
  } finally {
21618
21995
  this.spawning.delete(input.senderId);
@@ -21638,7 +22015,7 @@ var WaGateway = class {
21638
22015
  function buildWaSpawnRequest(input) {
21639
22016
  const personId = input.role === "public" && input.personId ? input.personId : void 0;
21640
22017
  return {
21641
- sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
22018
+ sessionId: input.sessionIdOverride && input.sessionIdOverride.length > 0 ? input.sessionIdOverride : adminSessionIdFor(input.accountId, input.senderId, personId),
21642
22019
  role: input.role,
21643
22020
  channel: "whatsapp",
21644
22021
  personId,
@@ -21822,8 +22199,8 @@ var import_dist6 = __toESM(require_dist(), 1);
21822
22199
 
21823
22200
  // app/lib/webchat/gateway/routes.ts
21824
22201
  function createWebchatChannelRoutes(deps) {
21825
- const app57 = new Hono();
21826
- app57.get("/webchat-channel/inbound", (c) => {
22202
+ const app61 = new Hono();
22203
+ app61.get("/webchat-channel/inbound", (c) => {
21827
22204
  const key = c.req.query("key");
21828
22205
  if (!key) return c.json({ error: "key required" }, 400);
21829
22206
  return streamSSE(c, async (stream2) => {
@@ -21841,7 +22218,7 @@ function createWebchatChannelRoutes(deps) {
21841
22218
  }
21842
22219
  });
21843
22220
  });
21844
- app57.post("/webchat-channel/reply", async (c) => {
22221
+ app61.post("/webchat-channel/reply", async (c) => {
21845
22222
  const body = await c.req.json().catch(() => null);
21846
22223
  const key = body?.key;
21847
22224
  const text = body?.text;
@@ -21851,7 +22228,7 @@ function createWebchatChannelRoutes(deps) {
21851
22228
  deps.onReply?.(key, text);
21852
22229
  return c.json({ ok: true });
21853
22230
  });
21854
- app57.post("/webchat-channel/connector-auth", async (c) => {
22231
+ app61.post("/webchat-channel/connector-auth", async (c) => {
21855
22232
  const body = await c.req.json().catch(() => null);
21856
22233
  const key = body?.key;
21857
22234
  const sessionId = body?.sessionId;
@@ -21864,7 +22241,7 @@ function createWebchatChannelRoutes(deps) {
21864
22241
  const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
21865
22242
  return c.json(result);
21866
22243
  });
21867
- app57.post("/webchat-channel/ready", async (c) => {
22244
+ app61.post("/webchat-channel/ready", async (c) => {
21868
22245
  const body = await c.req.json().catch(() => null);
21869
22246
  const key = body?.key;
21870
22247
  if (typeof key !== "string") {
@@ -21873,7 +22250,7 @@ function createWebchatChannelRoutes(deps) {
21873
22250
  deps.onReady?.(key);
21874
22251
  return c.json({ ok: true });
21875
22252
  });
21876
- app57.post("/webchat-channel/permission-request", async (c) => {
22253
+ app61.post("/webchat-channel/permission-request", async (c) => {
21877
22254
  const body = await c.req.json().catch(() => null);
21878
22255
  const key = body?.key;
21879
22256
  const requestId = body?.request_id;
@@ -21887,7 +22264,7 @@ function createWebchatChannelRoutes(deps) {
21887
22264
  const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
21888
22265
  return c.json(verdict);
21889
22266
  });
21890
- app57.post("/webchat-channel/received", async (c) => {
22267
+ app61.post("/webchat-channel/received", async (c) => {
21891
22268
  const body = await c.req.json().catch(() => null);
21892
22269
  const key = body?.key;
21893
22270
  const messageId = body?.messageId;
@@ -21897,7 +22274,7 @@ function createWebchatChannelRoutes(deps) {
21897
22274
  deps.onReceived?.(key, messageId);
21898
22275
  return c.json({ ok: true });
21899
22276
  });
21900
- app57.post("/webchat-channel/turn-end", async (c) => {
22277
+ app61.post("/webchat-channel/turn-end", async (c) => {
21901
22278
  const body = await c.req.json().catch(() => null);
21902
22279
  const key = body?.key;
21903
22280
  const sessionId = body?.sessionId;
@@ -21917,7 +22294,7 @@ function createWebchatChannelRoutes(deps) {
21917
22294
  console.error(`[webchat-native] op=turn-undelivered channel=webchat key=${k} sessionId=${sid} bytes=${finalBytes}`);
21918
22295
  return c.json({ ok: true, delivered: "undelivered" });
21919
22296
  });
21920
- return app57;
22297
+ return app61;
21921
22298
  }
21922
22299
 
21923
22300
  // app/lib/webchat/gateway/webchat-gateway.ts
@@ -22548,7 +22925,7 @@ function makeFileDelivery(opts) {
22548
22925
  }
22549
22926
 
22550
22927
  // app/lib/whatsapp/inbound/file-delivery-bridge.ts
22551
- var TAG35 = "[whatsapp-adaptor]";
22928
+ var TAG40 = "[whatsapp-adaptor]";
22552
22929
  var SEND_USER_FILE2 = "SendUserFile";
22553
22930
  var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
22554
22931
  function platformRoot() {
@@ -22566,7 +22943,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
22566
22943
  });
22567
22944
  if (result.ok) return { ok: true };
22568
22945
  console.error(
22569
- `${TAG35} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
22946
+ `${TAG40} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
22570
22947
  );
22571
22948
  return { ok: false, error: result.error };
22572
22949
  };
@@ -22574,7 +22951,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
22574
22951
  function makeWhatsAppFileDelivery(entry, maxyAccountId) {
22575
22952
  const shared = makeFileDelivery({
22576
22953
  entry,
22577
- tag: TAG35,
22954
+ tag: TAG40,
22578
22955
  channel: "whatsapp",
22579
22956
  sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
22580
22957
  });
@@ -22609,7 +22986,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
22609
22986
  if (!delivered) {
22610
22987
  const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
22611
22988
  console.error(
22612
- `${TAG35} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
22989
+ `${TAG40} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
22613
22990
  );
22614
22991
  }
22615
22992
  }
@@ -22786,8 +23163,8 @@ var import_dist7 = __toESM(require_dist(), 1);
22786
23163
 
22787
23164
  // app/lib/telegram/gateway/routes.ts
22788
23165
  function createTelegramChannelRoutes(deps) {
22789
- const app57 = new Hono();
22790
- app57.get("/tg-channel/inbound", (c) => {
23166
+ const app61 = new Hono();
23167
+ app61.get("/tg-channel/inbound", (c) => {
22791
23168
  const key = c.req.query("key");
22792
23169
  if (!key) return c.json({ error: "key required" }, 400);
22793
23170
  return streamSSE(c, async (stream2) => {
@@ -22805,7 +23182,7 @@ function createTelegramChannelRoutes(deps) {
22805
23182
  }
22806
23183
  });
22807
23184
  });
22808
- app57.post("/tg-channel/reply", async (c) => {
23185
+ app61.post("/tg-channel/reply", async (c) => {
22809
23186
  const body = await c.req.json().catch(() => null);
22810
23187
  const key = body?.key;
22811
23188
  const text = body?.text;
@@ -22821,7 +23198,7 @@ function createTelegramChannelRoutes(deps) {
22821
23198
  console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
22822
23199
  return c.json({ ok: true });
22823
23200
  });
22824
- app57.post("/tg-channel/ready", async (c) => {
23201
+ app61.post("/tg-channel/ready", async (c) => {
22825
23202
  const body = await c.req.json().catch(() => null);
22826
23203
  const key = body?.key;
22827
23204
  if (typeof key !== "string") {
@@ -22830,7 +23207,7 @@ function createTelegramChannelRoutes(deps) {
22830
23207
  deps.onReady?.(key);
22831
23208
  return c.json({ ok: true });
22832
23209
  });
22833
- app57.post("/tg-channel/received", async (c) => {
23210
+ app61.post("/tg-channel/received", async (c) => {
22834
23211
  const body = await c.req.json().catch(() => null);
22835
23212
  const key = body?.key;
22836
23213
  const messageId = body?.messageId;
@@ -22840,7 +23217,7 @@ function createTelegramChannelRoutes(deps) {
22840
23217
  deps.onReceived?.(key, messageId);
22841
23218
  return c.json({ ok: true });
22842
23219
  });
22843
- app57.post("/tg-channel/turn-end", async (c) => {
23220
+ app61.post("/tg-channel/turn-end", async (c) => {
22844
23221
  const body = await c.req.json().catch(() => null);
22845
23222
  const key = body?.key;
22846
23223
  const sessionId = body?.sessionId;
@@ -22856,7 +23233,7 @@ function createTelegramChannelRoutes(deps) {
22856
23233
  console.error(`[telegram-native] op=turn-end key=${key} sessionId=${sid} replied=no delivered=none`);
22857
23234
  return c.json({ ok: true, delivered: "none" });
22858
23235
  });
22859
- return app57;
23236
+ return app61;
22860
23237
  }
22861
23238
 
22862
23239
  // app/lib/telegram/gateway/telegram-gateway.ts
@@ -22923,7 +23300,7 @@ var TelegramGateway = class {
22923
23300
  );
22924
23301
  }
22925
23302
  this.hub.deliver(
22926
- { key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules },
23303
+ { key: input.senderId, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
22927
23304
  Date.now()
22928
23305
  );
22929
23306
  console.error(
@@ -22940,7 +23317,9 @@ var TelegramGateway = class {
22940
23317
  personId: input.personId ?? null,
22941
23318
  chatId: input.chatId,
22942
23319
  gatewayUrl: this.deps.gatewayUrl,
22943
- serverPath: this.deps.serverPath
23320
+ serverPath: this.deps.serverPath,
23321
+ // Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
23322
+ sessionIdOverride: input.scheduledSessionId
22944
23323
  });
22945
23324
  } finally {
22946
23325
  this.spawning.delete(input.senderId);
@@ -22958,7 +23337,7 @@ var TelegramGateway = class {
22958
23337
  function buildTelegramSpawnRequest(input) {
22959
23338
  const personId = input.role === "public" && input.personId ? input.personId : void 0;
22960
23339
  return {
22961
- sessionId: adminSessionIdFor(input.accountId, input.senderId, personId),
23340
+ sessionId: input.sessionIdOverride && input.sessionIdOverride.length > 0 ? input.sessionIdOverride : adminSessionIdFor(input.accountId, input.senderId, personId),
22962
23341
  role: input.role,
22963
23342
  channel: "telegram",
22964
23343
  personId,
@@ -22977,7 +23356,7 @@ function buildTelegramSpawnRequest(input) {
22977
23356
  import { realpathSync as realpathSync7 } from "fs";
22978
23357
  import { readFile as readFile7, stat as stat7 } from "fs/promises";
22979
23358
  import { resolve as resolve30, basename as basename12 } from "path";
22980
- var TAG36 = "[telegram:outbound]";
23359
+ var TAG41 = "[telegram:outbound]";
22981
23360
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
22982
23361
  async function sendTelegramDocument(input) {
22983
23362
  const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot3 } = input;
@@ -22993,16 +23372,16 @@ async function sendTelegramDocument(input) {
22993
23372
  resolvedPath = realpathSync7(filePath);
22994
23373
  const accountResolved = realpathSync7(accountDir);
22995
23374
  if (!resolvedPath.startsWith(accountResolved + "/")) {
22996
- console.error(`${TAG36} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
23375
+ console.error(`${TAG41} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
22997
23376
  return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
22998
23377
  }
22999
23378
  } catch (err) {
23000
23379
  const code = err.code;
23001
23380
  if (code === "ENOENT") {
23002
- console.error(`${TAG36} document ENOENT path=${filePath}`);
23381
+ console.error(`${TAG41} document ENOENT path=${filePath}`);
23003
23382
  return { ok: false, status: 404, error: `File not found: ${filePath}` };
23004
23383
  }
23005
- console.error(`${TAG36} document path error: ${String(err)}`);
23384
+ console.error(`${TAG41} document path error: ${String(err)}`);
23006
23385
  return { ok: false, status: 500, error: String(err) };
23007
23386
  }
23008
23387
  const fileStat = await stat7(resolvedPath);
@@ -23035,13 +23414,13 @@ async function sendTelegramDocument(input) {
23035
23414
  error = e instanceof Error ? e.message : String(e);
23036
23415
  }
23037
23416
  console.error(
23038
- `${TAG36} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
23417
+ `${TAG41} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
23039
23418
  );
23040
23419
  return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
23041
23420
  }
23042
23421
 
23043
23422
  // app/lib/telegram/outbound/file-delivery.ts
23044
- var TAG37 = "[telegram:outbound]";
23423
+ var TAG42 = "[telegram:outbound]";
23045
23424
  function platformRoot2() {
23046
23425
  return process.env.MAXY_PLATFORM_ROOT || "";
23047
23426
  }
@@ -23053,11 +23432,11 @@ function makeTelegramSendFile(entry) {
23053
23432
  botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
23054
23433
  }
23055
23434
  if (!botToken) {
23056
- console.error(`${TAG37} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
23435
+ console.error(`${TAG42} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
23057
23436
  return { ok: false, error: "no-bot-token" };
23058
23437
  }
23059
23438
  if (entry.replyTarget == null) {
23060
- console.error(`${TAG37} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
23439
+ console.error(`${TAG42} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
23061
23440
  return { ok: false, error: "no-reply-target" };
23062
23441
  }
23063
23442
  const result = await sendTelegramDocument({
@@ -23074,7 +23453,7 @@ function makeTelegramSendFile(entry) {
23074
23453
  function makeTelegramFileDelivery(entry) {
23075
23454
  return makeFileDelivery({
23076
23455
  entry,
23077
- tag: TAG37,
23456
+ tag: TAG42,
23078
23457
  channel: "telegram",
23079
23458
  sendFile: makeTelegramSendFile(entry)
23080
23459
  });
@@ -23123,8 +23502,8 @@ function telegramServerPath() {
23123
23502
  }
23124
23503
 
23125
23504
  // app/lib/channel-pty-bridge/public-session-end-review.ts
23126
- import { randomUUID as randomUUID13 } from "crypto";
23127
- var TAG38 = "[public-session-review]";
23505
+ import { randomUUID as randomUUID14 } from "crypto";
23506
+ var TAG43 = "[public-session-review]";
23128
23507
  var CONSUMED_CAP = 500;
23129
23508
  var consumed = /* @__PURE__ */ new Set();
23130
23509
  function consumeOnce(sessionId) {
@@ -23151,7 +23530,7 @@ async function fetchJsonl(sessionId) {
23151
23530
  return await res.text();
23152
23531
  } catch (err) {
23153
23532
  console.error(
23154
- `${TAG38} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
23533
+ `${TAG43} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
23155
23534
  );
23156
23535
  return null;
23157
23536
  }
@@ -23175,7 +23554,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
23175
23554
  const res = await fetch(url);
23176
23555
  if (!res.ok) {
23177
23556
  console.error(
23178
- `${TAG38} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
23557
+ `${TAG43} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
23179
23558
  );
23180
23559
  return [];
23181
23560
  }
@@ -23183,7 +23562,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
23183
23562
  return Array.isArray(body.writes) ? body.writes : [];
23184
23563
  } catch (err) {
23185
23564
  console.error(
23186
- `${TAG38} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
23565
+ `${TAG43} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
23187
23566
  );
23188
23567
  return [];
23189
23568
  }
@@ -23211,8 +23590,8 @@ function composeInitialMessage(input) {
23211
23590
  ].join("\n");
23212
23591
  }
23213
23592
  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)}`);
23593
+ const sessionId = randomUUID14();
23594
+ console.log(`${TAG43} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
23216
23595
  const spawned = await managerRcSpawn({
23217
23596
  sessionId,
23218
23597
  initialMessage,
@@ -23232,21 +23611,21 @@ async function firePublicSessionEndReview(input) {
23232
23611
  const dispatchedAt = Date.now();
23233
23612
  if (consumed.has(input.sessionId)) {
23234
23613
  console.log(
23235
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
23614
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
23236
23615
  );
23237
23616
  return;
23238
23617
  }
23239
23618
  const jsonl = await fetchJsonl(input.sessionId);
23240
23619
  if (!jsonl) {
23241
23620
  console.log(
23242
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
23621
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
23243
23622
  );
23244
23623
  return;
23245
23624
  }
23246
23625
  const operatorTurns = countOperatorTurns(jsonl);
23247
23626
  if (operatorTurns === 0) {
23248
23627
  console.log(
23249
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
23628
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
23250
23629
  );
23251
23630
  return;
23252
23631
  }
@@ -23260,19 +23639,19 @@ async function firePublicSessionEndReview(input) {
23260
23639
  });
23261
23640
  if (!consumeOnce(input.sessionId)) {
23262
23641
  console.log(
23263
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
23642
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
23264
23643
  );
23265
23644
  return;
23266
23645
  }
23267
23646
  const dispatched = await dispatchReviewer(input, initialMessage);
23268
23647
  if (!dispatched.ok) {
23269
23648
  console.error(
23270
- `${TAG38} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
23649
+ `${TAG43} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
23271
23650
  );
23272
23651
  return;
23273
23652
  }
23274
23653
  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}`
23654
+ `${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
23655
  );
23277
23656
  }
23278
23657
 
@@ -23687,7 +24066,7 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
23687
24066
  function isPublicHost(host) {
23688
24067
  return host.startsWith("public.") || aliasDomains.has(host);
23689
24068
  }
23690
- var app56 = new Hono();
24069
+ var app60 = new Hono();
23691
24070
  var nativeFileFollowers = /* @__PURE__ */ new Map();
23692
24071
  async function fetchAccountStandingRules(accountId) {
23693
24072
  const session = getSession();
@@ -23745,7 +24124,7 @@ var waGateway = new WaGateway({
23745
24124
  });
23746
24125
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
23747
24126
  },
23748
- ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId }) => {
24127
+ ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, sessionIdOverride }) => {
23749
24128
  if (passive) {
23750
24129
  const phoneHash = createHash6("sha256").update(senderId).digest("hex").slice(0, 12);
23751
24130
  const prompt = (text ?? "").trim();
@@ -23793,7 +24172,7 @@ var waGateway = new WaGateway({
23793
24172
  const managesAccount = effectiveAccountId !== accountId ? effectiveAccountId : "none";
23794
24173
  console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
23795
24174
  }
23796
- const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath });
24175
+ const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
23797
24176
  const userId = role === "admin" ? resolveAdminUserId({ accountId: effectiveAccountId, senderPhone: senderId }) ?? void 0 : void 0;
23798
24177
  if (role === "admin") {
23799
24178
  console.error(`[whatsapp-native] op=admin-identity senderId=${senderId} userId=${userId ?? "owner-fallback"}`);
@@ -23822,7 +24201,7 @@ var waGateway = new WaGateway({
23822
24201
  nativeFileFollowers.set(senderId, ac);
23823
24202
  }
23824
24203
  });
23825
- app56.route("/", waGateway.routes());
24204
+ app60.route("/", waGateway.routes());
23826
24205
  waGateway.startSweeper();
23827
24206
  var webchatGateway = new WebchatGateway({
23828
24207
  fetchStandingRules: fetchAccountStandingRules,
@@ -23906,7 +24285,7 @@ var webchatGateway = new WebchatGateway({
23906
24285
  firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
23907
24286
  });
23908
24287
  setWebchatGateway(webchatGateway);
23909
- app56.route("/", webchatGateway.routes());
24288
+ app60.route("/", webchatGateway.routes());
23910
24289
  webchatGateway.startSweeper();
23911
24290
  webchatGateway.startPublicReaper();
23912
24291
  var telegramFileFollowers = /* @__PURE__ */ new Map();
@@ -23914,8 +24293,8 @@ var telegramGateway = new TelegramGateway({
23914
24293
  fetchStandingRules: fetchAccountStandingRules,
23915
24294
  gatewayUrl: telegramGatewayUrl(),
23916
24295
  serverPath: telegramServerPath(),
23917
- ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath }) => {
23918
- const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath });
24296
+ ensureChannelSession: async ({ accountId, senderId, role, personId, chatId, gatewayUrl, serverPath, sessionIdOverride }) => {
24297
+ const req = buildTelegramSpawnRequest({ accountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
23919
24298
  const result = await managerRcSpawn(req);
23920
24299
  if ("error" in result) {
23921
24300
  console.error(`[telegram-native] spawn-failed senderId=${senderId} role=${role} error=${result.error} status=${result.status}`);
@@ -23940,7 +24319,7 @@ var telegramGateway = new TelegramGateway({
23940
24319
  }
23941
24320
  });
23942
24321
  setTelegramGateway(telegramGateway);
23943
- app56.route("/", telegramGateway.routes());
24322
+ app60.route("/", telegramGateway.routes());
23944
24323
  telegramGateway.startSweeper();
23945
24324
  var chatRoutes = createChatRoutes({
23946
24325
  handleInbound: (input) => webchatGateway.handleInbound(input),
@@ -23973,19 +24352,19 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
23973
24352
  return managed.account;
23974
24353
  }
23975
24354
  });
23976
- app56.route("/api/channel/schedule-inject", scheduleInjectRoutes);
23977
- app56.use("*", clientIpMiddleware);
24355
+ app60.route("/api/channel/schedule-inject", scheduleInjectRoutes);
24356
+ app60.use("*", clientIpMiddleware);
23978
24357
  function allowsSameOriginFraming(path2) {
23979
24358
  return path2 === "/vnc-viewer.html" || path2.startsWith("/api/admin/attachment/") || path2.startsWith("/api/public-reader/attachment/") || path2 === "/api/admin/files/download";
23980
24359
  }
23981
- app56.use("*", async (c, next) => {
24360
+ app60.use("*", async (c, next) => {
23982
24361
  await next();
23983
24362
  c.header("X-Content-Type-Options", "nosniff");
23984
24363
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
23985
24364
  c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
23986
24365
  });
23987
24366
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
23988
- app56.use("*", async (c, next) => {
24367
+ app60.use("*", async (c, next) => {
23989
24368
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
23990
24369
  await next();
23991
24370
  return;
@@ -24003,7 +24382,7 @@ app56.use("*", async (c, next) => {
24003
24382
  });
24004
24383
  }
24005
24384
  });
24006
- app56.use("*", async (c, next) => {
24385
+ app60.use("*", async (c, next) => {
24007
24386
  const host = (c.req.header("host") ?? "").split(":")[0];
24008
24387
  if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
24009
24388
  await next();
@@ -24041,7 +24420,7 @@ function resolveRemoteAuthOpts(c) {
24041
24420
  return { ...brandLoginOpts, origin };
24042
24421
  }
24043
24422
  var MAX_LOGIN_BODY = 8 * 1024;
24044
- app56.post("/__remote-auth/login", async (c) => {
24423
+ app60.post("/__remote-auth/login", async (c) => {
24045
24424
  const client = clientFrom(c);
24046
24425
  const clientIp = client.ip || "unknown";
24047
24426
  if (!requestIsTlsTerminated(c)) {
@@ -24086,7 +24465,7 @@ app56.post("/__remote-auth/login", async (c) => {
24086
24465
  }
24087
24466
  });
24088
24467
  });
24089
- app56.get("/__remote-auth/logout", (c) => {
24468
+ app60.get("/__remote-auth/logout", (c) => {
24090
24469
  const client = clientFrom(c);
24091
24470
  const clientIp = client.ip || "unknown";
24092
24471
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -24099,7 +24478,7 @@ app56.get("/__remote-auth/logout", (c) => {
24099
24478
  }
24100
24479
  });
24101
24480
  });
24102
- app56.post("/__remote-auth/change-password", async (c) => {
24481
+ app60.post("/__remote-auth/change-password", async (c) => {
24103
24482
  const client = clientFrom(c);
24104
24483
  const clientIp = client.ip || "unknown";
24105
24484
  const rateLimited = checkRateLimit(client);
@@ -24158,13 +24537,13 @@ app56.post("/__remote-auth/change-password", async (c) => {
24158
24537
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
24159
24538
  }
24160
24539
  });
24161
- app56.get("/__remote-auth/setup", (c) => {
24540
+ app60.get("/__remote-auth/setup", (c) => {
24162
24541
  if (isRemoteAuthConfigured()) {
24163
24542
  return c.redirect("/");
24164
24543
  }
24165
24544
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
24166
24545
  });
24167
- app56.post("/__remote-auth/set-initial-password", async (c) => {
24546
+ app60.post("/__remote-auth/set-initial-password", async (c) => {
24168
24547
  if (isRemoteAuthConfigured()) {
24169
24548
  return c.redirect("/");
24170
24549
  }
@@ -24202,10 +24581,10 @@ app56.post("/__remote-auth/set-initial-password", async (c) => {
24202
24581
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
24203
24582
  }
24204
24583
  });
24205
- app56.get("/api/remote-auth/status", (c) => {
24584
+ app60.get("/api/remote-auth/status", (c) => {
24206
24585
  return c.json({ configured: isRemoteAuthConfigured() });
24207
24586
  });
24208
- app56.post("/api/remote-auth/set-password", async (c) => {
24587
+ app60.post("/api/remote-auth/set-password", async (c) => {
24209
24588
  let body;
24210
24589
  try {
24211
24590
  body = await c.req.json();
@@ -24244,10 +24623,10 @@ app56.post("/api/remote-auth/set-password", async (c) => {
24244
24623
  return c.json({ error: "Failed to save password" }, 500);
24245
24624
  }
24246
24625
  });
24247
- app56.route("/api/_client-error", client_error_default);
24626
+ app60.route("/api/_client-error", client_error_default);
24248
24627
  console.log("[client-error-route] mounted");
24249
24628
  var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
24250
- app56.use("*", async (c, next) => {
24629
+ app60.use("*", async (c, next) => {
24251
24630
  const host = (c.req.header("host") ?? "").split(":")[0];
24252
24631
  const path2 = c.req.path;
24253
24632
  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 +24670,26 @@ app56.use("*", async (c, next) => {
24291
24670
  }
24292
24671
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path2 }), 200);
24293
24672
  });
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({
24673
+ app60.route("/api/health", health_default);
24674
+ app60.route("/api/chat", chatRoutes);
24675
+ app60.route("/api/whatsapp", whatsapp_default);
24676
+ app60.route("/api/whatsapp-reader", whatsapp_reader_default);
24677
+ app60.route("/api/public-reader", public_reader_default);
24678
+ app60.route("/api/webchat", createWebchatRoutes({
24300
24679
  handleInbound: (input) => webchatGateway.handleInbound(input),
24301
24680
  // Task 940 — the permission relay's pointer read + verdict write.
24302
24681
  pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
24303
24682
  deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
24304
24683
  resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
24305
24684
  }));
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);
24685
+ app60.route("/api/webchat/greeting", webchat_greeting_default);
24686
+ app60.route("/api/telegram", telegram_default);
24687
+ app60.route("/api/quickbooks", quickbooks_default);
24688
+ app60.route("/api/onboarding", onboarding_default);
24689
+ app60.route("/api/admin", admin_default);
24690
+ app60.route("/api/access", access_default);
24691
+ app60.route("/api/session", session_default2);
24692
+ app60.route("/api/calendar", calendar_public_default);
24314
24693
  var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
24315
24694
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
24316
24695
  var IMAGE_MIME = {
@@ -24322,7 +24701,7 @@ var IMAGE_MIME = {
24322
24701
  ".svg": "image/svg+xml",
24323
24702
  ".ico": "image/x-icon"
24324
24703
  };
24325
- app56.get("/agent-assets/:slug/:filename", (c) => {
24704
+ app60.get("/agent-assets/:slug/:filename", (c) => {
24326
24705
  const slug = c.req.param("slug");
24327
24706
  const filename = c.req.param("filename");
24328
24707
  if (!SAFE_SLUG_RE2.test(slug)) {
@@ -24357,7 +24736,7 @@ app56.get("/agent-assets/:slug/:filename", (c) => {
24357
24736
  "Cache-Control": "public, max-age=3600"
24358
24737
  });
24359
24738
  });
24360
- app56.get("/generated/:filename", (c) => {
24739
+ app60.get("/generated/:filename", (c) => {
24361
24740
  const filename = c.req.param("filename");
24362
24741
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
24363
24742
  console.error(`[generated] serve file=${filename} status=403`);
@@ -24387,10 +24766,10 @@ app56.get("/generated/:filename", (c) => {
24387
24766
  "Cache-Control": "public, max-age=86400"
24388
24767
  });
24389
24768
  });
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);
24769
+ app60.route("/sites", sites_default);
24770
+ app60.route("/listings", listings_default);
24771
+ app60.route("/v", visitor_event_default);
24772
+ app60.route("/v", visitor_consent_default);
24394
24773
  var htmlCache = /* @__PURE__ */ new Map();
24395
24774
  var brandLogoPath = "/brand/maxy-monochrome.png";
24396
24775
  var brandIconPath = "/brand/maxy-monochrome.png";
@@ -24545,7 +24924,7 @@ function brandedPublicHtml(agentSlug) {
24545
24924
  function agentUnavailableHtml() {
24546
24925
  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
24926
  }
24548
- app56.get("/", (c) => {
24927
+ app60.get("/", (c) => {
24549
24928
  const host = (c.req.header("host") ?? "").split(":")[0];
24550
24929
  const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
24551
24930
  if (klass === "operator") {
@@ -24567,12 +24946,12 @@ app56.get("/", (c) => {
24567
24946
  console.log(`[host-class] host=${host} class=admin served=index.html`);
24568
24947
  return c.html(cachedHtml("index.html"));
24569
24948
  });
24570
- app56.get("/public", (c) => {
24949
+ app60.get("/public", (c) => {
24571
24950
  const host = (c.req.header("host") ?? "").split(":")[0];
24572
24951
  if (isPublicHost(host)) return c.text("Not found", 404);
24573
24952
  return c.html(cachedHtml("public.html"));
24574
24953
  });
24575
- app56.get("/public-chat", (c) => {
24954
+ app60.get("/public-chat", (c) => {
24576
24955
  const host = (c.req.header("host") ?? "").split(":")[0];
24577
24956
  if (isPublicHost(host)) return c.text("Not found", 404);
24578
24957
  return c.html(cachedHtml("public.html"));
@@ -24591,9 +24970,9 @@ async function logViewerFetch(c, next) {
24591
24970
  duration_ms: Date.now() - start
24592
24971
  });
24593
24972
  }
24594
- app56.use("/vnc-viewer.html", logViewerFetch);
24595
- app56.use("/vnc-popout.html", logViewerFetch);
24596
- app56.get("/vnc-popout.html", (c) => {
24973
+ app60.use("/vnc-viewer.html", logViewerFetch);
24974
+ app60.use("/vnc-popout.html", logViewerFetch);
24975
+ app60.get("/vnc-popout.html", (c) => {
24597
24976
  let html = htmlCache.get("vnc-popout.html");
24598
24977
  if (!html) {
24599
24978
  html = readFileSync35(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
@@ -24606,7 +24985,7 @@ app56.get("/vnc-popout.html", (c) => {
24606
24985
  }
24607
24986
  return c.html(html);
24608
24987
  });
24609
- app56.post("/api/vnc/client-event", async (c) => {
24988
+ app60.post("/api/vnc/client-event", async (c) => {
24610
24989
  let body;
24611
24990
  try {
24612
24991
  body = await c.req.json();
@@ -24627,11 +25006,11 @@ app56.post("/api/vnc/client-event", async (c) => {
24627
25006
  });
24628
25007
  return c.json({ ok: true });
24629
25008
  });
24630
- app56.get("/g/:slug", (c) => {
25009
+ app60.get("/g/:slug", (c) => {
24631
25010
  return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
24632
25011
  });
24633
25012
  for (const pwa of PWA_SURFACES) {
24634
- app56.get(pwa.manifestPath, (c) => {
25013
+ app60.get(pwa.manifestPath, (c) => {
24635
25014
  const manifest = buildManifest(pwa, {
24636
25015
  productName: BRAND.productName,
24637
25016
  appIcon192: brandAppIcon192Path,
@@ -24647,7 +25026,7 @@ for (const pwa of PWA_SURFACES) {
24647
25026
  return c.body(JSON.stringify(manifest));
24648
25027
  });
24649
25028
  }
24650
- app56.get("/sw.js", (c) => {
25029
+ app60.get("/sw.js", (c) => {
24651
25030
  if (SW_SOURCE == null) {
24652
25031
  console.error("[pwa] op=sw status=500 reason=sw-source-missing");
24653
25032
  return c.text("Service worker unavailable", 500);
@@ -24656,12 +25035,12 @@ app56.get("/sw.js", (c) => {
24656
25035
  console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
24657
25036
  return c.body(SW_SOURCE);
24658
25037
  });
24659
- app56.get("/graph", (c) => {
25038
+ app60.get("/graph", (c) => {
24660
25039
  const host = (c.req.header("host") ?? "").split(":")[0];
24661
25040
  if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
24662
25041
  return c.html(cachedHtml("graph.html"));
24663
25042
  });
24664
- app56.get("/chat", (c) => {
25043
+ app60.get("/chat", (c) => {
24665
25044
  const host = (c.req.header("host") ?? "").split(":")[0];
24666
25045
  if (isOperatorHost(host, getOperatorDomains())) {
24667
25046
  console.log(`[host-class] host=${host} class=operator served=operator.html`);
@@ -24670,22 +25049,22 @@ app56.get("/chat", (c) => {
24670
25049
  if (isPublicHost(host)) return c.text("Not found", 404);
24671
25050
  return c.html(cachedHtml("chat.html"));
24672
25051
  });
24673
- app56.get("/data", (c) => {
25052
+ app60.get("/data", (c) => {
24674
25053
  const host = (c.req.header("host") ?? "").split(":")[0];
24675
25054
  if (isPublicHost(host)) return c.text("Not found", 404);
24676
25055
  return c.html(cachedHtml("data.html"));
24677
25056
  });
24678
- app56.get("/calendar", (c) => {
25057
+ app60.get("/calendar", (c) => {
24679
25058
  const host = (c.req.header("host") ?? "").split(":")[0];
24680
25059
  if (isPublicHost(host)) return c.text("Not found", 404);
24681
25060
  return c.html(cachedHtml("calendar.html"));
24682
25061
  });
24683
- app56.get("/browser", (c) => {
25062
+ app60.get("/browser", (c) => {
24684
25063
  const host = (c.req.header("host") ?? "").split(":")[0];
24685
25064
  if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
24686
25065
  return c.html(cachedHtml("browser.html"));
24687
25066
  });
24688
- app56.get("/:slug", async (c, next) => {
25067
+ app60.get("/:slug", async (c, next) => {
24689
25068
  const slug = c.req.param("slug");
24690
25069
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
24691
25070
  const account = resolveAccount();
@@ -24700,13 +25079,13 @@ app56.get("/:slug", async (c, next) => {
24700
25079
  await next();
24701
25080
  });
24702
25081
  if (brandFaviconPath !== "/favicon.ico") {
24703
- app56.get("/favicon.ico", (c) => {
25082
+ app60.get("/favicon.ico", (c) => {
24704
25083
  c.header("Cache-Control", "public, max-age=300");
24705
25084
  return c.redirect(brandFaviconPath, 302);
24706
25085
  });
24707
25086
  }
24708
- app56.use("/*", serveStatic({ root: "./public" }));
24709
- app56.all("*", (c) => {
25087
+ app60.use("/*", serveStatic({ root: "./public" }));
25088
+ app60.all("*", (c) => {
24710
25089
  const host = (c.req.header("host") ?? "").split(":")[0];
24711
25090
  const path2 = c.req.path;
24712
25091
  if (isPublicHost(host)) {
@@ -24720,7 +25099,7 @@ app56.all("*", (c) => {
24720
25099
  });
24721
25100
  var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
24722
25101
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
24723
- var httpServer = serve({ fetch: app56.fetch, port, hostname });
25102
+ var httpServer = serve({ fetch: app60.fetch, port, hostname });
24724
25103
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
24725
25104
  {
24726
25105
  const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, "..");
@@ -24744,6 +25123,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
24744
25123
  const loop = setInterval(runReconcile, RECONCILE_INTERVAL_MS);
24745
25124
  loop.unref();
24746
25125
  }
25126
+ startTimeEntryCensus(() => getSession());
24747
25127
  {
24748
25128
  const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, "..");
24749
25129
  const auditScript = resolve33(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
@@ -24820,7 +25200,7 @@ for (const m of SUBAPP_MANIFEST) {
24820
25200
  }
24821
25201
  try {
24822
25202
  const registered = [];
24823
- for (const r of app56.routes ?? []) {
25203
+ for (const r of app60.routes ?? []) {
24824
25204
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
24825
25205
  if (AGENT_SLUG_PATTERN.test(r.path)) {
24826
25206
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });