@rubytech/create-maxy-code 0.1.601 → 0.1.602

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 (253) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/hooks/video-frames-inject.sh +141 -0
  3. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +5 -1
  4. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
  5. package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
  6. package/payload/platform/plugins/docs/references/telegram-guide.md +2 -0
  7. package/payload/platform/plugins/scheduling/PLUGIN.md +2 -0
  8. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +67 -1
  9. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js.map +1 -1
  10. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +89 -1
  11. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -1
  12. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.d.ts +2 -0
  13. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.d.ts.map +1 -0
  14. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.js +160 -0
  15. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.js.map +1 -0
  16. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js +16 -0
  17. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js.map +1 -1
  18. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +31 -1
  19. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
  20. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +42 -4
  21. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
  22. package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.d.ts +101 -0
  23. package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.d.ts.map +1 -0
  24. package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.js +130 -0
  25. package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.js.map +1 -0
  26. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts +10 -1
  27. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts.map +1 -1
  28. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js.map +1 -1
  29. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +24 -0
  30. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts.map +1 -1
  31. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js +89 -0
  32. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
  33. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +67 -1
  34. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
  35. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js +31 -0
  36. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js.map +1 -1
  37. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +10 -1
  38. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  39. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +46 -1
  40. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  41. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +72 -4
  42. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  43. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +81 -4
  44. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
  45. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +50 -0
  46. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
  47. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +48 -7
  48. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
  49. package/payload/platform/plugins/telegram/PLUGIN.md +4 -0
  50. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.js +33 -1
  51. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.js.map +1 -1
  52. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.js +166 -1
  53. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.js.map +1 -1
  54. package/payload/platform/plugins/telegram/mcp/dist/index.js +39 -14
  55. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
  56. package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.d.ts +95 -0
  57. package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.d.ts.map +1 -1
  58. package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.js +125 -0
  59. package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.js.map +1 -1
  60. package/payload/platform/services/telegram-channel/dist/notification.d.ts +6 -0
  61. package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
  62. package/payload/platform/services/telegram-channel/dist/notification.js +12 -5
  63. package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
  64. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +5 -0
  65. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  66. package/payload/platform/services/whatsapp-channel/dist/notification.js +9 -3
  67. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  68. package/payload/platform/templates/account-settings.json +6 -0
  69. package/payload/server/chunk-CYU75QAV.js +377 -0
  70. package/payload/server/{chunk-34FPJYHN.js → chunk-GI5AVCRG.js} +87 -146
  71. package/payload/server/chunk-KUVNCAE4.js +77 -0
  72. package/payload/server/{manager-7BXVB76I.js → manager-VDHT3YYI.js} +2 -1
  73. package/payload/server/maxy-edge.js +33 -1
  74. package/payload/server/public/activity.html +6 -6
  75. package/payload/server/public/agents.html +5 -5
  76. package/payload/server/public/assets/{AdminLoginScreens-B3W6J6Bl.js → AdminLoginScreens-CaQqLuxZ.js} +1 -1
  77. package/payload/server/public/assets/AdminLoginScreens-CaQqLuxZ.js.br +0 -0
  78. package/payload/server/public/assets/AdminLoginScreens-CaQqLuxZ.js.gz +0 -0
  79. package/payload/server/public/assets/{AdminShell-C3R-vMZ5.js → AdminShell-D8WTrqem.js} +1 -1
  80. package/payload/server/public/assets/AdminShell-D8WTrqem.js.br +0 -0
  81. package/payload/server/public/assets/AdminShell-D8WTrqem.js.gz +0 -0
  82. package/payload/server/public/assets/{activity-tzv68iBs.js → activity-B3fiJrC2.js} +1 -1
  83. package/payload/server/public/assets/activity-B3fiJrC2.js.br +0 -0
  84. package/payload/server/public/assets/activity-B3fiJrC2.js.gz +0 -0
  85. package/payload/server/public/assets/admin-ouF-DflP.js +1 -0
  86. package/payload/server/public/assets/admin-ouF-DflP.js.br +0 -0
  87. package/payload/server/public/assets/admin-ouF-DflP.js.gz +0 -0
  88. package/payload/server/public/assets/{agents-DUZfeY3X.js → agents-C8RSXHdh.js} +1 -1
  89. package/payload/server/public/assets/agents-C8RSXHdh.js.br +0 -0
  90. package/payload/server/public/assets/agents-C8RSXHdh.js.gz +0 -0
  91. package/payload/server/public/assets/{browser-DwLaXqjO.js → browser-Dbv6-Rag.js} +1 -1
  92. package/payload/server/public/assets/browser-Dbv6-Rag.js.br +0 -0
  93. package/payload/server/public/assets/browser-Dbv6-Rag.js.gz +0 -0
  94. package/payload/server/public/assets/{calendar-Cli8Qjl9.js → calendar-vJjtsH9n.js} +1 -1
  95. package/payload/server/public/assets/calendar-vJjtsH9n.js.br +0 -0
  96. package/payload/server/public/assets/calendar-vJjtsH9n.js.gz +0 -0
  97. package/payload/server/public/assets/chat-cqL4qPUy.js +1 -0
  98. package/payload/server/public/assets/chat-cqL4qPUy.js.br +1 -0
  99. package/payload/server/public/assets/chat-cqL4qPUy.js.gz +0 -0
  100. package/payload/server/public/assets/chevron-left-DB98DSG3.js +1 -0
  101. package/payload/server/public/assets/chevron-left-DB98DSG3.js.br +0 -0
  102. package/payload/server/public/assets/clock-4YwsYe4L.js +1 -0
  103. package/payload/server/public/assets/clock-4YwsYe4L.js.br +0 -0
  104. package/payload/server/public/assets/clock-4YwsYe4L.js.gz +0 -0
  105. package/payload/server/public/assets/{copy-yhhwfEbQ.js → copy-DyG7sC5o.js} +1 -1
  106. package/payload/server/public/assets/copy-DyG7sC5o.js.br +0 -0
  107. package/payload/server/public/assets/copy-DyG7sC5o.js.gz +0 -0
  108. package/payload/server/public/assets/data-BAzLtx9C.js +1 -0
  109. package/payload/server/public/assets/data-BAzLtx9C.js.br +0 -0
  110. package/payload/server/public/assets/data-BAzLtx9C.js.gz +0 -0
  111. package/payload/server/public/assets/{field-jg0YQNDy.js → field-Bx6pM-vq.js} +1 -1
  112. package/payload/server/public/assets/field-Bx6pM-vq.js.br +0 -0
  113. package/payload/server/public/assets/field-Bx6pM-vq.js.gz +0 -0
  114. package/payload/server/public/assets/{file-text-D0EdW7h4.js → file-text-CpHWsMGe.js} +1 -1
  115. package/payload/server/public/assets/file-text-CpHWsMGe.js.br +0 -0
  116. package/payload/server/public/assets/file-text-CpHWsMGe.js.gz +0 -0
  117. package/payload/server/public/assets/{graph--AUr4uBc.js → graph-DjOywuv_.js} +1 -1
  118. package/payload/server/public/assets/graph-DjOywuv_.js.br +0 -0
  119. package/payload/server/public/assets/graph-DjOywuv_.js.gz +0 -0
  120. package/payload/server/public/assets/{graph-labels-DM0CiAX1.js → graph-labels-CGWtqa-m.js} +1 -1
  121. package/payload/server/public/assets/graph-labels-CGWtqa-m.js.br +0 -0
  122. package/payload/server/public/assets/graph-labels-CGWtqa-m.js.gz +0 -0
  123. package/payload/server/public/assets/{jsx-runtime-lfcjzaWi.css → jsx-runtime-D75_aR1J.css} +1 -1
  124. package/payload/server/public/assets/jsx-runtime-D75_aR1J.css.br +0 -0
  125. package/payload/server/public/assets/{jsx-runtime-lfcjzaWi.css.gz → jsx-runtime-D75_aR1J.css.gz} +0 -0
  126. package/payload/server/public/assets/{operator-CNYKStFX.js → operator-_DN0RF1R.js} +1 -1
  127. package/payload/server/public/assets/operator-_DN0RF1R.js.br +0 -0
  128. package/payload/server/public/assets/operator-_DN0RF1R.js.gz +0 -0
  129. package/payload/server/public/assets/page-DI4qQIK0.js +1 -0
  130. package/payload/server/public/assets/page-DI4qQIK0.js.br +0 -0
  131. package/payload/server/public/assets/page-DI4qQIK0.js.gz +0 -0
  132. package/payload/server/public/assets/page-zCwgrs8m.js +32 -0
  133. package/payload/server/public/assets/page-zCwgrs8m.js.br +0 -0
  134. package/payload/server/public/assets/page-zCwgrs8m.js.gz +0 -0
  135. package/payload/server/public/assets/play-CHQ5a9yh.js +1 -0
  136. package/payload/server/public/assets/play-CHQ5a9yh.js.br +0 -0
  137. package/payload/server/public/assets/play-CHQ5a9yh.js.gz +0 -0
  138. package/payload/server/public/assets/{public-7gXDqCog.js → public-DDVWBNSH.js} +1 -1
  139. package/payload/server/public/assets/public-DDVWBNSH.js.br +0 -0
  140. package/payload/server/public/assets/public-DDVWBNSH.js.gz +0 -0
  141. package/payload/server/public/assets/{rotate-ccw-DhqNTPpo.js → rotate-ccw-xTwkf-m7.js} +1 -1
  142. package/payload/server/public/assets/rotate-ccw-xTwkf-m7.js.br +0 -0
  143. package/payload/server/public/assets/rotate-ccw-xTwkf-m7.js.gz +0 -0
  144. package/payload/server/public/assets/{routines-DN_yDtEj.js → routines-Bu5MdNmG.js} +1 -1
  145. package/payload/server/public/assets/routines-Bu5MdNmG.js.br +0 -0
  146. package/payload/server/public/assets/routines-Bu5MdNmG.js.gz +0 -0
  147. package/payload/server/public/assets/{skills-pb_3BdOl.js → skills-DRunh5vy.js} +1 -1
  148. package/payload/server/public/assets/skills-DRunh5vy.js.br +0 -0
  149. package/payload/server/public/assets/skills-DRunh5vy.js.gz +0 -0
  150. package/payload/server/public/assets/{tasks-BQm4boat.js → tasks-DI2fznvd.js} +1 -1
  151. package/payload/server/public/assets/tasks-DI2fznvd.js.br +0 -0
  152. package/payload/server/public/assets/tasks-DI2fznvd.js.gz +0 -0
  153. package/payload/server/public/assets/{triangle-alert-d7yjaIqv.js → triangle-alert-B6CHZeUf.js} +1 -1
  154. package/payload/server/public/assets/triangle-alert-B6CHZeUf.js.br +0 -0
  155. package/payload/server/public/assets/triangle-alert-B6CHZeUf.js.gz +0 -0
  156. package/payload/server/public/assets/{useCopyFeedback-CZ6Qhfkj.js → useCopyFeedback-6rU2IEPk.js} +1 -1
  157. package/payload/server/public/assets/useCopyFeedback-6rU2IEPk.js.br +2 -0
  158. package/payload/server/public/assets/useCopyFeedback-6rU2IEPk.js.gz +0 -0
  159. package/payload/server/public/assets/{useMediaQuery-R1smYLx4.js → useMediaQuery-D7A5Bzs3.js} +1 -1
  160. package/payload/server/public/assets/useMediaQuery-D7A5Bzs3.js.br +0 -0
  161. package/payload/server/public/assets/useMediaQuery-D7A5Bzs3.js.gz +0 -0
  162. package/payload/server/public/assets/useVoiceRecorder-CptrerVA.js +2 -0
  163. package/payload/server/public/assets/useVoiceRecorder-CptrerVA.js.br +0 -0
  164. package/payload/server/public/assets/useVoiceRecorder-CptrerVA.js.gz +0 -0
  165. package/payload/server/public/assets/{wrench-DL1pbaCs.js → wrench-DyX4C8aY.js} +1 -1
  166. package/payload/server/public/assets/wrench-DyX4C8aY.js.br +0 -0
  167. package/payload/server/public/assets/wrench-DyX4C8aY.js.gz +0 -0
  168. package/payload/server/public/browser.html +5 -5
  169. package/payload/server/public/calendar.html +8 -8
  170. package/payload/server/public/chat.html +14 -14
  171. package/payload/server/public/data.html +12 -12
  172. package/payload/server/public/field.html +3 -3
  173. package/payload/server/public/graph.html +10 -10
  174. package/payload/server/public/index.html +14 -14
  175. package/payload/server/public/operator.html +15 -15
  176. package/payload/server/public/public.html +14 -14
  177. package/payload/server/public/routines.html +8 -8
  178. package/payload/server/public/skills.html +6 -6
  179. package/payload/server/public/tasks.html +7 -7
  180. package/payload/server/server.js +634 -461
  181. package/payload/server/video-extract.js +36 -0
  182. package/payload/server/public/assets/AdminLoginScreens-B3W6J6Bl.js.br +0 -0
  183. package/payload/server/public/assets/AdminLoginScreens-B3W6J6Bl.js.gz +0 -0
  184. package/payload/server/public/assets/AdminShell-C3R-vMZ5.js.br +0 -0
  185. package/payload/server/public/assets/AdminShell-C3R-vMZ5.js.gz +0 -0
  186. package/payload/server/public/assets/activity-tzv68iBs.js.br +0 -0
  187. package/payload/server/public/assets/activity-tzv68iBs.js.gz +0 -0
  188. package/payload/server/public/assets/admin-CzW_9jm3.js +0 -1
  189. package/payload/server/public/assets/admin-CzW_9jm3.js.br +0 -0
  190. package/payload/server/public/assets/admin-CzW_9jm3.js.gz +0 -0
  191. package/payload/server/public/assets/agents-DUZfeY3X.js.br +0 -0
  192. package/payload/server/public/assets/agents-DUZfeY3X.js.gz +0 -0
  193. package/payload/server/public/assets/browser-DwLaXqjO.js.br +0 -0
  194. package/payload/server/public/assets/browser-DwLaXqjO.js.gz +0 -0
  195. package/payload/server/public/assets/calendar-Cli8Qjl9.js.br +0 -0
  196. package/payload/server/public/assets/calendar-Cli8Qjl9.js.gz +0 -0
  197. package/payload/server/public/assets/chat-ByAgBgm1.js +0 -1
  198. package/payload/server/public/assets/chat-ByAgBgm1.js.br +0 -1
  199. package/payload/server/public/assets/chat-ByAgBgm1.js.gz +0 -0
  200. package/payload/server/public/assets/chevron-left-BIYVnwvk.js +0 -1
  201. package/payload/server/public/assets/chevron-left-BIYVnwvk.js.br +0 -0
  202. package/payload/server/public/assets/clock-Dzy79hq3.js +0 -1
  203. package/payload/server/public/assets/clock-Dzy79hq3.js.br +0 -0
  204. package/payload/server/public/assets/clock-Dzy79hq3.js.gz +0 -0
  205. package/payload/server/public/assets/copy-yhhwfEbQ.js.br +0 -0
  206. package/payload/server/public/assets/copy-yhhwfEbQ.js.gz +0 -0
  207. package/payload/server/public/assets/data-CsMMki2A.js +0 -1
  208. package/payload/server/public/assets/data-CsMMki2A.js.br +0 -0
  209. package/payload/server/public/assets/data-CsMMki2A.js.gz +0 -0
  210. package/payload/server/public/assets/field-jg0YQNDy.js.br +0 -0
  211. package/payload/server/public/assets/field-jg0YQNDy.js.gz +0 -0
  212. package/payload/server/public/assets/file-text-D0EdW7h4.js.br +0 -0
  213. package/payload/server/public/assets/file-text-D0EdW7h4.js.gz +0 -0
  214. package/payload/server/public/assets/graph--AUr4uBc.js.br +0 -0
  215. package/payload/server/public/assets/graph--AUr4uBc.js.gz +0 -0
  216. package/payload/server/public/assets/graph-labels-DM0CiAX1.js.br +0 -0
  217. package/payload/server/public/assets/graph-labels-DM0CiAX1.js.gz +0 -0
  218. package/payload/server/public/assets/jsx-runtime-lfcjzaWi.css.br +0 -0
  219. package/payload/server/public/assets/operator-CNYKStFX.js.br +0 -0
  220. package/payload/server/public/assets/operator-CNYKStFX.js.gz +0 -0
  221. package/payload/server/public/assets/page-DSsEpl8J.js +0 -32
  222. package/payload/server/public/assets/page-DSsEpl8J.js.br +0 -0
  223. package/payload/server/public/assets/page-DSsEpl8J.js.gz +0 -0
  224. package/payload/server/public/assets/page-DjhmwxnY.js +0 -1
  225. package/payload/server/public/assets/page-DjhmwxnY.js.br +0 -0
  226. package/payload/server/public/assets/page-DjhmwxnY.js.gz +0 -0
  227. package/payload/server/public/assets/play-DhZlml5b.js +0 -1
  228. package/payload/server/public/assets/play-DhZlml5b.js.br +0 -0
  229. package/payload/server/public/assets/play-DhZlml5b.js.gz +0 -0
  230. package/payload/server/public/assets/public-7gXDqCog.js.br +0 -0
  231. package/payload/server/public/assets/public-7gXDqCog.js.gz +0 -0
  232. package/payload/server/public/assets/rotate-ccw-DhqNTPpo.js.br +0 -0
  233. package/payload/server/public/assets/rotate-ccw-DhqNTPpo.js.gz +0 -0
  234. package/payload/server/public/assets/routines-DN_yDtEj.js.br +0 -0
  235. package/payload/server/public/assets/routines-DN_yDtEj.js.gz +0 -0
  236. package/payload/server/public/assets/skills-pb_3BdOl.js.br +0 -0
  237. package/payload/server/public/assets/skills-pb_3BdOl.js.gz +0 -0
  238. package/payload/server/public/assets/tasks-BQm4boat.js.br +0 -0
  239. package/payload/server/public/assets/tasks-BQm4boat.js.gz +0 -0
  240. package/payload/server/public/assets/triangle-alert-d7yjaIqv.js.br +0 -0
  241. package/payload/server/public/assets/triangle-alert-d7yjaIqv.js.gz +0 -0
  242. package/payload/server/public/assets/useCopyFeedback-CZ6Qhfkj.js.br +0 -0
  243. package/payload/server/public/assets/useCopyFeedback-CZ6Qhfkj.js.gz +0 -0
  244. package/payload/server/public/assets/useMediaQuery-R1smYLx4.js.br +0 -0
  245. package/payload/server/public/assets/useMediaQuery-R1smYLx4.js.gz +0 -0
  246. package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js +0 -2
  247. package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js.br +0 -0
  248. package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js.gz +0 -0
  249. package/payload/server/public/assets/wrench-DL1pbaCs.js.br +0 -0
  250. package/payload/server/public/assets/wrench-DL1pbaCs.js.gz +0 -0
  251. /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js → jsx-runtime-B2Q1UOSJ.js} +0 -0
  252. /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js.br → jsx-runtime-B2Q1UOSJ.js.br} +0 -0
  253. /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js.gz → jsx-runtime-B2Q1UOSJ.js.gz} +0 -0
@@ -71,6 +71,11 @@ import {
71
71
  vncLog,
72
72
  walkPremiumBundles
73
73
  } from "./chunk-MNN2RWJR.js";
74
+ import {
75
+ audioExtension,
76
+ isAudioMime,
77
+ isVideoMime
78
+ } from "./chunk-KUVNCAE4.js";
74
79
  import {
75
80
  ACCOUNTS_ROOT,
76
81
  DATA_ROOT,
@@ -210,13 +215,12 @@ import {
210
215
  storeMediaBuffer,
211
216
  storePublicAttachment,
212
217
  toWhatsappJid,
213
- transcribe,
214
218
  validateAccountIdEnv,
215
219
  validateFilePathInAccount,
216
220
  waitForConnection,
217
221
  warnNonUuidAccount,
218
222
  writeChatMetadataMerged
219
- } from "./chunk-34FPJYHN.js";
223
+ } from "./chunk-GI5AVCRG.js";
220
224
  import {
221
225
  ACCOUNTS_DIR,
222
226
  AGENT_SLUG_PATTERN,
@@ -282,6 +286,10 @@ import {
282
286
  verifyConversationOwnership,
283
287
  writeAdminUserAndPerson
284
288
  } from "./chunk-6AQYMT6C.js";
289
+ import {
290
+ extractVideo,
291
+ transcribe
292
+ } from "./chunk-CYU75QAV.js";
285
293
  import {
286
294
  D1_MAX_SQL_STATEMENT_BYTES,
287
295
  D1_QUERY_MAX_BODY_BYTES,
@@ -4252,6 +4260,74 @@ var TELEGRAM_CARD_TOOLS = /* @__PURE__ */ new Set([
4252
4260
  "mcp__telegram__telegram-card",
4253
4261
  "mcp__plugin_telegram_telegram__telegram-card"
4254
4262
  ]);
4263
+ var TELEGRAM_MEDIA_SEND_TOOLS = /* @__PURE__ */ new Set([
4264
+ "mcp__telegram__telegram-media-send",
4265
+ "mcp__plugin_telegram_telegram__telegram-media-send"
4266
+ ]);
4267
+ var TELEGRAM_ASK_TOOLS = /* @__PURE__ */ new Set([
4268
+ "mcp__telegram__telegram-ask",
4269
+ "mcp__plugin_telegram_telegram__telegram-ask"
4270
+ ]);
4271
+ var TELEGRAM_API_TOOLS = /* @__PURE__ */ new Set([
4272
+ "mcp__telegram__telegram-api",
4273
+ "mcp__plugin_telegram_telegram__telegram-api"
4274
+ ]);
4275
+ var TELEGRAM_API_TRANSMIT_METHODS = /* @__PURE__ */ new Set(["sendMessage", "editMessageText"]);
4276
+ var TELEGRAM_SEND_TOOLS = /* @__PURE__ */ new Set([
4277
+ ...TELEGRAM_CARD_TOOLS,
4278
+ ...TELEGRAM_MEDIA_SEND_TOOLS,
4279
+ ...TELEGRAM_ASK_TOOLS,
4280
+ ...TELEGRAM_API_TOOLS
4281
+ ]);
4282
+ function chatIdOf(value) {
4283
+ if (typeof value === "string") return value;
4284
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
4285
+ return "";
4286
+ }
4287
+ function cardOutcome(text, isError) {
4288
+ const v = /card-result: outcome=(\w+)/.exec(text)?.[1];
4289
+ if (v === "edited" || v === "unchanged" || v === "sent") return v;
4290
+ if (v === "none") return "failed";
4291
+ return isError ? "failed" : "sent";
4292
+ }
4293
+ function pendingSendOf(name, input) {
4294
+ const i = input ?? {};
4295
+ if (TELEGRAM_CARD_TOOLS.has(name)) {
4296
+ return {
4297
+ kind: "telegram-card",
4298
+ text: typeof i.text === "string" ? i.text : "",
4299
+ buttons: parseCardButtonsFromInput(input),
4300
+ chatId: chatIdOf(i.chatId),
4301
+ ts: null
4302
+ };
4303
+ }
4304
+ if (TELEGRAM_MEDIA_SEND_TOOLS.has(name) || TELEGRAM_ASK_TOOLS.has(name)) {
4305
+ const kind = typeof i.kind === "string" ? i.kind : "";
4306
+ const text = TELEGRAM_MEDIA_SEND_TOOLS.has(name) ? typeof i.caption === "string" ? i.caption : "" : typeof i.question === "string" ? i.question : "";
4307
+ return {
4308
+ kind: "telegram-send",
4309
+ label: kind,
4310
+ text,
4311
+ chatId: chatIdOf(i.chatId),
4312
+ edit: kind.startsWith("edit") || kind.startsWith("stop"),
4313
+ ts: null
4314
+ };
4315
+ }
4316
+ if (TELEGRAM_API_TOOLS.has(name)) {
4317
+ const method = typeof i.method === "string" ? i.method : "";
4318
+ if (!TELEGRAM_API_TRANSMIT_METHODS.has(method)) return null;
4319
+ const params = i.params ?? {};
4320
+ return {
4321
+ kind: "telegram-send",
4322
+ label: method,
4323
+ text: typeof params.text === "string" ? params.text : "",
4324
+ chatId: chatIdOf(params.chat_id),
4325
+ edit: method === "editMessageText",
4326
+ ts: null
4327
+ };
4328
+ }
4329
+ return null;
4330
+ }
4255
4331
  function parseCardButtonsFromInput(input) {
4256
4332
  const rows = input?.buttons;
4257
4333
  if (!Array.isArray(rows)) return [];
@@ -4396,7 +4472,29 @@ function erroredToolUseIds(lines) {
4396
4472
  }
4397
4473
  return ids;
4398
4474
  }
4399
- function assistantTurns(content, ts, promoteFinal = false, erroredIds = /* @__PURE__ */ new Set(), uuid) {
4475
+ function answeredToolUseIds(lines) {
4476
+ const ids = /* @__PURE__ */ new Set();
4477
+ for (const line of lines) {
4478
+ if (!line || line[0] !== "{" || !line.includes("tool_use_id")) continue;
4479
+ let row;
4480
+ try {
4481
+ const parsed = JSON.parse(line);
4482
+ if (!parsed || typeof parsed !== "object") continue;
4483
+ row = parsed;
4484
+ } catch {
4485
+ continue;
4486
+ }
4487
+ const content = row.message?.content;
4488
+ if (!Array.isArray(content)) continue;
4489
+ for (const block of content) {
4490
+ if (!block || typeof block !== "object") continue;
4491
+ const b = block;
4492
+ if (b.type === "tool_result" && typeof b.tool_use_id === "string") ids.add(b.tool_use_id);
4493
+ }
4494
+ }
4495
+ return ids;
4496
+ }
4497
+ function assistantTurns(content, ts, promoteFinal = false, erroredIds = /* @__PURE__ */ new Set(), uuid, answeredIds = /* @__PURE__ */ new Set(), pending = /* @__PURE__ */ new Map(), fullRead = true) {
4400
4498
  if (!Array.isArray(content)) return [];
4401
4499
  const out = [];
4402
4500
  for (const block of content) {
@@ -4430,21 +4528,21 @@ function assistantTurns(content, ts, promoteFinal = false, erroredIds = /* @__PU
4430
4528
  } else {
4431
4529
  out.push({ kind: "agent-file", files, caption, ts });
4432
4530
  }
4433
- } else if (b.type === "tool_use" && typeof b.name === "string" && TELEGRAM_CARD_TOOLS.has(b.name)) {
4434
- const input = b.input ?? {};
4435
- out.push({
4436
- kind: "telegram-card",
4437
- text: typeof input.text === "string" ? input.text : "",
4438
- buttons: parseCardButtonsFromInput(b.input),
4439
- ts
4440
- });
4531
+ } else if (b.type === "tool_use" && typeof b.name === "string" && TELEGRAM_SEND_TOOLS.has(b.name)) {
4532
+ const send = pendingSendOf(b.name, b.input);
4533
+ const id = typeof b.id === "string" ? b.id : null;
4534
+ if (send !== null && id !== null && (answeredIds.has(id) || !fullRead)) {
4535
+ pending.set(id, { ...send, ts });
4536
+ } else {
4537
+ out.push({ kind: "tool-call", name: b.name, input: b.input ?? null, ts });
4538
+ }
4441
4539
  } else if (b.type === "tool_use" && typeof b.name === "string") {
4442
4540
  out.push({ kind: "tool-call", name: b.name, input: b.input ?? null, ts });
4443
4541
  }
4444
4542
  }
4445
4543
  return out;
4446
4544
  }
4447
- function toolResultTurns(content, ts) {
4545
+ function toolResultTurns(content, ts, pending = /* @__PURE__ */ new Map()) {
4448
4546
  if (!Array.isArray(content)) return [];
4449
4547
  const out = [];
4450
4548
  for (const block of content) {
@@ -4455,6 +4553,15 @@ function toolResultTurns(content, ts) {
4455
4553
  (c) => c && typeof c === "object" && typeof c.text === "string" ? c.text : ""
4456
4554
  ).join("") : "";
4457
4555
  out.push({ kind: "tool-result", text, isError: b.is_error === true, ts });
4556
+ const id = b.tool_use_id;
4557
+ if (typeof id !== "string") continue;
4558
+ const send = pending.get(id);
4559
+ if (send === void 0) continue;
4560
+ pending.delete(id);
4561
+ const outcome = send.kind === "telegram-card" ? cardOutcome(text, b.is_error === true) : b.is_error === true ? "failed" : send.edit ? "edited" : "sent";
4562
+ out.push(
4563
+ send.kind === "telegram-card" ? { kind: "telegram-card", text: send.text, buttons: send.buttons, chatId: send.chatId, outcome, ts: send.ts } : { kind: "telegram-send", label: send.label, text: send.text, chatId: send.chatId, outcome, ts: send.ts }
4564
+ );
4458
4565
  }
4459
4566
  return out;
4460
4567
  }
@@ -4479,9 +4586,11 @@ function renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress, uuid,
4479
4586
  out.push(operatorInboundTurn(u, ts, uuid, census));
4480
4587
  }
4481
4588
  }
4482
- function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(), turnCtx = {}) {
4589
+ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(), turnCtx = {}, fullRead = true) {
4483
4590
  const out = [];
4591
+ const pendingSends = turnCtx.pendingTelegramSends ??= /* @__PURE__ */ new Map();
4484
4592
  const erroredIds = erroredToolUseIds(lines);
4593
+ const answeredIds = lines.some((l) => l.includes("telegram-")) ? answeredToolUseIds(lines) : /* @__PURE__ */ new Set();
4485
4594
  for (const line of lines) {
4486
4595
  if (!line || line[0] !== "{") continue;
4487
4596
  let row;
@@ -4505,7 +4614,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
4505
4614
  }
4506
4615
  const isEnd = msg?.stop_reason === "end_turn";
4507
4616
  const promoteFinal = isEnd && turnCtx.lastChannelSource !== void 0;
4508
- out.push(...assistantTurns(msg?.content, ts, promoteFinal, erroredIds, asString(row.uuid) ?? void 0));
4617
+ out.push(...assistantTurns(msg?.content, ts, promoteFinal, erroredIds, asString(row.uuid) ?? void 0, answeredIds, pendingSends, fullRead));
4509
4618
  continue;
4510
4619
  }
4511
4620
  if (row.type === "queue-operation" && row.operation === "enqueue") {
@@ -4538,7 +4647,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
4538
4647
  continue;
4539
4648
  }
4540
4649
  if (Array.isArray(msg.content)) {
4541
- out.push(...toolResultTurns(msg.content, ts));
4650
+ out.push(...toolResultTurns(msg.content, ts, pendingSends));
4542
4651
  continue;
4543
4652
  }
4544
4653
  const text = asString(msg.content);
@@ -5650,48 +5759,6 @@ function logPublicAddress(slug, verdict) {
5650
5759
  import { writeFile, mkdtemp, rm } from "fs/promises";
5651
5760
  import { tmpdir as tmpdir2 } from "os";
5652
5761
  import { join as join7 } from "path";
5653
-
5654
- // app/lib/stt/audio-mime.ts
5655
- var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
5656
- "audio/ogg",
5657
- "audio/opus",
5658
- "audio/webm",
5659
- "audio/mp4",
5660
- "audio/x-m4a",
5661
- "audio/mpeg",
5662
- "audio/wav",
5663
- "video/mp4"
5664
- ]);
5665
- function normalizeMime(mimeType) {
5666
- return mimeType.split(";")[0].trim().toLowerCase();
5667
- }
5668
- function isAudioMime(mimeType) {
5669
- return AUDIO_MIME_TYPES.has(normalizeMime(mimeType));
5670
- }
5671
- function audioExtension(mimeType) {
5672
- switch (normalizeMime(mimeType)) {
5673
- case "audio/ogg":
5674
- return ".ogg";
5675
- case "audio/opus":
5676
- return ".opus";
5677
- case "audio/webm":
5678
- return ".webm";
5679
- case "audio/mp4":
5680
- return ".m4a";
5681
- case "audio/x-m4a":
5682
- return ".m4a";
5683
- case "audio/mpeg":
5684
- return ".mp3";
5685
- case "audio/wav":
5686
- return ".wav";
5687
- case "video/mp4":
5688
- return ".mp4";
5689
- default:
5690
- return ".audio";
5691
- }
5692
- }
5693
-
5694
- // app/lib/stt/voice-note.ts
5695
5762
  var TAG4 = "[voice]";
5696
5763
  async function transcribeVoiceNote(file, source) {
5697
5764
  const startMs = Date.now();
@@ -7487,7 +7554,7 @@ async function defaultHttpGet(url) {
7487
7554
  }
7488
7555
  }
7489
7556
  async function defaultResolve(accountId) {
7490
- const { resolveSocket: resolveSocket2 } = await import("./manager-7BXVB76I.js");
7557
+ const { resolveSocket: resolveSocket2 } = await import("./manager-VDHT3YYI.js");
7491
7558
  return resolveSocket2(accountId);
7492
7559
  }
7493
7560
  async function fetchAvatar(accountId, jid, deps = {}) {
@@ -15841,7 +15908,7 @@ data: ${JSON.stringify(obj)}
15841
15908
  const { lines, nextOffset } = splitNewLines(buf, offset);
15842
15909
  offset = nextOffset;
15843
15910
  let n = 0;
15844
- for (const turn of parseTranscript(lines, queuedPendingSuppress, turnCtx)) {
15911
+ for (const turn of parseTranscript(lines, queuedPendingSuppress, turnCtx, false)) {
15845
15912
  send(controller, enrichAdminAttachments(enrichDownloads(turn, scratchpadRoot), sessionId), offset);
15846
15913
  actx.lastParentTurns.push(turn);
15847
15914
  if (turn.kind === "agent-error") {
@@ -16987,6 +17054,19 @@ async function authorizeAccountWrite(c, accountId) {
16987
17054
  return { ok: true, via: "session" };
16988
17055
  }
16989
17056
 
17057
+ // app/lib/video/webchat-video.ts
17058
+ var TAG26 = "[video]";
17059
+ async function extractWebchatVideo(file, extractImpl = extractVideo) {
17060
+ if (!isVideoMime(file.mimeType)) return void 0;
17061
+ try {
17062
+ return await extractImpl(file.storagePath, file.mimeType);
17063
+ } catch (err) {
17064
+ const reason = err instanceof Error ? err.message : String(err);
17065
+ console.error(`${TAG26} webchat extract failed error=${reason} path=${file.storagePath}`);
17066
+ return void 0;
17067
+ }
17068
+ }
17069
+
16990
17070
  // ../lib/models/src/index.ts
16991
17071
  var OPUS_MODEL = "claude-opus-5[1m]";
16992
17072
  var SONNET_MODEL = "claude-sonnet-5";
@@ -17422,6 +17502,18 @@ async function reapplyLeversViaManager() {
17422
17502
  }
17423
17503
  var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
17424
17504
  var sendSeq = 0;
17505
+ var transcribingKeys = /* @__PURE__ */ new Map();
17506
+ function markTranscribing(key2) {
17507
+ transcribingKeys.set(key2, (transcribingKeys.get(key2) ?? 0) + 1);
17508
+ }
17509
+ function clearTranscribing(key2) {
17510
+ const left = (transcribingKeys.get(key2) ?? 1) - 1;
17511
+ if (left > 0) transcribingKeys.set(key2, left);
17512
+ else transcribingKeys.delete(key2);
17513
+ }
17514
+ function isTranscribing(key2) {
17515
+ return (transcribingKeys.get(key2) ?? 0) > 0;
17516
+ }
17425
17517
  function createWebchatRoutes(deps) {
17426
17518
  const app81 = new Hono();
17427
17519
  app81.post("/send", requireAdminSession, async (c) => {
@@ -17532,13 +17624,17 @@ function createWebchatRoutes(deps) {
17532
17624
  deliveryKey = `session:${deliverySessionId}`;
17533
17625
  deliveryAccountId = bootstrapAccountId;
17534
17626
  }
17627
+ let audioFile;
17628
+ let kind = "files";
17629
+ const stored = [];
17630
+ const sendId = sendIdFromResolve ?? ++sendSeq;
17535
17631
  if (isMultipart) {
17536
- const kind = files.some((f) => isAudioMime(f.type)) ? "voice" : "files";
17632
+ kind = files.some((f) => isAudioMime(f.type)) ? "voice" : "files";
17537
17633
  if (files.length > MAX_FILES_PER_MESSAGE) {
17538
17634
  console.error(`[webchat:inbound] op=send-refused kind=${kind} reason=too-many-files count=${files.length}`);
17539
17635
  return c.json({ error: `Maximum ${MAX_FILES_PER_MESSAGE} files per message.` }, 422);
17540
17636
  }
17541
- const audioFile = files.find((f) => isAudioMime(f.type));
17637
+ audioFile = files.find((f) => isAudioMime(f.type));
17542
17638
  const regularFiles = files.filter((f) => !isAudioMime(f.type));
17543
17639
  for (const file of regularFiles) {
17544
17640
  try {
@@ -17552,7 +17648,6 @@ function createWebchatRoutes(deps) {
17552
17648
  return c.json({ error: detail }, 422);
17553
17649
  }
17554
17650
  }
17555
- const stored = [];
17556
17651
  if (audioFile) {
17557
17652
  if (audioFile.size > MAX_FILE_SIZE_BYTES) {
17558
17653
  console.error(`[webchat:inbound] op=send-refused kind=voice reason=oversize bytes=${audioFile.size}`);
@@ -17565,14 +17660,6 @@ function createWebchatRoutes(deps) {
17565
17660
  console.error(`[webchat:inbound] op=send-refused kind=voice reason=audio-store-failed detail=${detail}`);
17566
17661
  return c.json({ error: "failed to store voice recording" }, 500);
17567
17662
  }
17568
- const result = await transcribeVoiceNote(audioFile, "admin");
17569
- if (result.ok) {
17570
- text = text.length > 0 ? `${text}
17571
-
17572
- ${result.result.text}` : result.result.text;
17573
- } else {
17574
- console.error(`[webchat:inbound] op=stt-failed kind=voice detail=${result.error}`);
17575
- }
17576
17663
  }
17577
17664
  try {
17578
17665
  for (const file of regularFiles) {
@@ -17588,51 +17675,87 @@ ${result.result.text}` : result.result.text;
17588
17675
  const ext = dot >= 0 ? s.filename.slice(dot).toLowerCase() : "";
17589
17676
  console.log(`[attach-ingest] mime=${s.mimeType} ext=${ext} converted=${!!s.readableTextPath} path=${s.storagePath}`);
17590
17677
  }
17591
- if (stored.length > 0) {
17592
- const listing = stored.map((s) => `${s.filename} (${s.readableTextPath ?? s.storagePath})`).join(", ");
17593
- const note = `[The operator uploaded ${stored.length} file(s): ${listing}]`;
17594
- text = text.length > 0 ? `${text}
17595
-
17596
- ${note}` : note;
17597
- }
17598
- if (text.length === 0) {
17678
+ if (text.length === 0 && stored.length === 0) {
17599
17679
  console.error(`[webchat:inbound] op=send-refused kind=${kind} reason=empty-text`);
17600
17680
  return c.json({ error: "text required" }, 400);
17601
17681
  }
17602
- console.log(`[webchat:inbound] op=send-parsed kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
17603
- }
17604
- if (target !== void 0 && await managerActivity(deliverySessionId) === "busy") {
17605
- console.log(`[webchat:inbound] op=queued-busy sessionId=${deliverySessionId.slice(0, 8)} key=${deliveryKey}`);
17606
17682
  }
17607
- const adminUserId = requesterUserId ?? void 0;
17608
- const inboundStartedAt = Date.now();
17609
- const sendId = sendIdFromResolve ?? ++sendSeq;
17610
- const replyContext = resolveQuoted(deliverySessionId, quotedUuid, sendId);
17611
- const inbound = await deps.handleInbound({
17612
- role: "admin",
17613
- accountId: deliveryAccountId,
17614
- key: deliveryKey,
17615
- text,
17616
- sessionId: deliverySessionId,
17617
- adminUserId,
17618
- ...replyContext ? { replyContext } : {}
17619
- });
17620
- const turnSessionId = deliverySessionId;
17621
17683
  const keyDisplay2 = deliveryKey.slice(0, "session:".length + 8);
17622
- const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
17623
- console.error(
17624
- `[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"} acceptMs=${Date.now() - inboundStartedAt} spawn=${inbound.spawn !== null ? "triggered" : "none"}`
17625
- );
17626
- const turnTimer = setTimeout(() => {
17627
- const now = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
17628
- const grew = now !== null && (baseline === null || now > baseline);
17629
- if (grew) {
17630
- console.error(`[webchat:inbound] op=send-turned key=${keyDisplay2} sendId=${sendId} bytes=${now}`);
17631
- } else {
17632
- console.error(`[webchat:inbound] op=send-no-turn key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
17684
+ const completeSend = async () => {
17685
+ if (isMultipart) {
17686
+ if (audioFile) {
17687
+ const result = await transcribeVoiceNote(audioFile, "admin");
17688
+ if (result.ok) {
17689
+ text = text.length > 0 ? `${text}
17690
+
17691
+ ${result.result.text}` : result.result.text;
17692
+ } else {
17693
+ console.error(`[webchat:inbound] op=stt-failed kind=voice detail=${result.error}`);
17694
+ }
17695
+ }
17696
+ if (stored.length > 0) {
17697
+ const listing = stored.map((s) => `${s.filename} (${s.readableTextPath ?? s.storagePath})`).join(", ");
17698
+ const note = `[The operator uploaded ${stored.length} file(s): ${listing}]`;
17699
+ text = text.length > 0 ? `${text}
17700
+
17701
+ ${note}` : note;
17702
+ }
17703
+ for (const s of stored) {
17704
+ const timeline = await extractWebchatVideo(s);
17705
+ if (timeline) text = `${text}
17706
+
17707
+ ${timeline}`;
17708
+ }
17709
+ console.log(`[webchat:inbound] op=send-parsed kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
17633
17710
  }
17634
- }, WEBCHAT_SEND_TURN_WINDOW_MS);
17635
- if (turnTimer.unref) turnTimer.unref();
17711
+ if (target !== void 0 && await managerActivity(deliverySessionId) === "busy") {
17712
+ console.log(`[webchat:inbound] op=queued-busy sessionId=${deliverySessionId.slice(0, 8)} key=${deliveryKey}`);
17713
+ }
17714
+ const adminUserId = requesterUserId ?? void 0;
17715
+ const inboundStartedAt = Date.now();
17716
+ const replyContext = resolveQuoted(deliverySessionId, quotedUuid, sendId);
17717
+ const inbound = await deps.handleInbound({
17718
+ role: "admin",
17719
+ accountId: deliveryAccountId,
17720
+ key: deliveryKey,
17721
+ text,
17722
+ sessionId: deliverySessionId,
17723
+ adminUserId,
17724
+ ...replyContext ? { replyContext } : {}
17725
+ });
17726
+ const turnSessionId = deliverySessionId;
17727
+ const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
17728
+ console.error(
17729
+ `[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"} acceptMs=${Date.now() - inboundStartedAt} spawn=${inbound.spawn !== null ? "triggered" : "none"}`
17730
+ );
17731
+ const turnTimer = setTimeout(() => {
17732
+ const now = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
17733
+ const grew = now !== null && (baseline === null || now > baseline);
17734
+ if (grew) {
17735
+ console.error(`[webchat:inbound] op=send-turned key=${keyDisplay2} sendId=${sendId} bytes=${now}`);
17736
+ } else {
17737
+ console.error(`[webchat:inbound] op=send-no-turn key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
17738
+ }
17739
+ }, WEBCHAT_SEND_TURN_WINDOW_MS);
17740
+ if (turnTimer.unref) turnTimer.unref();
17741
+ };
17742
+ const deferred = audioFile !== void 0 || stored.some((s) => isVideoMime(s.mimeType));
17743
+ if (deferred) {
17744
+ markTranscribing(deliveryKey);
17745
+ notify("webchat-pointer", deliveryAccountId);
17746
+ const stagedBytes = stored.reduce((n, s) => n + s.sizeBytes, 0);
17747
+ console.log(`[webchat:inbound] op=send-staged kind=${kind} key=${keyDisplay2} bytes=${stagedBytes}`);
17748
+ void completeSend().catch((err) => {
17749
+ const detail = err instanceof Error ? err.message : String(err);
17750
+ console.error(`[webchat:inbound] op=send-continuation-failed key=${keyDisplay2} detail=${detail}`);
17751
+ deps.markDeliveryFailure?.(deliveryKey, `send-${sendId}`);
17752
+ }).finally(() => {
17753
+ clearTranscribing(deliveryKey);
17754
+ notify("webchat-pointer", deliveryAccountId);
17755
+ });
17756
+ return c.json({ ok: true, transcribing: true });
17757
+ }
17758
+ await completeSend();
17636
17759
  return c.json({ ok: true });
17637
17760
  });
17638
17761
  app81.post("/interrupt", requireAdminSession, async (c) => {
@@ -17742,7 +17865,7 @@ ${note}` : note;
17742
17865
  }
17743
17866
  const known = resolvedProjectDir !== null || sessionSidecarExists(target);
17744
17867
  const indicators2 = await fetchComposerIndicators(target);
17745
- return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${target}`) ?? null, ...indicators2, ...readLevers(scopeAccountId ? validateAccountId2(scopeAccountId) : null) });
17868
+ return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${target}`) ?? null, transcribing: isTranscribing(`session:${target}`), ...indicators2, ...readLevers(scopeAccountId ? validateAccountId2(scopeAccountId) : null) });
17746
17869
  }
17747
17870
  const account = scopeAccountId ? validateAccountId2(scopeAccountId) : null;
17748
17871
  const { sessionId, source } = resolveCanonical(accountId, account?.accountDir ?? null, requesterUserId, primaryUserId, scopeAccountId, multiAccount);
@@ -17770,7 +17893,7 @@ ${note}` : note;
17770
17893
  }
17771
17894
  }
17772
17895
  const indicators = await fetchComposerIndicators(sessionId);
17773
- return c.json({ sessionId, projectDir, source, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
17896
+ return c.json({ sessionId, projectDir, source, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, transcribing: isTranscribing(`session:${sessionId}`), ...indicators, ...readLevers(account) });
17774
17897
  });
17775
17898
  app81.post("/permission-verdict", requireAdminSession, async (c) => {
17776
17899
  const body = await c.req.json().catch(() => null);
@@ -18997,7 +19120,7 @@ function routeTelegramUpdate(input) {
18997
19120
  // app/lib/telegram/inbound/media.ts
18998
19121
  var import_dist5 = __toESM(require_dist4(), 1);
18999
19122
  import { join as join37 } from "path";
19000
- var TAG26 = "[telegram-inbound]";
19123
+ var TAG27 = "[telegram-inbound]";
19001
19124
  var TELEGRAM_MEDIA_DIR = "/tmp/maxy-media";
19002
19125
  var DOWNLOAD_TIMEOUT_MS = 45e3;
19003
19126
  async function downloadTelegramMedia(input) {
@@ -19046,7 +19169,7 @@ async function downloadTelegramMedia(input) {
19046
19169
  result = { ...base, failure: err instanceof Error ? err.message : String(err) };
19047
19170
  }
19048
19171
  console.error(
19049
- `${TAG26} op=media-download botId=${input.botId} type=${item.type} ok=${result.path ? "yes" : "no"} bytes=${bytes} path=${result.path ?? "-"} reason=${result.failure ?? "-"}`
19172
+ `${TAG27} op=media-download botId=${input.botId} type=${item.type} ok=${result.path ? "yes" : "no"} bytes=${bytes} path=${result.path ?? "-"} reason=${result.failure ?? "-"}`
19050
19173
  );
19051
19174
  out.push(result);
19052
19175
  }
@@ -19056,7 +19179,7 @@ async function downloadTelegramMedia(input) {
19056
19179
  // app/lib/telegram/inbound/servable.ts
19057
19180
  import { readFile as readFile6 } from "fs/promises";
19058
19181
  import { basename as basename12 } from "path";
19059
- var TAG27 = "[telegram-inbound]";
19182
+ var TAG28 = "[telegram-inbound]";
19060
19183
  async function storeTelegramServable(input) {
19061
19184
  const out = [];
19062
19185
  for (const [index, item] of input.media.entries()) {
@@ -19070,12 +19193,12 @@ async function storeTelegramServable(input) {
19070
19193
  }
19071
19194
  out.push(attachmentId);
19072
19195
  console.error(
19073
- `${TAG27} op=servable-store ok=true type=${item.type} id=${attachmentId}`
19196
+ `${TAG28} op=servable-store ok=true type=${item.type} id=${attachmentId}`
19074
19197
  );
19075
19198
  } catch (err) {
19076
19199
  const reason = err instanceof Error ? err.message : String(err);
19077
19200
  console.error(
19078
- `${TAG27} op=servable-store ok=false type=${item.type} id=${attachmentId} reason=${reason.slice(0, 100)}`
19201
+ `${TAG28} op=servable-store ok=false type=${item.type} id=${attachmentId} reason=${reason.slice(0, 100)}`
19079
19202
  );
19080
19203
  }
19081
19204
  }
@@ -19083,7 +19206,7 @@ async function storeTelegramServable(input) {
19083
19206
  }
19084
19207
 
19085
19208
  // app/lib/telegram/inbound/transcribe.ts
19086
- var TAG28 = "[telegram-inbound]";
19209
+ var TAG29 = "[telegram-inbound]";
19087
19210
  async function transcribeTelegramAudio(input) {
19088
19211
  const doTranscribe = input.transcribeImpl ?? transcribe;
19089
19212
  const out = [];
@@ -19095,7 +19218,7 @@ async function transcribeTelegramAudio(input) {
19095
19218
  }
19096
19219
  if (!m.path) {
19097
19220
  console.error(
19098
- `${TAG28} op=transcribe botId=${input.botId} ok=no chars=0 ms=0 reason=${m.failure ?? "no local file"}`
19221
+ `${TAG29} op=transcribe botId=${input.botId} ok=no chars=0 ms=0 reason=${m.failure ?? "no local file"}`
19099
19222
  );
19100
19223
  out.push(m);
19101
19224
  continue;
@@ -19112,7 +19235,7 @@ async function transcribeTelegramAudio(input) {
19112
19235
  reason = err instanceof Error ? err.message : String(err);
19113
19236
  }
19114
19237
  console.error(
19115
- `${TAG28} op=transcribe botId=${input.botId} ok=${heard ? "yes" : "no"} chars=${heard?.length ?? 0} ms=${Date.now() - startedMs} reason=${reason}`
19238
+ `${TAG29} op=transcribe botId=${input.botId} ok=${heard ? "yes" : "no"} chars=${heard?.length ?? 0} ms=${Date.now() - startedMs} reason=${reason}`
19116
19239
  );
19117
19240
  if (heard) {
19118
19241
  transcripts.push(heard);
@@ -19129,6 +19252,33 @@ async function transcribeTelegramAudio(input) {
19129
19252
  ${body}` : body, media: out };
19130
19253
  }
19131
19254
 
19255
+ // app/lib/telegram/inbound/video.ts
19256
+ var TAG30 = "[telegram-inbound]";
19257
+ async function extractTelegramVideo(input) {
19258
+ const doExtract = input.extractImpl ?? extractVideo;
19259
+ const out = [];
19260
+ for (const m of input.media) {
19261
+ if (m.type !== "video" || !m.path) {
19262
+ out.push(m);
19263
+ continue;
19264
+ }
19265
+ const startedMs = Date.now();
19266
+ let timeline;
19267
+ let reason = "-";
19268
+ try {
19269
+ timeline = await doExtract(m.path, m.mimetype ?? "");
19270
+ if (!timeline) reason = "no timeline returned";
19271
+ } catch (err) {
19272
+ reason = err instanceof Error ? err.message : String(err);
19273
+ }
19274
+ console.error(
19275
+ `${TAG30} op=video-extract botId=${input.botId} ok=${timeline ? "yes" : "no"} chars=${timeline?.length ?? 0} ms=${Date.now() - startedMs} reason=${reason}`
19276
+ );
19277
+ out.push(timeline ? { ...m, timeline } : m);
19278
+ }
19279
+ return { media: out };
19280
+ }
19281
+
19132
19282
  // app/lib/telegram/gateway/telegram-inbound-census.ts
19133
19283
  var ANSWER_THRESHOLD_MS = 3e4;
19134
19284
  var GAP_NAME_LIMIT2 = 10;
@@ -19571,7 +19721,7 @@ async function visitStatusSet(p) {
19571
19721
  }
19572
19722
 
19573
19723
  // app/lib/telegram/dispatch/press.ts
19574
- var TAG29 = "[dispatch-tg]";
19724
+ var TAG31 = "[dispatch-tg]";
19575
19725
  function logValue(v) {
19576
19726
  return v.replace(/[\r\n]+/g, " ");
19577
19727
  }
@@ -19632,12 +19782,12 @@ async function handleDispatchPress(p) {
19632
19782
  status: ${status}`;
19633
19783
  const done = await p.edit(p.token, p.chatId, p.messageId, text, toBotApiKeyboard(kb.rows));
19634
19784
  p.emit(
19635
- `${TAG29} op=card-redrawn visitId=${logVisitId} messageId=${p.messageId} buttons=${kb.rows.flat().length} drawnFor=${logValue(status)}` + (done.ok ? "" : ` editError="${logValue(done.error ?? "unknown")}"`)
19785
+ `${TAG31} op=card-redrawn visitId=${logVisitId} messageId=${p.messageId} buttons=${kb.rows.flat().length} drawnFor=${logValue(status)}` + (done.ok ? "" : ` editError="${logValue(done.error ?? "unknown")}"`)
19636
19786
  );
19637
19787
  };
19638
19788
  if (visit.status !== parsed.drawnFor) {
19639
19789
  p.emit(
19640
- `${TAG29} op=callback-stale updateId=${u} visitId=${logVisitId} expected=${logDrawnFor} actual=${logValue(visit.status)}`
19790
+ `${TAG31} op=callback-stale updateId=${u} visitId=${logVisitId} expected=${logDrawnFor} actual=${logValue(visit.status)}`
19641
19791
  );
19642
19792
  await redraw(visit.status);
19643
19793
  return {
@@ -19664,7 +19814,7 @@ status: ${status}`;
19664
19814
  return { kind: "refused", reason: out.reason, answer: out.message };
19665
19815
  }
19666
19816
  p.emit(
19667
- `${TAG29} op=callback-applied updateId=${u} visitId=${logVisitId} from=${logValue(out.value.from)} to=${logValue(out.value.to)} tool=dispatch-visit-status-set ms=${Date.now() - startedAt}`
19817
+ `${TAG31} op=callback-applied updateId=${u} visitId=${logVisitId} from=${logValue(out.value.from)} to=${logValue(out.value.to)} tool=dispatch-visit-status-set ms=${Date.now() - startedAt}`
19668
19818
  );
19669
19819
  await redraw(out.value.to);
19670
19820
  return {
@@ -19691,7 +19841,7 @@ async function bindChatToVisit(p) {
19691
19841
  }
19692
19842
 
19693
19843
  // app/lib/telegram/dispatch/location.ts
19694
- var TAG30 = "[dispatch-tg]";
19844
+ var TAG32 = "[dispatch-tg]";
19695
19845
  async function handleDispatchLocation(p) {
19696
19846
  const bound = await bindChatToVisit({
19697
19847
  session: p.session,
@@ -19708,7 +19858,7 @@ async function handleDispatchLocation(p) {
19708
19858
  at: { latitude: p.latitude, longitude: p.longitude }
19709
19859
  });
19710
19860
  p.emit(
19711
- `${TAG30} op=location-update visitId=${bound.visit.visitId} workerId=${bound.worker.workerId} distanceM=${v.distanceM ?? "none"} inside=${v.inside} siteHasCoords=${v.siteHasCoords} radiusM=${v.radiusM ?? "none"}`
19861
+ `${TAG32} op=location-update visitId=${bound.visit.visitId} workerId=${bound.worker.workerId} distanceM=${v.distanceM ?? "none"} inside=${v.inside} siteHasCoords=${v.siteHasCoords} radiusM=${v.radiusM ?? "none"}`
19712
19862
  );
19713
19863
  if (!v.siteHasCoords) return { kind: "no-coords" };
19714
19864
  if (v.radiusM === null) return { kind: "no-radius" };
@@ -19726,12 +19876,12 @@ async function handleDispatchLocation(p) {
19726
19876
  });
19727
19877
  if (!rec.ok) {
19728
19878
  p.emit(
19729
- `${TAG30} op=geofence-refused visitId=${bound.visit.visitId} workerId=${bound.worker.workerId} distanceM=${v.distanceM} reason=${rec.reason}`
19879
+ `${TAG32} op=geofence-refused visitId=${bound.visit.visitId} workerId=${bound.worker.workerId} distanceM=${v.distanceM} reason=${rec.reason}`
19730
19880
  );
19731
19881
  return { kind: "not-recorded" };
19732
19882
  }
19733
19883
  p.emit(
19734
- `${TAG30} op=geofence-enter visitId=${bound.visit.visitId} observedAt=${observedAt} distanceM=${v.distanceM} pressedAt=${bound.visit.arrivedPressedAt ?? "none"}`
19884
+ `${TAG32} op=geofence-enter visitId=${bound.visit.visitId} observedAt=${observedAt} distanceM=${v.distanceM} pressedAt=${bound.visit.arrivedPressedAt ?? "none"}`
19735
19885
  );
19736
19886
  return { kind: "recorded" };
19737
19887
  }
@@ -19763,7 +19913,7 @@ function readTgActivity(accountId) {
19763
19913
  }
19764
19914
 
19765
19915
  // app/lib/telegram/dispatch/media.ts
19766
- var TAG31 = "[dispatch-tg]";
19916
+ var TAG33 = "[dispatch-tg]";
19767
19917
  async function handleDispatchMedia(p) {
19768
19918
  const bound = await bindChatToVisit({
19769
19919
  session: p.session,
@@ -19774,14 +19924,14 @@ async function handleDispatchMedia(p) {
19774
19924
  if (bound.kind !== "bound") {
19775
19925
  const tell = bound.kind === "no-open-visit" ? `You have no open ${p.cfg.vocabulary.visit}, so I have kept this in the chat. Open one and send it again.` : bound.kind === "many-open-visits" ? `You have ${bound.visits.length} open ${p.cfg.vocabulary.visit}s, so I have kept this in the chat rather than guessing. Open the one you mean in the job sheet and send it there.` : null;
19776
19926
  p.emit(
19777
- `${TAG31} op=unbound-inbound chatId=${p.telegramUserId} kind=${p.kind} reason=${bound.kind} told=${tell !== null}`
19927
+ `${TAG33} op=unbound-inbound chatId=${p.telegramUserId} kind=${p.kind} reason=${bound.kind} told=${tell !== null}`
19778
19928
  );
19779
19929
  return { kind: "unattached", reason: bound.kind, tell };
19780
19930
  }
19781
19931
  const visitId = bound.visit.visitId;
19782
19932
  if (p.kind === "voice") {
19783
19933
  p.emit(
19784
- `${TAG31} op=voice-received visitId=${visitId} durationS=${p.durationS ?? "none"} bytes=${p.bytes ?? "none"}`
19934
+ `${TAG33} op=voice-received visitId=${visitId} durationS=${p.durationS ?? "none"} bytes=${p.bytes ?? "none"}`
19785
19935
  );
19786
19936
  noteVoiceReceived(p.accountId, visitId);
19787
19937
  if (p.transcript === null || p.transcript.length === 0) {
@@ -19801,7 +19951,7 @@ async function handleDispatchMedia(p) {
19801
19951
  note: p.transcript
19802
19952
  });
19803
19953
  p.emit(
19804
- `${TAG31} op=voice-transcribed visitId=${visitId} chars=${p.transcript.length} ms=${Date.now() - startedAt}`
19954
+ `${TAG33} op=voice-transcribed visitId=${visitId} chars=${p.transcript.length} ms=${Date.now() - startedAt}`
19805
19955
  );
19806
19956
  noteVoiceTranscribed(p.accountId, visitId);
19807
19957
  return { kind: "note", visitId };
@@ -19821,14 +19971,14 @@ async function handleDispatchMedia(p) {
19821
19971
  visitId,
19822
19972
  mediaRef: p.path
19823
19973
  });
19824
- p.emit(`${TAG31} op=media-attached visitId=${visitId} kind=${p.kind} path=${p.path}`);
19974
+ p.emit(`${TAG33} op=media-attached visitId=${visitId} kind=${p.kind} path=${p.path}`);
19825
19975
  return { kind: "media", visitId };
19826
19976
  }
19827
19977
 
19828
19978
  // app/lib/telegram/live-location.ts
19829
19979
  import { existsSync as existsSync26, mkdirSync as mkdirSync6, readFileSync as readFileSync30, readdirSync as readdirSync20, statSync as statSync19, writeFileSync as writeFileSync13 } from "fs";
19830
19980
  import { join as join38 } from "path";
19831
- var TAG32 = "[telegram-inbound]";
19981
+ var TAG34 = "[telegram-inbound]";
19832
19982
  var LIVE_LOCATION_FILE = "telegram-live-location.json";
19833
19983
  var LIVE_LOCATION_CENSUS_TAG = "[telegram-live-location-census]";
19834
19984
  function liveLocationKey(botId, senderId) {
@@ -19864,12 +20014,12 @@ function writeLiveLocation(input) {
19864
20014
  const livePeriodS = input.livePeriodS ?? stored[key2]?.livePeriodS ?? null;
19865
20015
  if (livePeriodS === null) {
19866
20016
  emit(
19867
- `${TAG32} op=live-location op=skipped-write senderId=${senderId} botId=${botId} reason=no-live-period`
20017
+ `${TAG34} op=live-location op=skipped-write senderId=${senderId} botId=${botId} reason=no-live-period`
19868
20018
  );
19869
20019
  return { written: false, reason: "no-live-period" };
19870
20020
  }
19871
20021
  if (input.atS === null) {
19872
- emit(`${TAG32} op=live-location op=skipped-write senderId=${senderId} botId=${botId} reason=no-date`);
20022
+ emit(`${TAG34} op=live-location op=skipped-write senderId=${senderId} botId=${botId} reason=no-date`);
19873
20023
  return { written: false, reason: "no-date" };
19874
20024
  }
19875
20025
  const next = {
@@ -19887,7 +20037,7 @@ function writeLiveLocation(input) {
19887
20037
  mkdirSync6(accountDir, { recursive: true });
19888
20038
  writeFileSync13(path, JSON.stringify(kept, null, 2) + "\n", "utf-8");
19889
20039
  emit(
19890
- `${TAG32} op=live-location op=updated senderId=${senderId} botId=${botId} ageMs=${now - next.at} livePeriodS=${livePeriodS}`
20040
+ `${TAG34} op=live-location op=updated senderId=${senderId} botId=${botId} ageMs=${now - next.at} livePeriodS=${livePeriodS}`
19891
20041
  );
19892
20042
  return { written: true };
19893
20043
  }
@@ -19931,7 +20081,7 @@ function liveLocationCensusLine(accountsRoot, now) {
19931
20081
  // app/lib/telegram/business-connection.ts
19932
20082
  import { existsSync as existsSync27, mkdirSync as mkdirSync7, readFileSync as readFileSync31, writeFileSync as writeFileSync14 } from "fs";
19933
20083
  import { join as join39 } from "path";
19934
- var TAG33 = "[telegram-inbound]";
20084
+ var TAG35 = "[telegram-inbound]";
19935
20085
  var BUSINESS_CONNECTION_FILE = "telegram-business-connection.json";
19936
20086
  function truncateConnectionId(id) {
19937
20087
  return `${id.slice(0, 6)}\u2026`;
@@ -19964,7 +20114,7 @@ function writeBusinessConnection(input) {
19964
20114
  const canReply = rights?.can_reply === true;
19965
20115
  const say = (stored, reason) => {
19966
20116
  emit(
19967
- `${TAG33} op=business-connection botId=${botId} connectionId=${id === null ? "none" : truncateConnectionId(id)} userId=${userId ?? "none"} isEnabled=${isEnabled} canReply=${canReply} stored=${stored} reason=${reason}`
20117
+ `${TAG35} op=business-connection botId=${botId} connectionId=${id === null ? "none" : truncateConnectionId(id)} userId=${userId ?? "none"} isEnabled=${isEnabled} canReply=${canReply} stored=${stored} reason=${reason}`
19968
20118
  );
19969
20119
  };
19970
20120
  if (id === null) {
@@ -20043,7 +20193,7 @@ async function editTelegramMessage(botToken, chatId, messageId, text, keyboard)
20043
20193
  }
20044
20194
 
20045
20195
  // server/routes/telegram.ts
20046
- var TAG34 = "[telegram-inbound]";
20196
+ var TAG36 = "[telegram-inbound]";
20047
20197
  var PROVISION_TAG = "[telegram-provision]";
20048
20198
  function entryActive(entry3, accountDir, botId, noteSpecialist) {
20049
20199
  if (entry3.role === "admin") return true;
@@ -20053,7 +20203,7 @@ function entryActive(entry3, accountDir, botId, noteSpecialist) {
20053
20203
  noteSpecialist?.(rosterValid);
20054
20204
  if (rosterValid) return true;
20055
20205
  console.error(
20056
- `${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=specialist-unknown`
20206
+ `${TAG36} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=specialist-unknown`
20057
20207
  );
20058
20208
  return false;
20059
20209
  }
@@ -20104,13 +20254,13 @@ function accountConfig(accountDir) {
20104
20254
  function raiseChannelTurn(input) {
20105
20255
  if (!input.active) {
20106
20256
  console.error(
20107
- `${TAG34} op=reject reason=agent-inactive botId=${input.botId} agent=${input.agentSlug}`
20257
+ `${TAG36} op=reject reason=agent-inactive botId=${input.botId} agent=${input.agentSlug}`
20108
20258
  );
20109
20259
  return;
20110
20260
  }
20111
20261
  const gateway = getTelegramGateway();
20112
20262
  if (!gateway) {
20113
- console.error(`${TAG34} op=reply-dropped botId=${input.botId} reason=gateway-not-ready`);
20263
+ console.error(`${TAG36} op=reply-dropped botId=${input.botId} reason=gateway-not-ready`);
20114
20264
  return;
20115
20265
  }
20116
20266
  const reply = async (replyText) => {
@@ -20131,8 +20281,8 @@ function raiseChannelTurn(input) {
20131
20281
  origin: "agent",
20132
20282
  createdAt: at
20133
20283
  });
20134
- console.error(`${TAG34} op=reply-sent botId=${input.botId} ok=true`);
20135
- } else console.error(`${TAG34} op=reply-dropped botId=${input.botId} reason=${sent.error}`);
20284
+ console.error(`${TAG36} op=reply-sent botId=${input.botId} ok=true`);
20285
+ } else console.error(`${TAG36} op=reply-dropped botId=${input.botId} reason=${sent.error}`);
20136
20286
  };
20137
20287
  void gateway.handleInbound({
20138
20288
  accountId: input.accountId,
@@ -20157,34 +20307,34 @@ var app11 = new Hono();
20157
20307
  app11.post("/", async (c) => {
20158
20308
  const botId = c.req.query("bot");
20159
20309
  if (!botId) {
20160
- console.error(`${TAG34} op=reject reason=missing-bot-param`);
20310
+ console.error(`${TAG36} op=reject reason=missing-bot-param`);
20161
20311
  return c.json({ ok: false }, 400);
20162
20312
  }
20163
- console.error(`${TAG34} op=received botId=${botId} path=/api/telegram/`);
20313
+ console.error(`${TAG36} op=received botId=${botId} path=/api/telegram/`);
20164
20314
  const resolved = resolveBotEntry(listValidAccounts(), botId);
20165
20315
  if (resolved.kind === "none") {
20166
- console.error(`${TAG34} op=reject reason=unknown-bot botId=${botId}`);
20316
+ console.error(`${TAG36} op=reject reason=unknown-bot botId=${botId}`);
20167
20317
  return c.json({ ok: false }, 401);
20168
20318
  }
20169
20319
  if (resolved.kind === "duplicate") {
20170
- console.error(`${TAG34} op=reject reason=duplicate-bot-id botId=${botId} accounts=${resolved.count}`);
20320
+ console.error(`${TAG36} op=reject reason=duplicate-bot-id botId=${botId} accounts=${resolved.count}`);
20171
20321
  return c.json({ ok: false }, 401);
20172
20322
  }
20173
20323
  const { accountId, accountDir, entry: entry3 } = resolved;
20174
20324
  const agentSlug = entryAgentSlug(entry3);
20175
- console.error(`${TAG34} op=entry botId=${botId} accountId=${accountId} role=${entry3.role} agent=${agentSlug}`);
20325
+ console.error(`${TAG36} op=entry botId=${botId} accountId=${accountId} role=${entry3.role} agent=${agentSlug}`);
20176
20326
  const sp = secretPath(botId);
20177
20327
  if (!existsSync28(sp)) {
20178
- console.error(`${TAG34} op=secret botId=${botId} result=missing-file`);
20328
+ console.error(`${TAG36} op=secret botId=${botId} result=missing-file`);
20179
20329
  return c.json({ ok: false }, 401);
20180
20330
  }
20181
20331
  const expected = readFileSync32(sp, "utf-8").trim();
20182
20332
  const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
20183
20333
  if (got !== expected) {
20184
- console.error(`${TAG34} op=secret botId=${botId} result=mismatch`);
20334
+ console.error(`${TAG36} op=secret botId=${botId} result=mismatch`);
20185
20335
  return c.json({ ok: false }, 401);
20186
20336
  }
20187
- console.error(`${TAG34} op=secret botId=${botId} result=ok`);
20337
+ console.error(`${TAG36} op=secret botId=${botId} result=ok`);
20188
20338
  let update;
20189
20339
  try {
20190
20340
  update = await c.req.json();
@@ -20193,7 +20343,7 @@ app11.post("/", async (c) => {
20193
20343
  }
20194
20344
  const shape = describeTelegramUpdate(update);
20195
20345
  console.error(
20196
- `${TAG34} op=inbound-kind botId=${botId} update=${shape.envelope} content=${shape.content} chatType=${shape.chatType} isEdit=${shape.isEdit ? "yes" : "no"}`
20346
+ `${TAG36} op=inbound-kind botId=${botId} update=${shape.envelope} content=${shape.content} chatType=${shape.chatType} isEdit=${shape.isEdit ? "yes" : "no"}`
20197
20347
  );
20198
20348
  if (update.business_connection) {
20199
20349
  writeBusinessConnection({
@@ -20207,13 +20357,13 @@ app11.post("/", async (c) => {
20207
20357
  if (shape.chatType === "group" || shape.chatType === "supergroup") {
20208
20358
  const allowlisted = entry3.role === "public" && (entry3.groupPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry3.allowGroups ?? []).includes(shape.chatId);
20209
20359
  console.error(
20210
- `${TAG34} op=group-inbound botId=${botId} chatType=${shape.chatType} chatId=${shape.chatId ?? "none"} senderId=${shape.senderId ?? "none"} threadId=${shape.threadId ?? "none"} allowlisted=${allowlisted ? "yes" : "no"}`
20360
+ `${TAG36} op=group-inbound botId=${botId} chatType=${shape.chatType} chatId=${shape.chatId ?? "none"} senderId=${shape.senderId ?? "none"} threadId=${shape.threadId ?? "none"} allowlisted=${allowlisted ? "yes" : "no"}`
20211
20361
  );
20212
20362
  }
20213
20363
  if (shape.chatType === "channel") {
20214
20364
  const allowlisted = entry3.role === "public" && (entry3.channelPolicy ?? "disabled") === "allowlist" && shape.chatId !== null && (entry3.allowChannels ?? []).includes(shape.chatId);
20215
20365
  console.error(
20216
- `${TAG34} op=channel-post botId=${botId} chatId=${shape.chatId ?? "none"} messageId=${shape.messageId ?? "none"} senderChat=${shape.senderChat ?? "none"} isEdit=${shape.isEdit ? "yes" : "no"} allowlisted=${allowlisted ? "yes" : "no"}`
20366
+ `${TAG36} op=channel-post botId=${botId} chatId=${shape.chatId ?? "none"} messageId=${shape.messageId ?? "none"} senderChat=${shape.senderChat ?? "none"} isEdit=${shape.isEdit ? "yes" : "no"} allowlisted=${allowlisted ? "yes" : "no"}`
20217
20367
  );
20218
20368
  }
20219
20369
  const hostBots = update.managed_bot ? listBotEntries(accountConfig(accountDir).telegram) : [];
@@ -20234,56 +20384,56 @@ app11.post("/", async (c) => {
20234
20384
  decision.kind === "managed-bot" && decision.authorised && decision.event === "created";
20235
20385
  noteInboundKind(shape.primaryKind, raisesTurn, shape.envelope);
20236
20386
  if (decision.kind === "ignore") {
20237
- console.error(`${TAG34} op=ignore botId=${botId} reason=${decision.reason}`);
20387
+ console.error(`${TAG36} op=ignore botId=${botId} reason=${decision.reason}`);
20238
20388
  return c.json({ ok: true }, 200);
20239
20389
  }
20240
20390
  if (decision.kind === "denied") {
20241
20391
  if (decision.reason === "admin-entry-no-groups" || decision.reason === "not-in-allowGroups" || decision.reason === "group-policy-disabled") {
20242
20392
  console.error(
20243
- `${TAG34} op=group-refused botId=${botId} chatId=${shape.chatId ?? "none"} reason=${decision.reason}`
20393
+ `${TAG36} op=group-refused botId=${botId} chatId=${shape.chatId ?? "none"} reason=${decision.reason}`
20244
20394
  );
20245
20395
  }
20246
20396
  if (decision.reason === "admin-entry-no-channels" || decision.reason === "specialist-entry-no-channels" || decision.reason === "unbound-entry-no-channels" || decision.reason === "not-in-allowChannels" || decision.reason === "channel-policy-disabled") {
20247
20397
  console.error(
20248
- `${TAG34} op=channel-refused botId=${botId} chatId=${shape.chatId ?? "none"} reason=${decision.reason}`
20398
+ `${TAG36} op=channel-refused botId=${botId} chatId=${shape.chatId ?? "none"} reason=${decision.reason}`
20249
20399
  );
20250
20400
  }
20251
- console.error(`${TAG34} op=access botId=${botId} senderId=- allowed=false reason=${decision.reason}`);
20401
+ console.error(`${TAG36} op=access botId=${botId} senderId=- allowed=false reason=${decision.reason}`);
20252
20402
  if (entry3.role === "specialist") {
20253
20403
  console.error(
20254
- `${TAG34} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=${decision.reason}`
20404
+ `${TAG36} op=specialist-refused botId=${botId} specialist=${logValue2(entry3.specialist)} reason=${decision.reason}`
20255
20405
  );
20256
20406
  }
20257
20407
  return c.json({ ok: true }, 200);
20258
20408
  }
20259
20409
  if (!isBindableEntry(entry3)) {
20260
- console.error(`${TAG34} op=ignore botId=${botId} reason=bot-unbound`);
20410
+ console.error(`${TAG36} op=ignore botId=${botId} reason=bot-unbound`);
20261
20411
  return c.json({ ok: true }, 200);
20262
20412
  }
20263
20413
  if (decision.kind === "chat-member") {
20264
20414
  console.error(
20265
- `${TAG34} op=chat-member-group botId=${botId} chatId=${decision.chatId} userId=${decision.userId || "none"} status=${logValue2(decision.status)}`
20415
+ `${TAG36} op=chat-member-group botId=${botId} chatId=${decision.chatId} userId=${decision.userId || "none"} status=${logValue2(decision.status)}`
20266
20416
  );
20267
20417
  return c.json({ ok: true }, 200);
20268
20418
  }
20269
20419
  if (decision.kind === "recorded") {
20270
20420
  console.error(
20271
- `${TAG34} op=recorded botId=${botId} envelope=${decision.envelope} chatId=${decision.chatId ?? "none"} messageId=${decision.messageId ?? "none"}`
20421
+ `${TAG36} op=recorded botId=${botId} envelope=${decision.envelope} chatId=${decision.chatId ?? "none"} messageId=${decision.messageId ?? "none"}`
20272
20422
  );
20273
20423
  return c.json({ ok: true }, 200);
20274
20424
  }
20275
20425
  if (decision.kind === "comment-root") {
20276
20426
  console.error(
20277
- `${TAG34} op=channel-comment-root botId=${botId} groupChatId=${decision.groupChatId} rootMessageId=${decision.rootMessageId} channelChatId=${decision.channelChatId}`
20427
+ `${TAG36} op=channel-comment-root botId=${botId} groupChatId=${decision.groupChatId} rootMessageId=${decision.rootMessageId} channelChatId=${decision.channelChatId}`
20278
20428
  );
20279
20429
  return c.json({ ok: true }, 200);
20280
20430
  }
20281
20431
  if (decision.kind === "callback") {
20282
20432
  console.error(
20283
- `${TAG34} op=callback-received botId=${botId} callbackId=${decision.callbackId} chatId=${decision.chatId} messageId=${decision.messageId ?? "none"} data=${decision.data === null ? "none" : logValue2(decision.data)}`
20433
+ `${TAG36} op=callback-received botId=${botId} callbackId=${decision.callbackId} chatId=${decision.chatId} messageId=${decision.messageId ?? "none"} data=${decision.data === null ? "none" : logValue2(decision.data)}`
20284
20434
  );
20285
20435
  console.error(
20286
- `${TAG34} op=callback-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20436
+ `${TAG36} op=callback-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20287
20437
  );
20288
20438
  const cbSubject = telegramConversationSubject(decision.chatType, decision.chatId, decision.senderId);
20289
20439
  if (decision.allowed) {
@@ -20296,7 +20446,7 @@ app11.post("/", async (c) => {
20296
20446
  cbBody = label;
20297
20447
  } else {
20298
20448
  console.error(
20299
- `${TAG34} op=button-label-miss botId=${botId} chatId=${decision.chatId} data=${logValue2(decision.data)}`
20449
+ `${TAG36} op=button-label-miss botId=${botId} chatId=${decision.chatId} data=${logValue2(decision.data)}`
20300
20450
  );
20301
20451
  }
20302
20452
  }
@@ -20357,11 +20507,11 @@ app11.post("/", async (c) => {
20357
20507
  const answered4 = await answerTelegramCallback(entry3.token, decision.callbackId, answerText);
20358
20508
  const outcome = !answered4.ok ? "error" : decision.allowed ? "stored" : "refused";
20359
20509
  console.error(
20360
- `${TAG34} op=callback-answered botId=${botId} callbackId=${decision.callbackId} ms=${Date.now() - answerStartedAt} outcome=${outcome}${answered4.error ? ` error=${logValue2(answered4.error)}` : ""}`
20510
+ `${TAG36} op=callback-answered botId=${botId} callbackId=${decision.callbackId} ms=${Date.now() - answerStartedAt} outcome=${outcome}${answered4.error ? ` error=${logValue2(answered4.error)}` : ""}`
20361
20511
  );
20362
20512
  if (decision.allowed && parseDispatchCallback(decision.data) === null) {
20363
20513
  const cbActive = entryActive(entry3, accountDir, botId);
20364
- console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${cbActive}`);
20514
+ console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${cbActive}`);
20365
20515
  raiseChannelTurn({
20366
20516
  accountId,
20367
20517
  accountDir,
@@ -20388,10 +20538,10 @@ app11.post("/", async (c) => {
20388
20538
  if (decision.kind === "poll") {
20389
20539
  const options = decision.optionIds.length > 0 ? decision.optionIds.join(",") : "retracted";
20390
20540
  console.error(
20391
- `${TAG34} op=poll-received botId=${botId} updateId=${decision.updateId ?? "none"} senderId=${decision.senderId} pollId=${logValue2(decision.pollId)} options=${options}`
20541
+ `${TAG36} op=poll-received botId=${botId} updateId=${decision.updateId ?? "none"} senderId=${decision.senderId} pollId=${logValue2(decision.pollId)} options=${options}`
20392
20542
  );
20393
20543
  console.error(
20394
- `${TAG34} op=poll-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20544
+ `${TAG36} op=poll-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20395
20545
  );
20396
20546
  if (!decision.allowed) return c.json({ ok: true }, 200);
20397
20547
  const pollKey = telegramChannelKey(botId, decision.senderId);
@@ -20414,7 +20564,7 @@ app11.post("/", async (c) => {
20414
20564
  createdAt: pollAt
20415
20565
  });
20416
20566
  const pollActive = entryActive(entry3, accountDir, botId);
20417
- console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${pollActive}`);
20567
+ console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${pollActive}`);
20418
20568
  raiseChannelTurn({
20419
20569
  accountId,
20420
20570
  accountDir,
@@ -20440,10 +20590,10 @@ app11.post("/", async (c) => {
20440
20590
  const quotedBody = findInboundBody(accountId, rKey, decision.messageId);
20441
20591
  const shown = decision.newReaction.length > 0 ? decision.newReaction.join(",") : "none";
20442
20592
  console.error(
20443
- `${TAG34} op=reaction-received botId=${botId} chatId=${decision.chatId} messageId=${decision.messageId} senderId=${decision.senderId} old=${decision.oldReaction.join(",") || "none"} new=${shown} targetHeld=${quotedBody === null ? "no" : "yes"}`
20593
+ `${TAG36} op=reaction-received botId=${botId} chatId=${decision.chatId} messageId=${decision.messageId} senderId=${decision.senderId} old=${decision.oldReaction.join(",") || "none"} new=${shown} targetHeld=${quotedBody === null ? "no" : "yes"}`
20444
20594
  );
20445
20595
  console.error(
20446
- `${TAG34} op=reaction-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20596
+ `${TAG36} op=reaction-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20447
20597
  );
20448
20598
  if (!decision.allowed) return c.json({ ok: true }, 200);
20449
20599
  const rScope = entry3.role === "admin" ? "admin" : "public";
@@ -20466,7 +20616,7 @@ app11.post("/", async (c) => {
20466
20616
  createdAt: rAt
20467
20617
  });
20468
20618
  const rActive = entryActive(entry3, accountDir, botId);
20469
- console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${rActive}`);
20619
+ console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${rActive}`);
20470
20620
  raiseChannelTurn({
20471
20621
  accountId,
20472
20622
  accountDir,
@@ -20490,25 +20640,25 @@ app11.post("/", async (c) => {
20490
20640
  if (decision.kind === "checkout") {
20491
20641
  if (decision.query === "pre-checkout") {
20492
20642
  console.error(
20493
- `${TAG34} op=precheckout-received botId=${botId} queryId=${decision.queryId} payload=${logValue2(decision.payload)} amount=${decision.amount ?? "none"} currency=${decision.currency ?? "none"}`
20643
+ `${TAG36} op=precheckout-received botId=${botId} queryId=${decision.queryId} payload=${logValue2(decision.payload)} amount=${decision.amount ?? "none"} currency=${decision.currency ?? "none"}`
20494
20644
  );
20495
20645
  noteCheckoutArrived(botId, decision.queryId, Date.now());
20496
20646
  } else {
20497
20647
  console.error(
20498
- `${TAG34} op=shipping-received botId=${botId} queryId=${decision.queryId} payload=${logValue2(decision.payload)}`
20648
+ `${TAG36} op=shipping-received botId=${botId} queryId=${decision.queryId} payload=${logValue2(decision.payload)}`
20499
20649
  );
20500
20650
  }
20501
20651
  console.error(
20502
- `${TAG34} op=checkout-ignored botId=${botId} senderId=${decision.senderId} queryId=${decision.queryId} query=${decision.query} allowed=${decision.allowed} reason=payments-removed`
20652
+ `${TAG36} op=checkout-ignored botId=${botId} senderId=${decision.senderId} queryId=${decision.queryId} query=${decision.query} allowed=${decision.allowed} reason=payments-removed`
20503
20653
  );
20504
20654
  return c.json({ ok: true }, 200);
20505
20655
  }
20506
20656
  if (decision.kind === "subscription") {
20507
20657
  console.error(
20508
- `${TAG34} op=subscription botId=${botId} userId=${decision.senderId} payload=${logValue2(decision.payload)} state=${decision.state}`
20658
+ `${TAG36} op=subscription botId=${botId} userId=${decision.senderId} payload=${logValue2(decision.payload)} state=${decision.state}`
20509
20659
  );
20510
20660
  console.error(
20511
- `${TAG34} op=subscription-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20661
+ `${TAG36} op=subscription-authorised botId=${botId} senderId=${decision.senderId} allowed=${decision.allowed} reason=${decision.reason}`
20512
20662
  );
20513
20663
  if (!decision.allowed) return c.json({ ok: true }, 200);
20514
20664
  const sKey = telegramChannelKey(botId, decision.senderId);
@@ -20531,7 +20681,7 @@ app11.post("/", async (c) => {
20531
20681
  createdAt: sAt
20532
20682
  });
20533
20683
  const sActive = entryActive(entry3, accountDir, botId);
20534
- console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${sActive}`);
20684
+ console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${sActive}`);
20535
20685
  raiseChannelTurn({
20536
20686
  accountId,
20537
20687
  accountDir,
@@ -20555,7 +20705,7 @@ app11.post("/", async (c) => {
20555
20705
  if (!decision.isClosed) return c.json({ ok: true }, 200);
20556
20706
  const where = findPollConversation(accountId, decision.pollId);
20557
20707
  console.error(
20558
- `${TAG34} op=poll-closed botId=${botId} pollId=${logValue2(decision.pollId)} options=${decision.options.length} totalVotes=${decision.totalVotes} targetHeld=${where === null ? "no" : "yes"}`
20708
+ `${TAG36} op=poll-closed botId=${botId} pollId=${logValue2(decision.pollId)} options=${decision.options.length} totalVotes=${decision.totalVotes} targetHeld=${where === null ? "no" : "yes"}`
20559
20709
  );
20560
20710
  if (where === null) return c.json({ ok: true }, 200);
20561
20711
  const plScope = entry3.role === "admin" ? "admin" : "public";
@@ -20578,7 +20728,7 @@ app11.post("/", async (c) => {
20578
20728
  createdAt: plAt
20579
20729
  });
20580
20730
  const plActive = entryActive(entry3, accountDir, botId);
20581
- console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${plActive}`);
20731
+ console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${plActive}`);
20582
20732
  raiseChannelTurn({
20583
20733
  accountId,
20584
20734
  accountDir,
@@ -20599,7 +20749,7 @@ app11.post("/", async (c) => {
20599
20749
  }
20600
20750
  if (decision.kind === "member") {
20601
20751
  console.error(
20602
- `${TAG34} op=chat-member botId=${botId} chatId=${decision.chatId} status=${decision.status}`
20752
+ `${TAG36} op=chat-member botId=${botId} chatId=${decision.chatId} status=${decision.status}`
20603
20753
  );
20604
20754
  return c.json({ ok: true }, 200);
20605
20755
  }
@@ -20607,13 +20757,13 @@ app11.post("/", async (c) => {
20607
20757
  const { newBotId } = decision;
20608
20758
  if (!decision.authorised) {
20609
20759
  console.error(
20610
- `${TAG34} op=managed-bot botId=${botId} event=${decision.event} newBotId=${newBotId} result=refused reason=public-entry-no-provision`
20760
+ `${TAG36} op=managed-bot botId=${botId} event=${decision.event} newBotId=${newBotId} result=refused reason=public-entry-no-provision`
20611
20761
  );
20612
20762
  return c.json({ ok: true }, 200);
20613
20763
  }
20614
20764
  const { event } = decision;
20615
20765
  console.error(
20616
- `${TAG34} op=managed-bot botId=${botId} event=${event} newBotId=${newBotId} creator=${decision.creatorId ?? "none"}`
20766
+ `${TAG36} op=managed-bot botId=${botId} event=${event} newBotId=${newBotId} creator=${decision.creatorId ?? "none"}`
20617
20767
  );
20618
20768
  const fetched = await getManagedBotToken(entry3.token, Number(newBotId));
20619
20769
  console.error(
@@ -20669,11 +20819,11 @@ app11.post("/", async (c) => {
20669
20819
  const matched = bizStored !== null && bizStored.id === decision.businessConnectionId;
20670
20820
  const bizNowS = Math.floor(Date.now() / 1e3);
20671
20821
  console.error(
20672
- `${TAG34} op=business-message botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} chatId=${decision.chatId} senderId=${decision.senderId} messageId=${decision.messageId ?? "none"} kind=${shape.primaryKind} ageS=${decision.date === null ? "none" : bizNowS - decision.date} matched=${matched ? "yes" : "no"}`
20822
+ `${TAG36} op=business-message botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} chatId=${decision.chatId} senderId=${decision.senderId} messageId=${decision.messageId ?? "none"} kind=${shape.primaryKind} ageS=${decision.date === null ? "none" : bizNowS - decision.date} matched=${matched ? "yes" : "no"}`
20673
20823
  );
20674
20824
  if (!matched) {
20675
20825
  console.error(
20676
- `${TAG34} op=business-refused botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} reason=${bizStored === null ? "no-record" : "mismatch"}`
20826
+ `${TAG36} op=business-refused botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} reason=${bizStored === null ? "no-record" : "mismatch"}`
20677
20827
  );
20678
20828
  return c.json({ ok: true }, 200);
20679
20829
  }
@@ -20735,7 +20885,7 @@ app11.post("/", async (c) => {
20735
20885
  }
20736
20886
  const bizGateway = getTelegramGateway();
20737
20887
  if (!bizGateway) {
20738
- console.error(`${TAG34} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
20888
+ console.error(`${TAG36} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
20739
20889
  return c.json({ ok: true }, 200);
20740
20890
  }
20741
20891
  const bizConnectionId = bizStored.id;
@@ -20749,7 +20899,7 @@ app11.post("/", async (c) => {
20749
20899
  );
20750
20900
  if (!verdict.allowed) {
20751
20901
  console.error(
20752
- `${TAG34} op=reply-dropped botId=${botId} reason=business-window-${verdict.reason} detail="${logValue2(businessWindowRefusal(decision.chatId, verdict.ageS))}"`
20902
+ `${TAG36} op=reply-dropped botId=${botId} reason=business-window-${verdict.reason} detail="${logValue2(businessWindowRefusal(decision.chatId, verdict.ageS))}"`
20753
20903
  );
20754
20904
  return;
20755
20905
  }
@@ -20776,8 +20926,8 @@ app11.post("/", async (c) => {
20776
20926
  origin: "agent",
20777
20927
  createdAt: outAt
20778
20928
  });
20779
- console.error(`${TAG34} op=reply-sent botId=${botId} ok=true`);
20780
- } else console.error(`${TAG34} op=reply-dropped botId=${botId} reason=${sent.error}`);
20929
+ console.error(`${TAG36} op=reply-sent botId=${botId} ok=true`);
20930
+ } else console.error(`${TAG36} op=reply-dropped botId=${botId} reason=${sent.error}`);
20781
20931
  };
20782
20932
  void bizGateway.handleInbound({
20783
20933
  accountId,
@@ -20808,7 +20958,7 @@ app11.post("/", async (c) => {
20808
20958
  const delStored = readBusinessConnection(accountDir, botId);
20809
20959
  if (delStored === null || delStored.id !== decision.businessConnectionId) {
20810
20960
  console.error(
20811
- `${TAG34} op=business-refused botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} reason=${delStored === null ? "no-record" : "mismatch"}`
20961
+ `${TAG36} op=business-refused botId=${botId} connectionId=${truncateConnectionId(decision.businessConnectionId)} reason=${delStored === null ? "no-record" : "mismatch"}`
20812
20962
  );
20813
20963
  return c.json({ ok: true }, 200);
20814
20964
  }
@@ -20825,12 +20975,12 @@ app11.post("/", async (c) => {
20825
20975
  if (res.created) marked += 1;
20826
20976
  }
20827
20977
  console.error(
20828
- `${TAG34} op=business-deleted botId=${botId} chatId=${decision.chatId} ids=${decision.messageIds.length} marked=${marked}`
20978
+ `${TAG36} op=business-deleted botId=${botId} chatId=${decision.chatId} ids=${decision.messageIds.length} marked=${marked}`
20829
20979
  );
20830
20980
  return c.json({ ok: true }, 200);
20831
20981
  }
20832
20982
  const { senderId, chatId, text } = decision;
20833
- console.error(`${TAG34} op=access botId=${botId} senderId=${senderId} allowed=true reason=${decision.reason}`);
20983
+ console.error(`${TAG36} op=access botId=${botId} senderId=${senderId} allowed=true reason=${decision.reason}`);
20834
20984
  const subject = telegramConversationSubject(decision.chatType, chatId, senderId);
20835
20985
  const channelKey = telegramChannelKey(botId, subject);
20836
20986
  const scope = entry3.role === "public" ? "public" : "admin";
@@ -20917,17 +21067,17 @@ app11.post("/", async (c) => {
20917
21067
  const active = entryActive(entry3, accountDir, botId, (rosterValid) => {
20918
21068
  if (entry3.role !== "specialist") return;
20919
21069
  console.error(
20920
- `${TAG34} op=specialist-inbound botId=${botId} specialist=${logValue2(entry3.specialist)} senderId=${senderId} sessionId=${sessionId} rosterValid=${rosterValid ? "yes" : "no"}`
21070
+ `${TAG36} op=specialist-inbound botId=${botId} specialist=${logValue2(entry3.specialist)} senderId=${senderId} sessionId=${sessionId} rosterValid=${rosterValid ? "yes" : "no"}`
20921
21071
  );
20922
21072
  });
20923
- console.error(`${TAG34} op=agent botId=${botId} slug=${agentSlug} active=${active}`);
21073
+ console.error(`${TAG36} op=agent botId=${botId} slug=${agentSlug} active=${active}`);
20924
21074
  if (!active) {
20925
- console.error(`${TAG34} op=reject reason=agent-inactive botId=${botId} agent=${agentSlug}`);
21075
+ console.error(`${TAG36} op=reject reason=agent-inactive botId=${botId} agent=${agentSlug}`);
20926
21076
  return c.json({ ok: true }, 200);
20927
21077
  }
20928
21078
  const gateway = getTelegramGateway();
20929
21079
  if (!gateway) {
20930
- console.error(`${TAG34} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
21080
+ console.error(`${TAG36} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
20931
21081
  return c.json({ ok: true }, 200);
20932
21082
  }
20933
21083
  const replyThreadId = decision.threadId ?? void 0;
@@ -20949,8 +21099,8 @@ app11.post("/", async (c) => {
20949
21099
  origin: "agent",
20950
21100
  createdAt: at
20951
21101
  });
20952
- console.error(`${TAG34} op=reply-sent botId=${botId} ok=true`);
20953
- } else console.error(`${TAG34} op=reply-dropped botId=${botId} reason=${sent.error}`);
21102
+ console.error(`${TAG36} op=reply-sent botId=${botId} ok=true`);
21103
+ } else console.error(`${TAG36} op=reply-dropped botId=${botId} reason=${sent.error}`);
20954
21104
  };
20955
21105
  const media = await downloadTelegramMedia({ token: entry3.token, botId, items: decision.media });
20956
21106
  if (media.length > 0) {
@@ -21010,7 +21160,7 @@ app11.post("/", async (c) => {
21010
21160
  if (written.written && !decision.isEdit) noteShareStarted();
21011
21161
  } catch (err) {
21012
21162
  console.error(
21013
- `${TAG34} op=live-location op=write-failed botId=${botId} senderId=${senderId} detail="${logValue2(err instanceof Error ? err.message : String(err))}"`
21163
+ `${TAG36} op=live-location op=write-failed botId=${botId} senderId=${senderId} detail="${logValue2(err instanceof Error ? err.message : String(err))}"`
21014
21164
  );
21015
21165
  }
21016
21166
  }
@@ -21022,6 +21172,8 @@ app11.post("/", async (c) => {
21022
21172
  textIsPlaceholder: decision.textIsPlaceholder,
21023
21173
  media
21024
21174
  });
21175
+ const seen = await extractTelegramVideo({ botId, media: heard.media });
21176
+ heard.media = seen.media;
21025
21177
  if (heard.text !== text) {
21026
21178
  const patched = appendUpdate(accountId, channelKey, {
21027
21179
  kind: "update",
@@ -21030,7 +21182,7 @@ app11.post("/", async (c) => {
21030
21182
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
21031
21183
  });
21032
21184
  console.error(
21033
- `${TAG34} op=transcript-patch botId=${botId} target=${inboundMessageId} ok=${patched.created}`
21185
+ `${TAG36} op=transcript-patch botId=${botId} target=${inboundMessageId} ok=${patched.created}`
21034
21186
  );
21035
21187
  }
21036
21188
  {
@@ -21066,7 +21218,7 @@ app11.post("/", async (c) => {
21066
21218
  }
21067
21219
  if (decision.isEdit && decision.location) {
21068
21220
  console.error(
21069
- `${TAG34} op=live-location op=suppressed-turn botId=${botId} senderId=${senderId} reason=live-edit`
21221
+ `${TAG36} op=live-location op=suppressed-turn botId=${botId} senderId=${senderId} reason=live-edit`
21070
21222
  );
21071
21223
  return;
21072
21224
  }
@@ -21117,7 +21269,7 @@ function mountTelegramRoutes(app81, telegramRoutes) {
21117
21269
  // server/routes/quickbooks.ts
21118
21270
  import { join as join41 } from "path";
21119
21271
  import { existsSync as existsSync29, readFileSync as readFileSync33, writeFileSync as writeFileSync15, mkdirSync as mkdirSync8, rmSync as rmSync4, renameSync as renameSync5 } from "fs";
21120
- var TAG35 = "[quickbooks]";
21272
+ var TAG37 = "[quickbooks]";
21121
21273
  var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
21122
21274
  var STATE_RE = /^[A-Za-z0-9_-]+$/;
21123
21275
  function pendingPath(accountDir, state) {
@@ -21130,14 +21282,14 @@ async function completeConsent(args) {
21130
21282
  const { accountDir, code, realmId } = args;
21131
21283
  const state = args.state;
21132
21284
  if (!state || !STATE_RE.test(state) || !existsSync29(pendingPath(accountDir, state))) {
21133
- console.error(`${TAG35} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
21285
+ console.error(`${TAG37} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
21134
21286
  return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
21135
21287
  }
21136
21288
  const claimFile = `${pendingPath(accountDir, state)}.claimed`;
21137
21289
  try {
21138
21290
  renameSync5(pendingPath(accountDir, state), claimFile);
21139
21291
  } catch {
21140
- console.error(`${TAG35} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
21292
+ console.error(`${TAG37} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
21141
21293
  return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
21142
21294
  }
21143
21295
  try {
@@ -21145,14 +21297,14 @@ async function completeConsent(args) {
21145
21297
  try {
21146
21298
  pending = JSON.parse(readFileSync33(claimFile, "utf-8"));
21147
21299
  } catch {
21148
- console.error(`${TAG35} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
21300
+ console.error(`${TAG37} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
21149
21301
  return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
21150
21302
  }
21151
21303
  if (Date.now() > pending.expiresAt) {
21152
- console.error(`${TAG35} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
21304
+ console.error(`${TAG37} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
21153
21305
  return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
21154
21306
  }
21155
- console.error(`${TAG35} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
21307
+ console.error(`${TAG37} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
21156
21308
  if (!code || !realmId) {
21157
21309
  return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
21158
21310
  }
@@ -21176,12 +21328,12 @@ async function completeConsent(args) {
21176
21328
  });
21177
21329
  const text = await res.text();
21178
21330
  if (!res.ok) {
21179
- console.error(`${TAG35} op=token-exchange realmId=${realmId} persisted=false`);
21331
+ console.error(`${TAG37} op=token-exchange realmId=${realmId} persisted=false`);
21180
21332
  return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
21181
21333
  }
21182
21334
  const body = JSON.parse(text);
21183
21335
  if (!body.refresh_token) {
21184
- console.error(`${TAG35} op=token-exchange realmId=${realmId} persisted=false`);
21336
+ console.error(`${TAG37} op=token-exchange realmId=${realmId} persisted=false`);
21185
21337
  return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
21186
21338
  }
21187
21339
  const now = Date.now();
@@ -21194,7 +21346,7 @@ async function completeConsent(args) {
21194
21346
  mkdirSync8(join41(accountDir, "secrets"), { recursive: true });
21195
21347
  writeFileSync15(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
21196
21348
  const persisted = JSON.parse(readFileSync33(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
21197
- console.error(`${TAG35} op=token-exchange realmId=${realmId} persisted=${persisted}`);
21349
+ console.error(`${TAG37} op=token-exchange realmId=${realmId} persisted=${persisted}`);
21198
21350
  return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
21199
21351
  } finally {
21200
21352
  rmSync4(claimFile, { force: true });
@@ -21207,7 +21359,7 @@ var app12 = new Hono();
21207
21359
  app12.get("/callback", async (c) => {
21208
21360
  const account = resolveAccount();
21209
21361
  if (!account) {
21210
- console.error(`${TAG35} op=callback stateValid=false realmId= reason=no-account`);
21362
+ console.error(`${TAG37} op=callback stateValid=false realmId= reason=no-account`);
21211
21363
  return c.html(page("QuickBooks", "This install has no account configured."), 500);
21212
21364
  }
21213
21365
  const result = await completeConsent({
@@ -22172,7 +22324,7 @@ function startDispatchFieldCensus(getSession3, intervalMs = FIFTEEN_MIN_MS) {
22172
22324
  }
22173
22325
 
22174
22326
  // server/routes/field.ts
22175
- var TAG36 = "[dispatch-field]";
22327
+ var TAG38 = "[dispatch-field]";
22176
22328
  var MAX_INITDATA_AGE_S = 3600;
22177
22329
  var ZONE_FALLBACK2 = "UTC";
22178
22330
  var SITE_HISTORY_LIMIT = 20;
@@ -22221,7 +22373,7 @@ function gate(c) {
22221
22373
  Date.now()
22222
22374
  );
22223
22375
  console.log(
22224
- `${TAG36} op=initdata-verify workerId=${auth.ok ? auth.worker.workerId : "none"} ok=${auth.ok} reason=${auth.ok ? "ok" : auth.reason} ageS=${auth.ageS}`
22376
+ `${TAG38} op=initdata-verify workerId=${auth.ok ? auth.worker.workerId : "none"} ok=${auth.ok} reason=${auth.ok ? "ok" : auth.reason} ageS=${auth.ageS}`
22225
22377
  );
22226
22378
  if (auth.ok) {
22227
22379
  noteFieldContact(auth.accountId, auth.worker.workerId, Date.now());
@@ -22243,7 +22395,7 @@ async function loadSheet(auth, visitId) {
22243
22395
  if (!visit) return { ok: false, status: 404, reason: "not-found" };
22244
22396
  if (visit.workerId !== auth.worker.workerId) {
22245
22397
  console.error(
22246
- `${TAG36} op=visit-refused visitId=${visitId} workerId=${auth.worker.workerId} reason=not-assigned`
22398
+ `${TAG38} op=visit-refused visitId=${visitId} workerId=${auth.worker.workerId} reason=not-assigned`
22247
22399
  );
22248
22400
  return { ok: false, status: 403, reason: "not-assigned" };
22249
22401
  }
@@ -22264,7 +22416,7 @@ async function loadSheet(auth, visitId) {
22264
22416
  }
22265
22417
  function readFailed(reason, err, ctx) {
22266
22418
  console.error(
22267
- `${TAG36} op=read-failed ${ctx} error="${err instanceof Error ? err.message : String(err)}" reason=${reason}`
22419
+ `${TAG38} op=read-failed ${ctx} error="${err instanceof Error ? err.message : String(err)}" reason=${reason}`
22268
22420
  );
22269
22421
  }
22270
22422
  var app14 = new Hono();
@@ -22280,7 +22432,7 @@ app14.get("/session", async (c) => {
22280
22432
  return c.json({ reason: "read-failed" }, 503);
22281
22433
  }
22282
22434
  console.log(
22283
- `${TAG36} op=session-open workerId=${auth.worker.workerId} visits=${visits} source=network`
22435
+ `${TAG38} op=session-open workerId=${auth.worker.workerId} visits=${visits} source=network`
22284
22436
  );
22285
22437
  return c.json({
22286
22438
  worker: { workerId: auth.worker.workerId, name: auth.worker.name },
@@ -22316,7 +22468,7 @@ app14.get("/visit/:visitId", async (c) => {
22316
22468
  const loaded = await loadSheet(auth, visitId);
22317
22469
  if (!loaded.ok) return c.json({ reason: loaded.reason }, loaded.status);
22318
22470
  console.log(
22319
- `${TAG36} op=sheet-open visitId=${visitId} workerId=${auth.worker.workerId} historyVisits=${loaded.history.length} source=network`
22471
+ `${TAG38} op=sheet-open visitId=${visitId} workerId=${auth.worker.workerId} historyVisits=${loaded.history.length} source=network`
22320
22472
  );
22321
22473
  return c.json({
22322
22474
  visit: loaded.visit,
@@ -22352,7 +22504,7 @@ app14.post("/visit/:visitId/record", async (c) => {
22352
22504
  );
22353
22505
  if (!out.ok) return c.json({ reason: out.reason, detail: out.message }, 400);
22354
22506
  const kind = body.checklistItem !== void 0 ? "checklist" : body.partId !== void 0 ? "part" : body.signature !== void 0 ? "signature" : body.mediaRef !== void 0 ? "media" : "note";
22355
- console.log(`${TAG36} op=edit-recorded visitId=${visitId} workerId=${auth.worker.workerId} kind=${kind}`);
22507
+ console.log(`${TAG38} op=edit-recorded visitId=${visitId} workerId=${auth.worker.workerId} kind=${kind}`);
22356
22508
  return c.json(out.value);
22357
22509
  });
22358
22510
  app14.post("/visit/:visitId/status", async (c) => {
@@ -22379,7 +22531,7 @@ app14.post("/visit/:visitId/status", async (c) => {
22379
22531
  const prefix = "missing-required-field:";
22380
22532
  if (out.reason.startsWith(prefix)) {
22381
22533
  const missing = out.reason.slice(prefix.length);
22382
- console.error(`${TAG36} op=complete-refused visitId=${visitId} missing=${missing}`);
22534
+ console.error(`${TAG38} op=complete-refused visitId=${visitId} missing=${missing}`);
22383
22535
  return c.json({ reason: "missing-required-field", missing, detail: out.message }, 409);
22384
22536
  }
22385
22537
  return c.json({ reason: out.reason, detail: out.message }, 409);
@@ -22391,7 +22543,7 @@ app14.post("/visit/:visitId/status", async (c) => {
22391
22543
  Math.round((Date.parse(out.value.at) - Date.parse(dueToLeaveAt)) / 1e3)
22392
22544
  );
22393
22545
  console.log(
22394
- `${TAG36} op=complete visitId=${visitId} checklist=${state.checklistDone}/${state.checklistTotal} notes=${state.notes} media=${state.media} parts=${state.parts} signatures=${state.signatures} lagS=${lagS}`
22546
+ `${TAG38} op=complete visitId=${visitId} checklist=${state.checklistDone}/${state.checklistTotal} notes=${state.notes} media=${state.media} parts=${state.parts} signatures=${state.signatures} lagS=${lagS}`
22395
22547
  );
22396
22548
  return c.json(out.value);
22397
22549
  });
@@ -22400,10 +22552,10 @@ app14.post("/probe", async (c) => {
22400
22552
  if (!auth.ok) return c.json({ reason: auth.reason }, auth.status);
22401
22553
  const p = await c.req.json();
22402
22554
  console.log(
22403
- `${TAG36} op=storage-probe platform=${p.platform} indexedDB=${p.indexedDB} localStorage=${p.localStorage} cacheStorage=${p.cacheStorage} serviceWorker=${p.serviceWorker} persisted=${p.persisted} workerId=${auth.worker.workerId}`
22555
+ `${TAG38} op=storage-probe platform=${p.platform} indexedDB=${p.indexedDB} localStorage=${p.localStorage} cacheStorage=${p.cacheStorage} serviceWorker=${p.serviceWorker} persisted=${p.persisted} workerId=${auth.worker.workerId}`
22404
22556
  );
22405
22557
  console.log(
22406
- `${TAG36} op=launch-params workerId=${auth.worker.workerId} keys=${(p.launchKeys ?? []).join(",") || "none"}`
22558
+ `${TAG38} op=launch-params workerId=${auth.worker.workerId} keys=${(p.launchKeys ?? []).join(",") || "none"}`
22407
22559
  );
22408
22560
  const anyUsable = p.indexedDB || p.localStorage || p.cacheStorage;
22409
22561
  noteFieldStorage(auth.accountId, auth.worker.workerId, anyUsable, Date.now());
@@ -22530,6 +22682,14 @@ app15.post("/", async (c) => {
22530
22682
  // the standard fields.
22531
22683
  "graph-fullscreen-not-covering",
22532
22684
  "graph-fullscreen-canvas-mismatch",
22685
+ // Task 2439 — the admin composer's own send failure. The inline reporter in
22686
+ // server/index.ts hooks only `error` and `unhandledrejection`, so a caught
22687
+ // fetch rejection in send() reached no sink at all. Without this entry the
22688
+ // POST collapses to kind=unknown and the log loses the source, which is the
22689
+ // whole point of the report. Deliberately NOT in ERROR_KINDS: it fires at
22690
+ // most once per send press, so it cannot exhaust a budget, and leaving it in
22691
+ // the telemetry class keeps the protected error budget for uncaught errors.
22692
+ "webchat-send-failed",
22533
22693
  "event"
22534
22694
  ]);
22535
22695
  const kind = allowedKinds.has(kindRaw) ? kindRaw : "unknown";
@@ -25309,7 +25469,7 @@ function resolveTunnelUrl() {
25309
25469
  if (!state) return null;
25310
25470
  return `https://${hostname2}.${state.domain}`;
25311
25471
  }
25312
- var TAG37 = "[claude-session-manager:wrapper]";
25472
+ var TAG39 = "[claude-session-manager:wrapper]";
25313
25473
  async function refuseIfClaudeAuthDead(c, route, sessionId) {
25314
25474
  const auth = await ensureAuth();
25315
25475
  if (auth.status !== "dead" && auth.status !== "missing") return null;
@@ -25327,12 +25487,12 @@ async function performSpawnWithInitialMessage(args) {
25327
25487
  const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
25328
25488
  const ownerMs = Date.now() - ownerStart;
25329
25489
  const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
25330
- console.log(`${TAG37} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
25490
+ console.log(`${TAG39} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
25331
25491
  const dormantPlugins = computeDormantPlugins(args.senderId);
25332
25492
  const activePlugins = computeActivePlugins(args.senderId);
25333
25493
  const specialistDomains = computeSpecialistDomains(args.senderId);
25334
25494
  const tunnelUrl = resolveTunnelUrl();
25335
- console.log(`${TAG37} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
25495
+ console.log(`${TAG39} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
25336
25496
  const upstreamPayload = JSON.stringify({
25337
25497
  senderId: args.senderId,
25338
25498
  // Task 205 — pass userId through to the manager so it lands as
@@ -25359,24 +25519,24 @@ async function performSpawnWithInitialMessage(args) {
25359
25519
  // unshapely values.
25360
25520
  conversationNodeId: args.conversationNodeId
25361
25521
  });
25362
- console.log(`${TAG37} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
25522
+ console.log(`${TAG39} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
25363
25523
  const forwardStart = Date.now();
25364
25524
  const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
25365
25525
  method: "POST",
25366
25526
  headers: { "content-type": "application/json" },
25367
25527
  body: upstreamPayload
25368
25528
  }).catch((err) => {
25369
- console.error(`${TAG37} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
25529
+ console.error(`${TAG39} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
25370
25530
  return null;
25371
25531
  });
25372
25532
  if (!upstream) return {
25373
25533
  response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
25374
25534
  claudeSessionId: null
25375
25535
  };
25376
- console.log(`${TAG37} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
25536
+ console.log(`${TAG39} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
25377
25537
  if (args.initialMessage) {
25378
25538
  const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
25379
- console.log(`${TAG37} initial-message-inlined bytes=${inputBytes}`);
25539
+ console.log(`${TAG39} initial-message-inlined bytes=${inputBytes}`);
25380
25540
  }
25381
25541
  const bodyText = await upstream.text().catch(() => "");
25382
25542
  let claudeSessionId = null;
@@ -25411,7 +25571,7 @@ app24.post("/", async (c) => {
25411
25571
  if (refusal) return refusal;
25412
25572
  const senderId = getAccountIdForSession(cacheKey) ?? "";
25413
25573
  if (!senderId) {
25414
- console.error(`${TAG37} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
25574
+ console.error(`${TAG39} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
25415
25575
  return c.json({ error: "admin-account-not-resolved" }, 500);
25416
25576
  }
25417
25577
  const userId = getUserIdForSession(cacheKey) ?? void 0;
@@ -25420,7 +25580,7 @@ app24.post("/", async (c) => {
25420
25580
  const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
25421
25581
  const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
25422
25582
  const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
25423
- console.log(`${TAG37} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
25583
+ console.log(`${TAG39} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
25424
25584
  const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
25425
25585
  const { response, claudeSessionId } = await performSpawnWithInitialMessage({
25426
25586
  senderId,
@@ -25439,13 +25599,13 @@ app24.post("/", async (c) => {
25439
25599
  claudeSessionId,
25440
25600
  senderId
25441
25601
  );
25442
- console.log(`${TAG37} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
25602
+ console.log(`${TAG39} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
25443
25603
  return response;
25444
25604
  });
25445
25605
  var claude_sessions_default = app24;
25446
25606
 
25447
25607
  // server/routes/admin/log-ingest.ts
25448
- var TAG38 = "[log-ingest]";
25608
+ var TAG40 = "[log-ingest]";
25449
25609
  var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
25450
25610
  var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
25451
25611
  var MAX_LINE_BYTES = 4096;
@@ -25456,7 +25616,7 @@ function isLoopbackAddr2(addr) {
25456
25616
  app25.post("/", async (c) => {
25457
25617
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
25458
25618
  if (!isLoopbackAddr2(remoteAddr)) {
25459
- console.error(`${TAG38} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25619
+ console.error(`${TAG40} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25460
25620
  return c.json({ error: "log-ingest-loopback-only" }, 403);
25461
25621
  }
25462
25622
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -25465,7 +25625,7 @@ app25.post("/", async (c) => {
25465
25625
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
25466
25626
  const offender = tokens.find((t) => !isLoopbackAddr2(t));
25467
25627
  if (offender !== void 0) {
25468
- console.error(`${TAG38} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25628
+ console.error(`${TAG40} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25469
25629
  return c.json({ error: "log-ingest-loopback-only" }, 403);
25470
25630
  }
25471
25631
  }
@@ -25500,7 +25660,7 @@ var log_ingest_default = app25;
25500
25660
 
25501
25661
  // server/routes/admin/session-blocked.ts
25502
25662
  import { join as join48 } from "path";
25503
- var TAG39 = "[blocked-tool-notify]";
25663
+ var TAG41 = "[blocked-tool-notify]";
25504
25664
  function isLoopbackAddr3(addr) {
25505
25665
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
25506
25666
  }
@@ -25518,18 +25678,18 @@ Answer the permission card in the session's PTY or in Claude Desktop. Some check
25518
25678
  async function sendWhatsApp(account, to, text) {
25519
25679
  const res = resolveSocket(account.accountId);
25520
25680
  if (!res.ok) {
25521
- console.error(`${TAG39} op=socket-unavailable accountId=${account.accountId} reason=${res.reason}`);
25681
+ console.error(`${TAG41} op=socket-unavailable accountId=${account.accountId} reason=${res.reason}`);
25522
25682
  return false;
25523
25683
  }
25524
25684
  const sent = await sendTextMessage(res.sock, to, text, { accountId: res.accountId });
25525
- if (!sent.success) console.error(`${TAG39} op=send-failed to=${to} error=${sent.error ?? "unknown"}`);
25685
+ if (!sent.success) console.error(`${TAG41} op=send-failed to=${to} error=${sent.error ?? "unknown"}`);
25526
25686
  return sent.success === true;
25527
25687
  }
25528
25688
  var app26 = new Hono();
25529
25689
  app26.post("/", async (c) => {
25530
25690
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
25531
25691
  if (!isLoopbackAddr3(remoteAddr)) {
25532
- console.error(`${TAG39} op=reject reason=non-loopback remoteAddr=${remoteAddr}`);
25692
+ console.error(`${TAG41} op=reject reason=non-loopback remoteAddr=${remoteAddr}`);
25533
25693
  return c.json({ error: "session-blocked-loopback-only" }, 403);
25534
25694
  }
25535
25695
  let body = {};
@@ -25550,13 +25710,13 @@ app26.post("/", async (c) => {
25550
25710
  const account = validateAccountId2(meta.accountId ?? "");
25551
25711
  if (!account) {
25552
25712
  console.error(
25553
- `${TAG39} op=account-unresolved sessionId=${sessionId.slice(0, 8)} sidecarAccountId=${meta.accountId ?? "none"}`
25713
+ `${TAG41} op=account-unresolved sessionId=${sessionId.slice(0, 8)} sidecarAccountId=${meta.accountId ?? "none"}`
25554
25714
  );
25555
25715
  return c.json({ delivered: false, channel: "none" }, 200);
25556
25716
  }
25557
25717
  if (meta.role === "admin" && meta.channel === "whatsapp" && meta.senderId) {
25558
25718
  const delivered2 = await sendWhatsApp(account, meta.senderId, text);
25559
- console.error(`${TAG39} op=notify sessionId=${sessionId.slice(0, 8)} channel=whatsapp delivered=${delivered2}`);
25719
+ console.error(`${TAG41} op=notify sessionId=${sessionId.slice(0, 8)} channel=whatsapp delivered=${delivered2}`);
25560
25720
  return c.json({ delivered: delivered2, channel: "whatsapp" }, 200);
25561
25721
  }
25562
25722
  if (meta.role === "admin" && meta.channel === "telegram" && meta.senderId) {
@@ -25566,11 +25726,11 @@ app26.post("/", async (c) => {
25566
25726
  const chatId = Number(parsed.senderId);
25567
25727
  if (resolved.kind === "one" && Number.isFinite(chatId)) {
25568
25728
  const res = await sendTelegramText(resolved.entry.token, chatId, text);
25569
- console.error(`${TAG39} op=notify sessionId=${sessionId.slice(0, 8)} channel=telegram delivered=${res.ok}`);
25729
+ console.error(`${TAG41} op=notify sessionId=${sessionId.slice(0, 8)} channel=telegram delivered=${res.ok}`);
25570
25730
  return c.json({ delivered: res.ok, channel: "telegram" }, 200);
25571
25731
  }
25572
25732
  console.error(
25573
- `${TAG39} op=telegram-unresolved sessionId=${sessionId.slice(0, 8)} botId=${parsed.botId} kind=${resolved.kind}`
25733
+ `${TAG41} op=telegram-unresolved sessionId=${sessionId.slice(0, 8)} botId=${parsed.botId} kind=${resolved.kind}`
25574
25734
  );
25575
25735
  }
25576
25736
  }
@@ -25580,7 +25740,7 @@ app26.post("/", async (c) => {
25580
25740
  if (await sendWhatsApp(account, phone, text)) delivered = true;
25581
25741
  }
25582
25742
  console.error(
25583
- `${TAG39} op=notify sessionId=${sessionId.slice(0, 8)} channel=house-admin phones=${phones.length} delivered=${delivered}`
25743
+ `${TAG41} op=notify sessionId=${sessionId.slice(0, 8)} channel=house-admin phones=${phones.length} delivered=${delivered}`
25584
25744
  );
25585
25745
  return c.json({ delivered, channel: "house-admin" }, 200);
25586
25746
  });
@@ -25613,18 +25773,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
25613
25773
  ]);
25614
25774
  var app27 = new Hono();
25615
25775
  app27.post("/", async (c) => {
25616
- const TAG75 = "[admin:events]";
25776
+ const TAG77 = "[admin:events]";
25617
25777
  let body;
25618
25778
  try {
25619
25779
  body = await c.req.json();
25620
25780
  } catch (err) {
25621
25781
  const detail = err instanceof Error ? err.message : String(err);
25622
- console.error(`${TAG75} reject reason=body-not-json detail=${detail}`);
25782
+ console.error(`${TAG77} reject reason=body-not-json detail=${detail}`);
25623
25783
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
25624
25784
  }
25625
25785
  const event = typeof body.event === "string" ? body.event : "";
25626
25786
  if (!ALLOWED_EVENTS.has(event)) {
25627
- console.error(`${TAG75} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
25787
+ console.error(`${TAG77} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
25628
25788
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
25629
25789
  }
25630
25790
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -31189,7 +31349,7 @@ function managerLogFollowUrl(sessionId, opts) {
31189
31349
  }
31190
31350
 
31191
31351
  // server/routes/admin/linkedin-ingest.ts
31192
- var TAG40 = "[linkedin-ingest-route]";
31352
+ var TAG42 = "[linkedin-ingest-route]";
31193
31353
  var UUID4 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
31194
31354
  var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
31195
31355
  var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
@@ -31314,28 +31474,28 @@ app45.post("/", requireIngestToken, async (c) => {
31314
31474
  try {
31315
31475
  body = await c.req.json();
31316
31476
  } catch {
31317
- console.error(TAG40 + " rejected status=400 reason=schema:body-not-json");
31477
+ console.error(TAG42 + " rejected status=400 reason=schema:body-not-json");
31318
31478
  return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
31319
31479
  }
31320
31480
  const v = validate2(body);
31321
31481
  if (!v.ok) {
31322
- console.error(TAG40 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
31482
+ console.error(TAG42 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
31323
31483
  return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
31324
31484
  }
31325
31485
  const envelope = v.envelope;
31326
31486
  const senderId = c.var.ingestAccountId ?? "";
31327
31487
  if (!senderId) {
31328
- console.error(TAG40 + " rejected status=500 reason=admin-account-not-resolved");
31488
+ console.error(TAG42 + " rejected status=500 reason=admin-account-not-resolved");
31329
31489
  return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
31330
31490
  }
31331
31491
  const payloadBytes = JSON.stringify(envelope).length;
31332
31492
  console.log(
31333
- TAG40 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
31493
+ TAG42 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
31334
31494
  );
31335
31495
  const initialMessage = buildInitialMessage(envelope);
31336
31496
  const spawnStart = Date.now();
31337
31497
  const sessionId = randomUUID9();
31338
- console.log(TAG40 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
31498
+ console.log(TAG42 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
31339
31499
  const spawned = await managerRcSpawn({
31340
31500
  sessionId,
31341
31501
  initialMessage,
@@ -31348,12 +31508,12 @@ app45.post("/", requireIngestToken, async (c) => {
31348
31508
  });
31349
31509
  if ("error" in spawned) {
31350
31510
  console.error(
31351
- TAG40 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
31511
+ TAG42 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
31352
31512
  );
31353
31513
  return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
31354
31514
  }
31355
31515
  console.log(
31356
- TAG40 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
31516
+ TAG42 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
31357
31517
  );
31358
31518
  return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
31359
31519
  });
@@ -31361,7 +31521,7 @@ var linkedin_ingest_default = app45;
31361
31521
 
31362
31522
  // server/routes/admin/post-turn-context.ts
31363
31523
  import neo4j3 from "neo4j-driver";
31364
- var TAG41 = "[post-turn-context]";
31524
+ var TAG43 = "[post-turn-context]";
31365
31525
  var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
31366
31526
  "embedding",
31367
31527
  "passwordHash",
@@ -31403,7 +31563,7 @@ var app46 = new Hono();
31403
31563
  app46.get("/", async (c) => {
31404
31564
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
31405
31565
  if (!isLoopbackAddr4(remoteAddr)) {
31406
- console.error(`${TAG41} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31566
+ console.error(`${TAG43} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31407
31567
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
31408
31568
  }
31409
31569
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -31412,7 +31572,7 @@ app46.get("/", async (c) => {
31412
31572
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
31413
31573
  const offender = tokens.find((t) => !isLoopbackAddr4(t));
31414
31574
  if (offender !== void 0) {
31415
- console.error(`${TAG41} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31575
+ console.error(`${TAG43} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31416
31576
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
31417
31577
  }
31418
31578
  }
@@ -31444,7 +31604,7 @@ app46.get("/", async (c) => {
31444
31604
  writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
31445
31605
  const total = Date.now() - started2;
31446
31606
  console.log(
31447
- `${TAG41} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
31607
+ `${TAG43} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
31448
31608
  );
31449
31609
  return c.json({
31450
31610
  writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
@@ -31453,7 +31613,7 @@ app46.get("/", async (c) => {
31453
31613
  const elapsed = Date.now() - started2;
31454
31614
  const message = err instanceof Error ? err.message : String(err);
31455
31615
  console.error(
31456
- `${TAG41} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
31616
+ `${TAG43} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
31457
31617
  );
31458
31618
  return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
31459
31619
  } finally {
@@ -31566,7 +31726,7 @@ function formatPreviousContext(writes) {
31566
31726
  }
31567
31727
 
31568
31728
  // server/routes/admin/public-session-context.ts
31569
- var TAG42 = "[public-session-context]";
31729
+ var TAG44 = "[public-session-context]";
31570
31730
  function isLoopbackAddr5(addr) {
31571
31731
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
31572
31732
  }
@@ -31574,7 +31734,7 @@ var app47 = new Hono();
31574
31734
  app47.get("/", async (c) => {
31575
31735
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
31576
31736
  if (!isLoopbackAddr5(remoteAddr)) {
31577
- console.error(`${TAG42} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31737
+ console.error(`${TAG44} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31578
31738
  return c.json({ error: "public-session-context-loopback-only" }, 403);
31579
31739
  }
31580
31740
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -31583,7 +31743,7 @@ app47.get("/", async (c) => {
31583
31743
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
31584
31744
  const offender = tokens.find((t) => !isLoopbackAddr5(t));
31585
31745
  if (offender !== void 0) {
31586
- console.error(`${TAG42} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31746
+ console.error(`${TAG44} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31587
31747
  return c.json({ error: "public-session-context-loopback-only" }, 403);
31588
31748
  }
31589
31749
  }
@@ -31597,14 +31757,14 @@ app47.get("/", async (c) => {
31597
31757
  const writes = await fetchSliceWrites(session, sliceToken, accountId);
31598
31758
  const total = Date.now() - started2;
31599
31759
  console.log(
31600
- `${TAG42} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
31760
+ `${TAG44} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
31601
31761
  );
31602
31762
  return c.json({ writes });
31603
31763
  } catch (err) {
31604
31764
  const elapsed = Date.now() - started2;
31605
31765
  const message = err instanceof Error ? err.message : String(err);
31606
31766
  console.error(
31607
- `${TAG42} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
31767
+ `${TAG44} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
31608
31768
  );
31609
31769
  return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
31610
31770
  } finally {
@@ -31623,7 +31783,7 @@ function getWebchatGateway() {
31623
31783
  }
31624
31784
 
31625
31785
  // server/routes/admin/public-session-exit.ts
31626
- var TAG43 = "[public-session-exit-route]";
31786
+ var TAG45 = "[public-session-exit-route]";
31627
31787
  function isLoopbackAddr6(addr) {
31628
31788
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
31629
31789
  }
@@ -31631,7 +31791,7 @@ var app48 = new Hono();
31631
31791
  app48.post("/", async (c) => {
31632
31792
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
31633
31793
  if (!isLoopbackAddr6(remoteAddr)) {
31634
- console.error(`${TAG43} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31794
+ console.error(`${TAG45} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31635
31795
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
31636
31796
  }
31637
31797
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -31640,7 +31800,7 @@ app48.post("/", async (c) => {
31640
31800
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
31641
31801
  const offender = tokens.find((t) => !isLoopbackAddr6(t));
31642
31802
  if (offender !== void 0) {
31643
- console.error(`${TAG43} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31803
+ console.error(`${TAG45} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31644
31804
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
31645
31805
  }
31646
31806
  }
@@ -31654,7 +31814,7 @@ app48.post("/", async (c) => {
31654
31814
  if (!sessionId) return c.json({ error: "sessionId required" }, 400);
31655
31815
  const gateway = getWebchatGateway();
31656
31816
  if (!gateway) {
31657
- console.error(`${TAG43} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
31817
+ console.error(`${TAG45} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
31658
31818
  return c.json({ error: "webchat-gateway-unset" }, 503);
31659
31819
  }
31660
31820
  gateway.handlePublicSessionExit(sessionId);
@@ -31663,7 +31823,7 @@ app48.post("/", async (c) => {
31663
31823
  var public_session_exit_default = app48;
31664
31824
 
31665
31825
  // server/routes/admin/access-session-evict.ts
31666
- var TAG44 = "[access-session-evict]";
31826
+ var TAG46 = "[access-session-evict]";
31667
31827
  function isLoopbackAddr7(addr) {
31668
31828
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
31669
31829
  }
@@ -31671,7 +31831,7 @@ var app49 = new Hono();
31671
31831
  app49.post("/", async (c) => {
31672
31832
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
31673
31833
  if (!isLoopbackAddr7(remoteAddr)) {
31674
- console.error(`${TAG44} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31834
+ console.error(`${TAG46} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31675
31835
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
31676
31836
  }
31677
31837
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -31680,7 +31840,7 @@ app49.post("/", async (c) => {
31680
31840
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
31681
31841
  const offender = tokens.find((t) => !isLoopbackAddr7(t));
31682
31842
  if (offender !== void 0) {
31683
- console.error(`${TAG44} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31843
+ console.error(`${TAG46} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31684
31844
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
31685
31845
  }
31686
31846
  }
@@ -31693,13 +31853,13 @@ app49.post("/", async (c) => {
31693
31853
  const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
31694
31854
  if (!grantId) return c.json({ error: "grantId required" }, 400);
31695
31855
  const dropped = evictAccessSessionsByGrant(grantId);
31696
- console.log(`${TAG44} grantId=${grantId} dropped=${dropped}`);
31856
+ console.log(`${TAG46} grantId=${grantId} dropped=${dropped}`);
31697
31857
  return c.json({ ok: true, dropped });
31698
31858
  });
31699
31859
  var access_session_evict_default = app49;
31700
31860
 
31701
31861
  // server/routes/admin/enrol-person.ts
31702
- var TAG45 = "[enrol]";
31862
+ var TAG47 = "[enrol]";
31703
31863
  function isLoopbackAddr8(addr) {
31704
31864
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
31705
31865
  }
@@ -31708,7 +31868,7 @@ var app50 = new Hono();
31708
31868
  app50.post("/", async (c) => {
31709
31869
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
31710
31870
  if (!isLoopbackAddr8(remoteAddr)) {
31711
- console.error(`${TAG45} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31871
+ console.error(`${TAG47} reject reason=non-loopback remoteAddr=${remoteAddr}`);
31712
31872
  return c.json({ error: "enrol-person-loopback-only" }, 403);
31713
31873
  }
31714
31874
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -31717,7 +31877,7 @@ app50.post("/", async (c) => {
31717
31877
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
31718
31878
  const offender = tokens.find((t) => !isLoopbackAddr8(t));
31719
31879
  if (offender !== void 0) {
31720
- console.error(`${TAG45} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31880
+ console.error(`${TAG47} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
31721
31881
  return c.json({ error: "enrol-person-loopback-only" }, 403);
31722
31882
  }
31723
31883
  }
@@ -31742,7 +31902,7 @@ app50.post("/", async (c) => {
31742
31902
  }
31743
31903
  const accountId = process.env.ACCOUNT_ID ?? "";
31744
31904
  if (!accountId) {
31745
- console.error(`${TAG45} op=person result=no-account-id`);
31905
+ console.error(`${TAG47} op=person result=no-account-id`);
31746
31906
  return c.json({ error: "no-account-id" }, 500);
31747
31907
  }
31748
31908
  let personId;
@@ -31750,7 +31910,7 @@ app50.post("/", async (c) => {
31750
31910
  personId = await enrolPerson({ accountId, phone, email, agentSlug });
31751
31911
  } catch (err) {
31752
31912
  console.error(
31753
- `${TAG45} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
31913
+ `${TAG47} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
31754
31914
  );
31755
31915
  return c.json({ error: "enrol-failed" }, 500);
31756
31916
  }
@@ -31760,11 +31920,11 @@ app50.post("/", async (c) => {
31760
31920
  if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
31761
31921
  } catch (err) {
31762
31922
  console.error(
31763
- `${TAG45} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
31923
+ `${TAG47} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
31764
31924
  );
31765
31925
  }
31766
31926
  console.log(
31767
- `${TAG45} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
31927
+ `${TAG47} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
31768
31928
  );
31769
31929
  return c.json({ personId, grant }, 200);
31770
31930
  });
@@ -33832,7 +33992,7 @@ function toNum(v) {
33832
33992
  }
33833
33993
 
33834
33994
  // server/routes/admin/tasks-list.ts
33835
- var TAG46 = "[task-timer]";
33995
+ var TAG48 = "[task-timer]";
33836
33996
  var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
33837
33997
  var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
33838
33998
  var app57 = new Hono();
@@ -33840,12 +34000,12 @@ app57.get("/", requireAdminSession, async (c) => {
33840
34000
  const cacheKey = c.var.cacheKey;
33841
34001
  const accountId = getAccountIdForSession(cacheKey);
33842
34002
  if (!accountId) {
33843
- console.error(`${TAG46} op=list auth-rejected reason="no account for session"`);
34003
+ console.error(`${TAG48} op=list auth-rejected reason="no account for session"`);
33844
34004
  return c.json({ error: "Account not found for session" }, 401);
33845
34005
  }
33846
34006
  const cacheStart = Date.now();
33847
34007
  const cached3 = await getOrCompute("tasks-list", accountId, () => computeTaskList(accountId));
33848
- console.log(`${TAG46} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
34008
+ console.log(`${TAG48} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
33849
34009
  if (cached3.value === null) {
33850
34010
  return c.json({ error: "tasks-list-failed" }, 500);
33851
34011
  }
@@ -33946,13 +34106,13 @@ async function computeTaskList(accountId) {
33946
34106
  orphans = orphanResult.records.length > 0 ? toNum(orphanResult.records[0].get("orphans")) : 0;
33947
34107
  } catch (err) {
33948
34108
  console.error(
33949
- `${TAG46} op=session-orphans-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
34109
+ `${TAG48} op=session-orphans-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
33950
34110
  );
33951
34111
  orphans = -1;
33952
34112
  }
33953
34113
  if (orphans > 0) {
33954
34114
  console.error(
33955
- `${TAG46} op=session-orphans account=${accountId} orphans=${orphans} detail="task marked for a session spawn that never linked; the spawned session is unreachable from its row"`
34115
+ `${TAG48} op=session-orphans account=${accountId} orphans=${orphans} detail="task marked for a session spawn that never linked; the spawned session is unreachable from its row"`
33956
34116
  );
33957
34117
  }
33958
34118
  let orphanEntries = 0;
@@ -33971,14 +34131,14 @@ async function computeTaskList(accountId) {
33971
34131
  orphanAdjustments = orphanTime.records.length > 0 ? toNum(orphanTime.records[0].get("orphanAdjustments")) : 0;
33972
34132
  } catch (err) {
33973
34133
  console.error(
33974
- `${TAG46} op=orphan-time-records-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
34134
+ `${TAG48} op=orphan-time-records-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
33975
34135
  );
33976
34136
  orphanEntries = -1;
33977
34137
  orphanAdjustments = -1;
33978
34138
  }
33979
34139
  if (orphanEntries > 0 || orphanAdjustments > 0) {
33980
34140
  console.error(
33981
- `${TAG46} op=orphan-time-records account=${accountId} orphanEntries=${orphanEntries} orphanAdjustments=${orphanAdjustments} detail="time records whose task no longer exists; something removed the task without its records"`
34141
+ `${TAG48} op=orphan-time-records account=${accountId} orphanEntries=${orphanEntries} orphanAdjustments=${orphanAdjustments} detail="time records whose task no longer exists; something removed the task without its records"`
33982
34142
  );
33983
34143
  }
33984
34144
  const linkedIds = [...open3, ...completed].map((r) => r.sessionId).filter((s) => s !== null);
@@ -33991,7 +34151,7 @@ async function computeTaskList(accountId) {
33991
34151
  const walk = enumerateJsonlsWithSkips(join60(cfg, "projects"));
33992
34152
  if (walk.skipped > 0) {
33993
34153
  console.error(
33994
- `${TAG46} op=session-dangling-census-incomplete account=${accountId} skipped=${walk.skipped} detail="a slug the walk could not read contributes no session ids, so its links cannot be judged"`
34154
+ `${TAG48} op=session-dangling-census-incomplete account=${accountId} skipped=${walk.skipped} detail="a slug the walk could not read contributes no session ids, so its links cannot be judged"`
33995
34155
  );
33996
34156
  dangling = null;
33997
34157
  } else {
@@ -34000,28 +34160,28 @@ async function computeTaskList(accountId) {
34000
34160
  }
34001
34161
  } catch (err) {
34002
34162
  console.error(
34003
- `${TAG46} op=session-dangling-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
34163
+ `${TAG48} op=session-dangling-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
34004
34164
  );
34005
34165
  dangling = null;
34006
34166
  }
34007
34167
  }
34008
34168
  if (dangling !== null && dangling > 0) {
34009
34169
  console.error(
34010
- `${TAG46} op=session-dangling account=${accountId} dangling=${dangling} linked=${linkedIds.length} detail="a task links a session with no JSONL on disk; clicking it will not resume"`
34170
+ `${TAG48} op=session-dangling account=${accountId} dangling=${dangling} linked=${linkedIds.length} detail="a task links a session with no JSONL on disk; clicking it will not resume"`
34011
34171
  );
34012
34172
  }
34013
34173
  const returned = result.records.length;
34014
34174
  if (returned < graphTotal) {
34015
34175
  console.error(
34016
- `${TAG46} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
34176
+ `${TAG48} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
34017
34177
  );
34018
34178
  }
34019
34179
  console.log(
34020
- `${TAG46} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned} sessionLinked=${sessionLinked} sessionOrphans=${orphans < 0 ? "n/a" : orphans} sessionDangling=${dangling === null ? "n/a" : dangling}`
34180
+ `${TAG48} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned} sessionLinked=${sessionLinked} sessionOrphans=${orphans < 0 ? "n/a" : orphans} sessionDangling=${dangling === null ? "n/a" : dangling}`
34021
34181
  );
34022
34182
  return { open: open3, completed };
34023
34183
  } catch (err) {
34024
- console.error(`${TAG46} op=list error="${err instanceof Error ? err.message : String(err)}"`);
34184
+ console.error(`${TAG48} op=list error="${err instanceof Error ? err.message : String(err)}"`);
34025
34185
  return null;
34026
34186
  } finally {
34027
34187
  await session.close();
@@ -34031,7 +34191,7 @@ var tasks_list_default = app57;
34031
34191
 
34032
34192
  // server/routes/admin/task-timer-start.ts
34033
34193
  import { randomUUID as randomUUID11 } from "crypto";
34034
- var TAG47 = "[task-timer]";
34194
+ var TAG49 = "[task-timer]";
34035
34195
  var app58 = new Hono();
34036
34196
  app58.post("/", requireAdminSession, async (c) => {
34037
34197
  const cacheKey = c.var.cacheKey;
@@ -34046,7 +34206,7 @@ app58.post("/", requireAdminSession, async (c) => {
34046
34206
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
34047
34207
  if (!taskId) {
34048
34208
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
34049
- console.error(`${TAG47} op=timer-start rejected reason=${reason} account=${accountId}`);
34209
+ console.error(`${TAG49} op=timer-start rejected reason=${reason} account=${accountId}`);
34050
34210
  return c.json({ error: "taskId required" }, 400);
34051
34211
  }
34052
34212
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -34057,7 +34217,7 @@ app58.post("/", requireAdminSession, async (c) => {
34057
34217
  { taskId, accountId }
34058
34218
  );
34059
34219
  if (target.records.length === 0) {
34060
- console.error(`${TAG47} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
34220
+ console.error(`${TAG49} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
34061
34221
  return c.json({ error: "task-not-found" }, 404);
34062
34222
  }
34063
34223
  const open3 = await session.run(
@@ -34069,7 +34229,7 @@ app58.post("/", requireAdminSession, async (c) => {
34069
34229
  const priorEntryId = open3.records[0]?.get("entryId");
34070
34230
  const priorStartedAt = open3.records[0]?.get("startedAt");
34071
34231
  if (priorEntryId) {
34072
- console.log(`${TAG47} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
34232
+ console.log(`${TAG49} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
34073
34233
  invalidate("tasks-list", accountId);
34074
34234
  return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
34075
34235
  }
@@ -34080,11 +34240,11 @@ app58.post("/", requireAdminSession, async (c) => {
34080
34240
  CREATE (te)-[:LOGGED_AGAINST]->(t)`,
34081
34241
  { taskId, accountId, entryId, now }
34082
34242
  );
34083
- console.log(`${TAG47} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
34243
+ console.log(`${TAG49} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
34084
34244
  invalidate("tasks-list", accountId);
34085
34245
  return c.json({ ok: true, running: true, entryId, startedAt: now });
34086
34246
  } catch (err) {
34087
- console.error(`${TAG47} op=start error="${err instanceof Error ? err.message : String(err)}"`);
34247
+ console.error(`${TAG49} op=start error="${err instanceof Error ? err.message : String(err)}"`);
34088
34248
  return c.json({ error: "task-timer-start-failed" }, 500);
34089
34249
  } finally {
34090
34250
  await session.close();
@@ -34094,7 +34254,7 @@ var task_timer_start_default = app58;
34094
34254
 
34095
34255
  // server/routes/admin/task-timer-stop.ts
34096
34256
  import neo4j5 from "neo4j-driver";
34097
- var TAG48 = "[task-timer]";
34257
+ var TAG50 = "[task-timer]";
34098
34258
  var app59 = new Hono();
34099
34259
  app59.post("/", requireAdminSession, async (c) => {
34100
34260
  const cacheKey = c.var.cacheKey;
@@ -34109,7 +34269,7 @@ app59.post("/", requireAdminSession, async (c) => {
34109
34269
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
34110
34270
  if (!taskId) {
34111
34271
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
34112
- console.error(`${TAG48} op=timer-stop rejected reason=${reason} account=${accountId}`);
34272
+ console.error(`${TAG50} op=timer-stop rejected reason=${reason} account=${accountId}`);
34113
34273
  return c.json({ error: "taskId required" }, 400);
34114
34274
  }
34115
34275
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -34130,7 +34290,7 @@ app59.post("/", requireAdminSession, async (c) => {
34130
34290
  { taskId, accountId }
34131
34291
  );
34132
34292
  const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
34133
- console.log(`${TAG48} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
34293
+ console.log(`${TAG50} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
34134
34294
  invalidate("tasks-list", accountId);
34135
34295
  return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
34136
34296
  }
@@ -34154,12 +34314,12 @@ app59.post("/", requireAdminSession, async (c) => {
34154
34314
  const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
34155
34315
  const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
34156
34316
  const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
34157
- console.log(`${TAG48} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
34158
- console.log(`${TAG48} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
34317
+ console.log(`${TAG50} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
34318
+ console.log(`${TAG50} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
34159
34319
  invalidate("tasks-list", accountId);
34160
34320
  return c.json({ ok: true, running: false, seconds, secondsLogged });
34161
34321
  } catch (err) {
34162
- console.error(`${TAG48} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
34322
+ console.error(`${TAG50} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
34163
34323
  return c.json({ error: "task-timer-stop-failed" }, 500);
34164
34324
  } finally {
34165
34325
  await session.close();
@@ -34168,7 +34328,7 @@ app59.post("/", requireAdminSession, async (c) => {
34168
34328
  var task_timer_stop_default = app59;
34169
34329
 
34170
34330
  // server/routes/admin/task-complete.ts
34171
- var TAG49 = "[task-timer]";
34331
+ var TAG51 = "[task-timer]";
34172
34332
  var app60 = new Hono();
34173
34333
  app60.post("/", requireAdminSession, async (c) => {
34174
34334
  const cacheKey = c.var.cacheKey;
@@ -34183,7 +34343,7 @@ app60.post("/", requireAdminSession, async (c) => {
34183
34343
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
34184
34344
  if (!taskId) {
34185
34345
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
34186
- console.error(`${TAG49} op=complete rejected reason=${reason} account=${accountId}`);
34346
+ console.error(`${TAG51} op=complete rejected reason=${reason} account=${accountId}`);
34187
34347
  return c.json({ error: "taskId required" }, 400);
34188
34348
  }
34189
34349
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -34199,11 +34359,11 @@ app60.post("/", requireAdminSession, async (c) => {
34199
34359
  return c.json({ error: "task-not-found" }, 404);
34200
34360
  }
34201
34361
  const secondsLogged = toNum(result.records[0].get("secondsLogged"));
34202
- console.log(`${TAG49} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
34362
+ console.log(`${TAG51} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
34203
34363
  invalidate("tasks-list", accountId);
34204
34364
  return c.json({ ok: true, status: "completed", secondsLogged });
34205
34365
  } catch (err) {
34206
- console.error(`${TAG49} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
34366
+ console.error(`${TAG51} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
34207
34367
  return c.json({ error: "task-complete-failed" }, 500);
34208
34368
  } finally {
34209
34369
  await session.close();
@@ -34214,7 +34374,7 @@ var task_complete_default = app60;
34214
34374
  // server/routes/admin/task-time-adjust.ts
34215
34375
  import { randomUUID as randomUUID12 } from "crypto";
34216
34376
  import neo4j6 from "neo4j-driver";
34217
- var TAG50 = "[task-time-adjust]";
34377
+ var TAG52 = "[task-time-adjust]";
34218
34378
  var app61 = new Hono();
34219
34379
  app61.post("/", requireAdminSession, async (c) => {
34220
34380
  const cacheKey = c.var.cacheKey;
@@ -34224,23 +34384,23 @@ app61.post("/", requireAdminSession, async (c) => {
34224
34384
  try {
34225
34385
  body = await c.req.json();
34226
34386
  } catch {
34227
- console.error(`${TAG50} op=reject reason=bad-json`);
34387
+ console.error(`${TAG52} op=reject reason=bad-json`);
34228
34388
  return c.json({ error: "invalid-json" }, 400);
34229
34389
  }
34230
34390
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
34231
34391
  if (!taskId) {
34232
34392
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
34233
- console.error(`${TAG50} op=time-adjust rejected reason=${reason} account=${accountId}`);
34393
+ console.error(`${TAG52} op=time-adjust rejected reason=${reason} account=${accountId}`);
34234
34394
  return c.json({ error: "taskId required" }, 400);
34235
34395
  }
34236
34396
  const newSeconds = body.newSeconds;
34237
34397
  if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
34238
- console.error(`${TAG50} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
34398
+ console.error(`${TAG52} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
34239
34399
  return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
34240
34400
  }
34241
34401
  const adjustmentId = randomUUID12();
34242
34402
  const now = (/* @__PURE__ */ new Date()).toISOString();
34243
- console.log(`${TAG50} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
34403
+ console.log(`${TAG52} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
34244
34404
  const session = getSession();
34245
34405
  try {
34246
34406
  const guard = await session.run(
@@ -34250,12 +34410,12 @@ app61.post("/", requireAdminSession, async (c) => {
34250
34410
  { taskId, accountId }
34251
34411
  );
34252
34412
  if (guard.records.length === 0) {
34253
- console.error(`${TAG50} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
34413
+ console.error(`${TAG52} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
34254
34414
  return c.json({ error: "task-not-found" }, 404);
34255
34415
  }
34256
34416
  const openCount = toNum(guard.records[0].get("openCount"));
34257
34417
  if (openCount > 0) {
34258
- console.error(`${TAG50} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
34418
+ console.error(`${TAG52} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
34259
34419
  return c.json({ error: "task-timer-running" }, 409);
34260
34420
  }
34261
34421
  const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
@@ -34281,11 +34441,11 @@ app61.post("/", requireAdminSession, async (c) => {
34281
34441
  }
34282
34442
  );
34283
34443
  const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
34284
- console.log(`${TAG50} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
34444
+ console.log(`${TAG52} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
34285
34445
  invalidate("tasks-list", accountId);
34286
34446
  return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
34287
34447
  } catch (err) {
34288
- console.error(`${TAG50} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
34448
+ console.error(`${TAG52} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
34289
34449
  return c.json({ error: "task-time-adjust-failed" }, 500);
34290
34450
  } finally {
34291
34451
  await session.close();
@@ -34295,7 +34455,7 @@ var task_time_adjust_default = app61;
34295
34455
 
34296
34456
  // server/routes/admin/task-delete.ts
34297
34457
  import { randomUUID as randomUUID13 } from "crypto";
34298
- var TAG51 = "[task-delete]";
34458
+ var TAG53 = "[task-delete]";
34299
34459
  var app62 = new Hono();
34300
34460
  app62.post("/", requireAdminSession, async (c) => {
34301
34461
  const cacheKey = c.var.cacheKey;
@@ -34305,18 +34465,18 @@ app62.post("/", requireAdminSession, async (c) => {
34305
34465
  try {
34306
34466
  body = await c.req.json();
34307
34467
  } catch {
34308
- console.error(`${TAG51} op=reject reason=bad-json`);
34468
+ console.error(`${TAG53} op=reject reason=bad-json`);
34309
34469
  return c.json({ error: "invalid-json" }, 400);
34310
34470
  }
34311
34471
  const deletionId = randomUUID13();
34312
34472
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
34313
34473
  if (!taskId) {
34314
34474
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
34315
- console.error(`${TAG51} op=reject reason=${reason} deletionId=${deletionId} accountId=${accountId}`);
34475
+ console.error(`${TAG53} op=reject reason=${reason} deletionId=${deletionId} accountId=${accountId}`);
34316
34476
  return c.json({ error: "taskId required" }, 400);
34317
34477
  }
34318
34478
  console.log(
34319
- `${TAG51} op=request deletionId=${deletionId} taskId=${taskId} accountId=${accountId} confirmed=${body.confirmed === true}`
34479
+ `${TAG53} op=request deletionId=${deletionId} taskId=${taskId} accountId=${accountId} confirmed=${body.confirmed === true}`
34320
34480
  );
34321
34481
  const session = getSession();
34322
34482
  try {
@@ -34332,18 +34492,18 @@ app62.post("/", requireAdminSession, async (c) => {
34332
34492
  { taskId, accountId }
34333
34493
  );
34334
34494
  if (guard.records.length === 0) {
34335
- console.error(`${TAG51} op=reject reason=no-task deletionId=${deletionId} taskId=${taskId} accountId=${accountId}`);
34495
+ console.error(`${TAG53} op=reject reason=no-task deletionId=${deletionId} taskId=${taskId} accountId=${accountId}`);
34336
34496
  return c.json({ error: "task-not-found" }, 404);
34337
34497
  }
34338
34498
  const timeEntries = toNum(guard.records[0].get("timeEntries"));
34339
34499
  const openCount = toNum(guard.records[0].get("openCount"));
34340
34500
  const adjustments = toNum(guard.records[0].get("adjustments"));
34341
34501
  console.log(
34342
- `${TAG51} op=guard deletionId=${deletionId} taskId=${taskId} openCount=${openCount} timeEntries=${timeEntries} adjustments=${adjustments}`
34502
+ `${TAG53} op=guard deletionId=${deletionId} taskId=${taskId} openCount=${openCount} timeEntries=${timeEntries} adjustments=${adjustments}`
34343
34503
  );
34344
34504
  if (openCount > 0) {
34345
34505
  console.error(
34346
- `${TAG51} op=reject reason=running deletionId=${deletionId} taskId=${taskId} openCount=${openCount}`
34506
+ `${TAG53} op=reject reason=running deletionId=${deletionId} taskId=${taskId} openCount=${openCount}`
34347
34507
  );
34348
34508
  return c.json({ error: "task-timer-running" }, 409);
34349
34509
  }
@@ -34379,18 +34539,18 @@ app62.post("/", requireAdminSession, async (c) => {
34379
34539
  const adjustmentsLeft = toNum(after.records[0]?.get("adjustmentsLeft"));
34380
34540
  const remaining = taskLeft + entriesLeft + adjustmentsLeft;
34381
34541
  console.log(
34382
- `${TAG51} op=persisted deletionId=${deletionId} taskId=${taskId} tasksDeleted=${tasksDeleted} timeEntriesDeleted=${timeEntriesDeleted} adjustmentsDeleted=${adjustmentsDeleted} remaining=${remaining}`
34542
+ `${TAG53} op=persisted deletionId=${deletionId} taskId=${taskId} tasksDeleted=${tasksDeleted} timeEntriesDeleted=${timeEntriesDeleted} adjustmentsDeleted=${adjustmentsDeleted} remaining=${remaining}`
34383
34543
  );
34384
34544
  if (remaining > 0) {
34385
34545
  console.error(
34386
- `${TAG51} op=incomplete deletionId=${deletionId} taskId=${taskId} taskLeft=${taskLeft} entriesLeft=${entriesLeft} adjustmentsLeft=${adjustmentsLeft} detail="the delete returned but rows for this taskId survive"`
34546
+ `${TAG53} op=incomplete deletionId=${deletionId} taskId=${taskId} taskLeft=${taskLeft} entriesLeft=${entriesLeft} adjustmentsLeft=${adjustmentsLeft} detail="the delete returned but rows for this taskId survive"`
34387
34547
  );
34388
34548
  }
34389
34549
  invalidate("tasks-list", accountId);
34390
34550
  return c.json({ ok: true, tasksDeleted, timeEntriesDeleted, adjustmentsDeleted, remaining });
34391
34551
  } catch (err) {
34392
34552
  console.error(
34393
- `${TAG51} op=error deletionId=${deletionId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`
34553
+ `${TAG53} op=error deletionId=${deletionId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`
34394
34554
  );
34395
34555
  return c.json({ error: "task-delete-failed" }, 500);
34396
34556
  } finally {
@@ -34484,7 +34644,7 @@ async function resolveAssignableAdmins(accountId, accountsDir = ACCOUNTS_DIR) {
34484
34644
  }
34485
34645
 
34486
34646
  // server/routes/admin/task-assign.ts
34487
- var TAG52 = "[task-assign]";
34647
+ var TAG54 = "[task-assign]";
34488
34648
  var app63 = new Hono();
34489
34649
  app63.post("/", requireAdminSession, async (c) => {
34490
34650
  const cacheKey = c.var.cacheKey;
@@ -34499,7 +34659,7 @@ app63.post("/", requireAdminSession, async (c) => {
34499
34659
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
34500
34660
  if (!taskId) {
34501
34661
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
34502
- console.error(`${TAG52} op=assign rejected reason=${reason} account=${accountId}`);
34662
+ console.error(`${TAG54} op=assign rejected reason=${reason} account=${accountId}`);
34503
34663
  return c.json({ error: "taskId required" }, 400);
34504
34664
  }
34505
34665
  const rawAssignee = body.assigneeUserId;
@@ -34511,7 +34671,7 @@ app63.post("/", requireAdminSession, async (c) => {
34511
34671
  const { ids } = await resolveAllowedAssigneeIds(accountId);
34512
34672
  if (!ids.has(assigneeUserId)) {
34513
34673
  console.error(
34514
- `${TAG52} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
34674
+ `${TAG54} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
34515
34675
  );
34516
34676
  return c.json({ error: "assignee-not-in-roster" }, 403);
34517
34677
  }
@@ -34533,7 +34693,7 @@ app63.post("/", requireAdminSession, async (c) => {
34533
34693
  `MATCH (t:Task {taskId: $taskId, accountId: $accountId}) SET t.updatedAt = $now`,
34534
34694
  { taskId, accountId, now }
34535
34695
  );
34536
- console.log(`${TAG52} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
34696
+ console.log(`${TAG54} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
34537
34697
  invalidate("tasks-list", accountId);
34538
34698
  return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
34539
34699
  }
@@ -34549,7 +34709,7 @@ app63.post("/", requireAdminSession, async (c) => {
34549
34709
  );
34550
34710
  if (set.records.length === 0) {
34551
34711
  console.error(
34552
- `${TAG52} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
34712
+ `${TAG54} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
34553
34713
  );
34554
34714
  return c.json({ error: "assignee-no-admin-node" }, 409);
34555
34715
  }
@@ -34557,12 +34717,12 @@ app63.post("/", requireAdminSession, async (c) => {
34557
34717
  const family = set.records[0].get("familyName") ?? null;
34558
34718
  const assigneeName = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
34559
34719
  console.log(
34560
- `${TAG52} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
34720
+ `${TAG54} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
34561
34721
  );
34562
34722
  invalidate("tasks-list", accountId);
34563
34723
  return c.json({ ok: true, assigneeUserId, assigneeName });
34564
34724
  } catch (err) {
34565
- console.error(`${TAG52} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
34725
+ console.error(`${TAG54} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
34566
34726
  return c.json({ error: "task-assign-failed" }, 500);
34567
34727
  } finally {
34568
34728
  await session.close();
@@ -34571,13 +34731,13 @@ app63.post("/", requireAdminSession, async (c) => {
34571
34731
  var task_assign_default = app63;
34572
34732
 
34573
34733
  // server/routes/admin/task-session-open.ts
34574
- var TAG53 = "[task-session]";
34734
+ var TAG55 = "[task-session]";
34575
34735
  var app64 = new Hono();
34576
34736
  app64.post("/", requireAdminSession, async (c) => {
34577
34737
  const cacheKey = c.var.cacheKey;
34578
34738
  const accountId = getAccountIdForSession(cacheKey);
34579
34739
  if (!accountId) {
34580
- console.error(`${TAG53} op=request auth-rejected reason="no account for session"`);
34740
+ console.error(`${TAG55} op=request auth-rejected reason="no account for session"`);
34581
34741
  return c.json({ error: "Account not found for session" }, 401);
34582
34742
  }
34583
34743
  let body;
@@ -34589,7 +34749,7 @@ app64.post("/", requireAdminSession, async (c) => {
34589
34749
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
34590
34750
  if (!taskId) {
34591
34751
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
34592
- console.error(`${TAG53} op=request rejected reason=${reason} account=${accountId}`);
34752
+ console.error(`${TAG55} op=request rejected reason=${reason} account=${accountId}`);
34593
34753
  return c.json({ error: "taskId required" }, 400);
34594
34754
  }
34595
34755
  const session = getSession();
@@ -34603,14 +34763,14 @@ app64.post("/", requireAdminSession, async (c) => {
34603
34763
  { taskId, accountId }
34604
34764
  );
34605
34765
  if (found.records.length === 0) {
34606
- console.error(`${TAG53} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
34766
+ console.error(`${TAG55} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
34607
34767
  return c.json({ error: "task-not-found" }, 404);
34608
34768
  }
34609
34769
  const title = found.records[0].get("name") ?? "";
34610
34770
  const sessionId = found.records[0].get("sessionId") ?? null;
34611
34771
  const description = found.records[0].get("description") ?? "";
34612
34772
  const notes = found.records[0].get("notes") ?? "";
34613
- console.log(`${TAG53} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
34773
+ console.log(`${TAG55} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
34614
34774
  if (sessionId !== null) return c.json({ sessionId, title, description, notes });
34615
34775
  const now = (/* @__PURE__ */ new Date()).toISOString();
34616
34776
  const stamped = await session.run(
@@ -34620,10 +34780,10 @@ app64.post("/", requireAdminSession, async (c) => {
34620
34780
  { taskId, accountId, now }
34621
34781
  );
34622
34782
  const at = stamped.records[0]?.get("at") ?? void 0;
34623
- console.log(`${TAG53} op=marker taskId=${taskId} stamped=${at !== void 0}`);
34783
+ console.log(`${TAG55} op=marker taskId=${taskId} stamped=${at !== void 0}`);
34624
34784
  return c.json({ sessionId: null, title, description, notes });
34625
34785
  } catch (err) {
34626
- console.error(`${TAG53} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
34786
+ console.error(`${TAG55} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
34627
34787
  return c.json({ error: "task-session-open-failed" }, 500);
34628
34788
  } finally {
34629
34789
  await session.close();
@@ -34632,13 +34792,13 @@ app64.post("/", requireAdminSession, async (c) => {
34632
34792
  var task_session_open_default = app64;
34633
34793
 
34634
34794
  // server/routes/admin/task-session-link.ts
34635
- var TAG54 = "[task-session]";
34795
+ var TAG56 = "[task-session]";
34636
34796
  var app65 = new Hono();
34637
34797
  app65.post("/", requireAdminSession, async (c) => {
34638
34798
  const cacheKey = c.var.cacheKey;
34639
34799
  const accountId = getAccountIdForSession(cacheKey);
34640
34800
  if (!accountId) {
34641
- console.error(`${TAG54} op=link auth-rejected reason="no account for session"`);
34801
+ console.error(`${TAG56} op=link auth-rejected reason="no account for session"`);
34642
34802
  return c.json({ error: "Account not found for session" }, 401);
34643
34803
  }
34644
34804
  let body;
@@ -34650,12 +34810,12 @@ app65.post("/", requireAdminSession, async (c) => {
34650
34810
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
34651
34811
  if (!taskId) {
34652
34812
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
34653
- console.error(`${TAG54} op=link rejected reason=${reason} account=${accountId}`);
34813
+ console.error(`${TAG56} op=link rejected reason=${reason} account=${accountId}`);
34654
34814
  return c.json({ error: "taskId required" }, 400);
34655
34815
  }
34656
34816
  const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : "";
34657
34817
  if (!sessionId) {
34658
- console.error(`${TAG54} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
34818
+ console.error(`${TAG56} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
34659
34819
  return c.json({ error: "sessionId required" }, 400);
34660
34820
  }
34661
34821
  const session = getSession();
@@ -34669,13 +34829,13 @@ app65.post("/", requireAdminSession, async (c) => {
34669
34829
  { taskId, accountId, sessionId }
34670
34830
  );
34671
34831
  if (state.records.length === 0) {
34672
- console.error(`${TAG54} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
34832
+ console.error(`${TAG56} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
34673
34833
  return c.json({ error: "task-not-found" }, 404);
34674
34834
  }
34675
34835
  const conversationExists = state.records[0].get("conversationExists") === true;
34676
34836
  const priorSessionIds = (state.records[0].get("priorSessionIds") ?? []).filter((s) => typeof s === "string");
34677
34837
  if (!conversationExists) {
34678
- console.error(`${TAG54} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
34838
+ console.error(`${TAG56} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
34679
34839
  return c.json({ linked: false, created: false, repointedFrom: null });
34680
34840
  }
34681
34841
  const stale = priorSessionIds.filter((s) => s !== sessionId);
@@ -34701,18 +34861,18 @@ app65.post("/", requireAdminSession, async (c) => {
34701
34861
  const repointedFrom = stale.length > 0 ? stale[0] : null;
34702
34862
  if (!linked) {
34703
34863
  console.error(
34704
- `${TAG54} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
34864
+ `${TAG56} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
34705
34865
  );
34706
34866
  return c.json({ linked: false, created: false, repointedFrom });
34707
34867
  }
34708
34868
  console.log(
34709
- `${TAG54} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
34869
+ `${TAG56} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
34710
34870
  );
34711
34871
  invalidate("tasks-list", accountId);
34712
34872
  return c.json({ linked: true, created, repointedFrom });
34713
34873
  } catch (err) {
34714
34874
  console.error(
34715
- `${TAG54} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
34875
+ `${TAG56} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
34716
34876
  );
34717
34877
  return c.json({ error: "task-session-link-failed" }, 500);
34718
34878
  } finally {
@@ -34722,21 +34882,21 @@ app65.post("/", requireAdminSession, async (c) => {
34722
34882
  var task_session_link_default = app65;
34723
34883
 
34724
34884
  // server/routes/admin/admin-users-list.ts
34725
- var TAG55 = "[admin-users]";
34885
+ var TAG57 = "[admin-users]";
34726
34886
  var app66 = new Hono();
34727
34887
  app66.get("/", requireAdminSession, async (c) => {
34728
34888
  const cacheKey = c.var.cacheKey;
34729
34889
  const accountId = getAccountIdForSession(cacheKey);
34730
34890
  if (!accountId) {
34731
- console.error(`${TAG55} op=list auth-rejected reason="no account for session"`);
34891
+ console.error(`${TAG57} op=list auth-rejected reason="no account for session"`);
34732
34892
  return c.json({ error: "Account not found for session" }, 401);
34733
34893
  }
34734
34894
  try {
34735
34895
  const users = await resolveAssignableAdmins(accountId);
34736
- console.log(`${TAG55} op=list account=${accountId} count=${users.length}`);
34896
+ console.log(`${TAG57} op=list account=${accountId} count=${users.length}`);
34737
34897
  return c.json({ ok: true, users });
34738
34898
  } catch (err) {
34739
- console.error(`${TAG55} op=list error="${err instanceof Error ? err.message : String(err)}"`);
34899
+ console.error(`${TAG57} op=list error="${err instanceof Error ? err.message : String(err)}"`);
34740
34900
  return c.json({ error: "admin-users-list-failed" }, 500);
34741
34901
  }
34742
34902
  });
@@ -34744,7 +34904,7 @@ var admin_users_list_default = app66;
34744
34904
 
34745
34905
  // server/routes/admin/dispatch-destinations.ts
34746
34906
  import { resolve as resolve43 } from "path";
34747
- var TAG56 = "[admin:routines]";
34907
+ var TAG58 = "[admin:routines]";
34748
34908
  function scopeFor(d, houseDir, houseAccountId) {
34749
34909
  if (d.channel !== "whatsapp") return null;
34750
34910
  if (d.label === "Account manager") return boundSubAccountFor(houseDir, d.destination);
@@ -34762,7 +34922,7 @@ var app67 = new Hono();
34762
34922
  app67.get("/", requireAdminSession, async (c) => {
34763
34923
  const accountId = getAccountIdForSession(c.var.cacheKey);
34764
34924
  if (!accountId) {
34765
- console.error(`${TAG56} op=destinations auth-rejected reason="no account for session"`);
34925
+ console.error(`${TAG58} op=destinations auth-rejected reason="no account for session"`);
34766
34926
  return c.json({ error: "Account not found for session" }, 401);
34767
34927
  }
34768
34928
  let houseAccountId = null;
@@ -34770,7 +34930,7 @@ app67.get("/", requireAdminSession, async (c) => {
34770
34930
  houseAccountId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
34771
34931
  } catch (err) {
34772
34932
  const message = err instanceof Error ? err.message : String(err);
34773
- console.error(`${TAG56} op=destinations account=${accountId.slice(0, 8)} outcome=house-unresolved reason="${message}"`);
34933
+ console.error(`${TAG58} op=destinations account=${accountId.slice(0, 8)} outcome=house-unresolved reason="${message}"`);
34774
34934
  }
34775
34935
  const destinations = listDispatchDestinations({ accountsDir: ACCOUNTS_DIR, houseAccountId, accountId });
34776
34936
  const houseDir = houseAccountId === null ? null : resolve43(ACCOUNTS_DIR, houseAccountId);
@@ -34821,7 +34981,7 @@ app67.get("/", requireAdminSession, async (c) => {
34821
34981
  const scopes = [...byScope.keys()];
34822
34982
  const nameScope = scopes.length === 0 ? "none" : scopes.every((s) => s === houseAccountId) ? "house" : scopes.some((s) => s === houseAccountId) ? "mixed" : "account";
34823
34983
  console.log(
34824
- `${TAG56} op=destinations account=${accountId.slice(0, 8)} count=${destinations.length} named=${named} unnamed=${destinations.length - named} nameScope=${nameScope}` + (houseAccountId === null ? " outcome=house-unresolved" : "") + (namesUnresolved === null ? "" : ` outcome=names-unresolved reason="${namesUnresolved}"`)
34984
+ `${TAG58} op=destinations account=${accountId.slice(0, 8)} count=${destinations.length} named=${named} unnamed=${destinations.length - named} nameScope=${nameScope}` + (houseAccountId === null ? " outcome=house-unresolved" : "") + (namesUnresolved === null ? "" : ` outcome=names-unresolved reason="${namesUnresolved}"`)
34825
34985
  );
34826
34986
  return c.json({ destinations });
34827
34987
  });
@@ -34830,7 +34990,7 @@ var dispatch_destinations_default = app67;
34830
34990
  // server/routes/admin/activity.ts
34831
34991
  import { readdirSync as readdirSync30 } from "fs";
34832
34992
  var app68 = new Hono();
34833
- var TAG57 = "[activity]";
34993
+ var TAG59 = "[activity]";
34834
34994
  function resolveHouseAccountId2(accounts) {
34835
34995
  const houses = accounts.filter((a) => a.config.role === "house");
34836
34996
  if (houses.length === 1) return { accountId: houses[0].accountId, reason: "house" };
@@ -34859,19 +35019,19 @@ app68.get("/", requireAdminSession, async (c) => {
34859
35019
  const house = resolveHouseAccountId2(valid);
34860
35020
  const isHouse = caller2 !== null && house.accountId !== null && caller2 === house.accountId;
34861
35021
  console.log(
34862
- `${TAG57} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
35022
+ `${TAG59} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
34863
35023
  );
34864
35024
  if (!isHouse) {
34865
35025
  const reason = house.accountId === null ? house.reason : "not-house";
34866
35026
  console.error(
34867
- `${TAG57} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
35027
+ `${TAG59} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
34868
35028
  );
34869
35029
  return c.json({ error: "house-only" }, 403);
34870
35030
  }
34871
- console.log(`${TAG57} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
35031
+ console.log(`${TAG59} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
34872
35032
  const onDisk = countAccountDirsOnDisk();
34873
35033
  console.log(
34874
- `${TAG57} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
35034
+ `${TAG59} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
34875
35035
  );
34876
35036
  const start = Date.now();
34877
35037
  let res;
@@ -34887,17 +35047,17 @@ app68.get("/", requireAdminSession, async (c) => {
34887
35047
  });
34888
35048
  } catch (err) {
34889
35049
  console.error(
34890
- `${TAG57} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
35050
+ `${TAG59} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
34891
35051
  );
34892
35052
  return c.json({ error: "manager-unreachable" }, 502);
34893
35053
  }
34894
35054
  if (res.status !== 200) {
34895
- console.error(`${TAG57} op=manager-fail req=${req} reason=status status=${res.status}`);
35055
+ console.error(`${TAG59} op=manager-fail req=${req} reason=status status=${res.status}`);
34896
35056
  return c.json({ error: `manager-status-${res.status}` }, 502);
34897
35057
  }
34898
35058
  const body = await res.json().catch(() => null);
34899
35059
  if (!body || !Array.isArray(body.rows)) {
34900
- console.error(`${TAG57} op=manager-fail req=${req} reason=bad-json`);
35060
+ console.error(`${TAG59} op=manager-fail req=${req} reason=bad-json`);
34901
35061
  return c.json({ error: "manager-bad-json" }, 502);
34902
35062
  }
34903
35063
  const rows = body.rows;
@@ -34908,10 +35068,10 @@ app68.get("/", requireAdminSession, async (c) => {
34908
35068
  const ageNull = rows.filter((r) => r.ageMs === null).length;
34909
35069
  const sidecarNull = rows.filter((r) => r.sidecarMissing).length;
34910
35070
  console.log(
34911
- `${TAG57} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
35071
+ `${TAG59} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
34912
35072
  );
34913
35073
  console.log(
34914
- `${TAG57} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
35074
+ `${TAG59} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
34915
35075
  );
34916
35076
  const names = {};
34917
35077
  await Promise.all(
@@ -34930,7 +35090,7 @@ app68.get("/", requireAdminSession, async (c) => {
34930
35090
  return acc;
34931
35091
  }, {});
34932
35092
  console.log(
34933
- `${TAG57} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
35093
+ `${TAG59} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
34934
35094
  );
34935
35095
  return c.json({
34936
35096
  rows,
@@ -35021,7 +35181,7 @@ app69.route("/activity", activity_default);
35021
35181
  var admin_default = app69;
35022
35182
 
35023
35183
  // server/routes/access/verify-token.ts
35024
- var TAG58 = "[access-verify]";
35184
+ var TAG60 = "[access-verify]";
35025
35185
  var MINT_TAG = "[access-session-mint]";
35026
35186
  var COOKIE_NAME = "__access_session";
35027
35187
  var app70 = new Hono();
@@ -35040,39 +35200,39 @@ app70.post("/", async (c) => {
35040
35200
  }
35041
35201
  const rateMsg = checkAccessRateLimit(ip, agentSlug);
35042
35202
  if (rateMsg) {
35043
- console.error(`${TAG58} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
35203
+ console.error(`${TAG60} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
35044
35204
  return c.json({ error: rateMsg }, 429);
35045
35205
  }
35046
35206
  const grant = await findGrantByMagicToken(token);
35047
35207
  if (!grant) {
35048
35208
  recordAccessFailedAttempt(ip, agentSlug);
35049
- console.error(`${TAG58} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
35209
+ console.error(`${TAG60} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
35050
35210
  return c.json({ error: "invalid-or-expired-link" }, 401);
35051
35211
  }
35052
35212
  if (grant.agentSlug !== agentSlug) {
35053
35213
  recordAccessFailedAttempt(ip, agentSlug);
35054
35214
  console.error(
35055
- `${TAG58} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
35215
+ `${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
35056
35216
  );
35057
35217
  return c.json({ error: "invalid-or-expired-link" }, 401);
35058
35218
  }
35059
35219
  if (grant.status === "expired" || grant.status === "revoked") {
35060
35220
  recordAccessFailedAttempt(ip, agentSlug);
35061
35221
  console.error(
35062
- `${TAG58} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
35222
+ `${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
35063
35223
  );
35064
35224
  return c.json({ error: "access-no-longer-valid" }, 401);
35065
35225
  }
35066
35226
  if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
35067
35227
  recordAccessFailedAttempt(ip, agentSlug);
35068
35228
  console.error(
35069
- `${TAG58} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
35229
+ `${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
35070
35230
  );
35071
35231
  return c.json({ error: "access-no-longer-valid" }, 401);
35072
35232
  }
35073
35233
  if (!grant.sliceToken) {
35074
35234
  console.error(
35075
- `${TAG58} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
35235
+ `${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
35076
35236
  );
35077
35237
  return c.json({ error: "grant-misconfigured" }, 500);
35078
35238
  }
@@ -35088,12 +35248,12 @@ app70.post("/", async (c) => {
35088
35248
  await consumeMagicTokenAndActivate(grant.grantId);
35089
35249
  } catch (err) {
35090
35250
  console.error(
35091
- `${TAG58} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
35251
+ `${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
35092
35252
  );
35093
35253
  return c.json({ error: "verification-failed" }, 500);
35094
35254
  }
35095
35255
  clearAccessRateLimit(ip, agentSlug);
35096
- console.log(`${TAG58} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
35256
+ console.log(`${TAG60} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
35097
35257
  console.log(
35098
35258
  `${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
35099
35259
  );
@@ -35169,7 +35329,7 @@ async function sendMagicLinkEmail(payload) {
35169
35329
  }
35170
35330
 
35171
35331
  // server/routes/access/request-magic-link.ts
35172
- var TAG59 = "[access-request-link]";
35332
+ var TAG61 = "[access-request-link]";
35173
35333
  var app71 = new Hono();
35174
35334
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
35175
35335
  app71.post("/", async (c) => {
@@ -35186,18 +35346,18 @@ app71.post("/", async (c) => {
35186
35346
  }
35187
35347
  const rateMsg = checkRequestLinkRateLimit(contactValue);
35188
35348
  if (rateMsg) {
35189
- console.error(`${TAG59} contactValue=${maskContact(contactValue)} result=rate-limited`);
35349
+ console.error(`${TAG61} contactValue=${maskContact(contactValue)} result=rate-limited`);
35190
35350
  return c.json({ error: rateMsg }, 429);
35191
35351
  }
35192
35352
  recordRequestLinkAttempt(contactValue);
35193
35353
  const accountId = process.env.ACCOUNT_ID ?? "";
35194
35354
  if (!accountId) {
35195
- console.error(`${TAG59} contactValue=${maskContact(contactValue)} result=no-account-id`);
35355
+ console.error(`${TAG61} contactValue=${maskContact(contactValue)} result=no-account-id`);
35196
35356
  return c.json({ message: VISITOR_MESSAGE }, 200);
35197
35357
  }
35198
35358
  const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
35199
35359
  if (!grant) {
35200
- console.log(`${TAG59} contactValue=${maskContact(contactValue)} result=notfound`);
35360
+ console.log(`${TAG61} contactValue=${maskContact(contactValue)} result=notfound`);
35201
35361
  return c.json({ message: VISITOR_MESSAGE }, 200);
35202
35362
  }
35203
35363
  let token;
@@ -35205,7 +35365,7 @@ app71.post("/", async (c) => {
35205
35365
  token = await generateNewMagicToken(grant.grantId);
35206
35366
  } catch (err) {
35207
35367
  console.error(
35208
- `${TAG59} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
35368
+ `${TAG61} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
35209
35369
  );
35210
35370
  return c.json({ message: VISITOR_MESSAGE }, 200);
35211
35371
  }
@@ -35237,12 +35397,12 @@ app71.post("/", async (c) => {
35237
35397
  });
35238
35398
  if (!sendResult.ok) {
35239
35399
  console.error(
35240
- `${TAG59} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
35400
+ `${TAG61} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
35241
35401
  );
35242
35402
  return c.json({ message: VISITOR_MESSAGE }, 200);
35243
35403
  }
35244
35404
  console.log(
35245
- `${TAG59} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
35405
+ `${TAG61} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
35246
35406
  );
35247
35407
  return c.json({ message: VISITOR_MESSAGE }, 200);
35248
35408
  });
@@ -36252,7 +36412,7 @@ import { stat as stat8, readFile as readFile12, realpath } from "fs/promises";
36252
36412
  import { join as join62, resolve as resolve47, sep as sep11 } from "path";
36253
36413
  import { Readable as Readable3 } from "stream";
36254
36414
  var app79 = new Hono();
36255
- var TAG60 = "[portal-fetch]";
36415
+ var TAG62 = "[portal-fetch]";
36256
36416
  async function verifySignature(secret, accountId, relPath, expiresAtMs, signature, nowMs) {
36257
36417
  if (!secret || !signature) return false;
36258
36418
  if (!Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return false;
@@ -36307,14 +36467,14 @@ async function readAccountSecret(accountId) {
36307
36467
  try {
36308
36468
  text = await readFile12(path, "utf8");
36309
36469
  } catch {
36310
- console.error(`${TAG60} op=no-secret account="${accountId}" path="${path}"`);
36470
+ console.error(`${TAG62} op=no-secret account="${accountId}" path="${path}"`);
36311
36471
  return "";
36312
36472
  }
36313
36473
  for (const line of text.split("\n")) {
36314
36474
  const m = line.match(/^PORTAL_FETCH_SECRET=(.*)$/);
36315
36475
  if (m) return m[1].trim();
36316
36476
  }
36317
- console.error(`${TAG60} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
36477
+ console.error(`${TAG62} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
36318
36478
  return "";
36319
36479
  }
36320
36480
  function isValidAccountId2(value) {
@@ -36374,16 +36534,16 @@ async function handle(c, headOnly) {
36374
36534
  const sig = c.req.query("sig") ?? "";
36375
36535
  const owner = c.req.query("owner") ?? "";
36376
36536
  console.log(
36377
- `${TAG60} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
36537
+ `${TAG62} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
36378
36538
  );
36379
36539
  if (!isValidAccountId2(accountId)) {
36380
- console.error(`${TAG60} op=denied account=${q(accountId)} reason=account-id`);
36540
+ console.error(`${TAG62} op=denied account=${q(accountId)} reason=account-id`);
36381
36541
  return c.json({ ok: false, error: "denied" }, 401);
36382
36542
  }
36383
36543
  const secret = await readAccountSecret(accountId);
36384
36544
  const verified = owner ? await verifyOwnUploadSignature(secret, accountId, owner, relPath, exp, sig, Date.now()) : await verifySignature(secret, accountId, relPath, exp, sig, Date.now());
36385
36545
  if (!verified) {
36386
- console.error(`${TAG60} op=denied account=${q(accountId)} reason=secret`);
36546
+ console.error(`${TAG62} op=denied account=${q(accountId)} reason=secret`);
36387
36547
  return c.json({ ok: false, error: "denied" }, 401);
36388
36548
  }
36389
36549
  const target = await resolveFetchTarget(
@@ -36393,14 +36553,14 @@ async function handle(c, headOnly) {
36393
36553
  );
36394
36554
  if (!target.ok) {
36395
36555
  const op = target.reason === "enoent" ? "miss" : "denied";
36396
- console.error(`${TAG60} op=${op} account=${accountId} reason=${target.reason}`);
36556
+ console.error(`${TAG62} op=${op} account=${accountId} reason=${target.reason}`);
36397
36557
  return c.json({ ok: false, error: "not found" }, 404);
36398
36558
  }
36399
36559
  if (headOnly) {
36400
- console.log(`${TAG60} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
36560
+ console.log(`${TAG62} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
36401
36561
  return c.body(null, 200);
36402
36562
  }
36403
- console.log(`${TAG60} op=served account=${accountId} bytes=${target.sizeBytes}`);
36563
+ console.log(`${TAG62} op=served account=${accountId} bytes=${target.sizeBytes}`);
36404
36564
  return new Response(Readable3.toWeb(createReadStream3(target.absolute)), {
36405
36565
  status: 200,
36406
36566
  headers: {
@@ -36419,7 +36579,7 @@ app79.on("HEAD", "/fetch", (c) => handle(c, true));
36419
36579
  var portal_fetch_default = app79;
36420
36580
 
36421
36581
  // app/lib/timeentry-census.ts
36422
- var TAG61 = "[timeentry-census]";
36582
+ var TAG63 = "[timeentry-census]";
36423
36583
  function reconcileTimeEntries(rows, now, horizonMs) {
36424
36584
  const openEntries = rows.openEntries.length;
36425
36585
  let oldestOpenAgeMs = 0;
@@ -36459,12 +36619,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
36459
36619
  sumAdjustments: toNum(r.get("sumAdjustments"))
36460
36620
  }));
36461
36621
  const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
36462
- const line = `${TAG61} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
36622
+ const line = `${TAG63} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
36463
36623
  if (finding.alarm) console.error(`${line} alarm=true`);
36464
36624
  else console.log(line);
36465
36625
  return finding;
36466
36626
  } catch (err) {
36467
- console.error(`${TAG61} error="${err instanceof Error ? err.message : String(err)}"`);
36627
+ console.error(`${TAG63} error="${err instanceof Error ? err.message : String(err)}"`);
36468
36628
  return null;
36469
36629
  }
36470
36630
  }
@@ -36478,13 +36638,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
36478
36638
  try {
36479
36639
  session = openSession();
36480
36640
  } catch (err) {
36481
- console.error(`${TAG61} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
36641
+ console.error(`${TAG63} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
36482
36642
  return;
36483
36643
  }
36484
36644
  try {
36485
36645
  await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
36486
36646
  } catch (err) {
36487
- console.error(`${TAG61} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
36647
+ console.error(`${TAG63} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
36488
36648
  } finally {
36489
36649
  try {
36490
36650
  await session.close();
@@ -36545,7 +36705,7 @@ function formatCensusLine(f) {
36545
36705
  }
36546
36706
 
36547
36707
  // app/lib/ledger-census.ts
36548
- var TAG62 = "[ledger-census]";
36708
+ var TAG64 = "[ledger-census]";
36549
36709
  var DAY_MS = 864e5;
36550
36710
  function countWriteRejects24h(logDir, now) {
36551
36711
  let entries2;
@@ -36621,7 +36781,7 @@ async function runLedgerCensusOnce(session, now) {
36621
36781
  else console.log(line);
36622
36782
  return finding;
36623
36783
  } catch (err) {
36624
- console.error(`${TAG62} error="${err instanceof Error ? err.message : String(err)}"`);
36784
+ console.error(`${TAG64} error="${err instanceof Error ? err.message : String(err)}"`);
36625
36785
  return null;
36626
36786
  }
36627
36787
  }
@@ -36634,7 +36794,7 @@ function startLedgerCensus(openSession, opts = {}) {
36634
36794
  session = openSession();
36635
36795
  } catch (err) {
36636
36796
  console.error(
36637
- `${TAG62} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
36797
+ `${TAG64} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
36638
36798
  );
36639
36799
  return;
36640
36800
  }
@@ -36642,7 +36802,7 @@ function startLedgerCensus(openSession, opts = {}) {
36642
36802
  await runLedgerCensusOnce(session, Date.now());
36643
36803
  } catch (err) {
36644
36804
  console.error(
36645
- `${TAG62} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
36805
+ `${TAG64} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
36646
36806
  );
36647
36807
  } finally {
36648
36808
  try {
@@ -36987,7 +37147,7 @@ function startDispatchTgCensus(getSession3, intervalMs = FIFTEEN_MIN_MS3) {
36987
37147
  }
36988
37148
 
36989
37149
  // app/lib/conversation-audit.ts
36990
- var TAG63 = "[conversation-audit]";
37150
+ var TAG65 = "[conversation-audit]";
36991
37151
  async function runConversationAudit() {
36992
37152
  const session = getSession();
36993
37153
  try {
@@ -37024,12 +37184,12 @@ async function runConversationAudit() {
37024
37184
  multiAnchored: Number(multiRec?.get("multiAnchored") ?? 0)
37025
37185
  };
37026
37186
  console.error(
37027
- `${TAG63} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
37187
+ `${TAG65} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
37028
37188
  );
37029
37189
  return result;
37030
37190
  } catch (err) {
37031
37191
  const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
37032
- console.error(`${TAG63} op=failed reason=${reason}`);
37192
+ console.error(`${TAG65} op=failed reason=${reason}`);
37033
37193
  return null;
37034
37194
  } finally {
37035
37195
  await session.close();
@@ -37157,7 +37317,7 @@ function startGraphHealthTimer() {
37157
37317
  import { existsSync as existsSync54, statSync as statSync29, readdirSync as readdirSync32 } from "fs";
37158
37318
  import { join as join65 } from "path";
37159
37319
  var import_dist16 = __toESM(require_dist(), 1);
37160
- var TAG64 = "[shared-census]";
37320
+ var TAG66 = "[shared-census]";
37161
37321
  var WIRED_SURFACES = 3;
37162
37322
  function countFiles(dir) {
37163
37323
  let n = 0;
@@ -37185,8 +37345,8 @@ function runSharedFolderCensus(dataRoot = DATA_ROOT) {
37185
37345
  }
37186
37346
  }
37187
37347
  const files = isDir ? countFiles(root) : 0;
37188
- console.error(`${TAG64} op=root exists=${exists} isDir=${isDir} files=${files}`);
37189
- console.error(`${TAG64} op=wiring surfaces=${WIRED_SURFACES}/3`);
37348
+ console.error(`${TAG66} op=root exists=${exists} isDir=${isDir} files=${files}`);
37349
+ console.error(`${TAG66} op=wiring surfaces=${WIRED_SURFACES}/3`);
37190
37350
  return `shared root ${exists ? "present" : "ABSENT"}, ${files} file(s)`;
37191
37351
  }
37192
37352
  function startSharedFolderCensus() {
@@ -37202,7 +37362,7 @@ function startSharedFolderCensus() {
37202
37362
  import { readdirSync as readdirSync33, readFileSync as readFileSync57 } from "fs";
37203
37363
  import { homedir as homedir4 } from "os";
37204
37364
  import { join as join66 } from "path";
37205
- var TAG65 = "[claude-auth]";
37365
+ var TAG67 = "[claude-auth]";
37206
37366
  function refreshTokenLength(raw) {
37207
37367
  let data;
37208
37368
  try {
@@ -37246,7 +37406,7 @@ function runCredRefreshCensus(home = homedir4()) {
37246
37406
  const blank = rows.filter(isBlank).length;
37247
37407
  const detail = rows.map((r) => `${r.brand}:${r.refreshTokenLen === null ? "unreadable" : r.refreshTokenLen}`).join(",");
37248
37408
  console.log(
37249
- `${TAG65} op=cred-refresh-census result=${censusResult(rows)} brands=${rows.length} blank=${blank} detail=${detail}`
37409
+ `${TAG67} op=cred-refresh-census result=${censusResult(rows)} brands=${rows.length} blank=${blank} detail=${detail}`
37250
37410
  );
37251
37411
  return `${rows.length} brand(s), ${blank} blank`;
37252
37412
  }
@@ -39745,6 +39905,16 @@ var WebchatGateway = class _WebchatGateway {
39745
39905
  clearDeliveryFailure(key2) {
39746
39906
  this.deliveryFailures.delete(key2);
39747
39907
  }
39908
+ /** Task 2439 — mark a key undelivered from OUTSIDE the drain path. Every other
39909
+ * writer above fires because a message the hub already holds could not be
39910
+ * delivered. The send route's deferred continuation is the one case where no
39911
+ * message ever reached the hub: it dies before handleInbound runs, so nothing
39912
+ * is queued, nothing can go stale, and no drain can fail. Without this the
39913
+ * client's pending window (Task 2465 reads exactly this marker) never gets a
39914
+ * verdict and the composer stays disabled until the page is reloaded. */
39915
+ markDeliveryFailure(key2, messageId) {
39916
+ this.deliveryFailures.set(key2, { messageId, at: Date.now() });
39917
+ }
39748
39918
  /** Task 2465 — record which session a conversation key's child is running.
39749
39919
  * Public so the audit below can be driven directly in tests without standing
39750
39920
  * up the channel-server HTTP surface; production writes come from runSpawn and
@@ -40437,14 +40607,14 @@ function makeFileDelivery(opts) {
40437
40607
  }
40438
40608
 
40439
40609
  // app/lib/webchat/file-delivery.ts
40440
- var TAG66 = "[webchat-adaptor]";
40610
+ var TAG68 = "[webchat-adaptor]";
40441
40611
  function platformRoot2() {
40442
40612
  return process.env.MAXY_PLATFORM_ROOT || "";
40443
40613
  }
40444
40614
  function makeWebchatSendFile(entry3) {
40445
40615
  return async (filePath) => {
40446
40616
  if (!entry3.accountId) {
40447
- console.error(`${TAG66} file-delivery reject reason=no-account sender=${entry3.senderId}`);
40617
+ console.error(`${TAG68} file-delivery reject reason=no-account sender=${entry3.senderId}`);
40448
40618
  return { ok: false, error: "no-account" };
40449
40619
  }
40450
40620
  const accountDir = resolve50(platformRoot2(), "..", "data/accounts", entry3.accountId);
@@ -40452,14 +40622,14 @@ function makeWebchatSendFile(entry3) {
40452
40622
  const resolved = realpathSync9(filePath);
40453
40623
  const accountResolved = realpathSync9(accountDir);
40454
40624
  if (!resolved.startsWith(accountResolved + "/")) {
40455
- console.error(`${TAG66} file-delivery reject reason=outside_account_directory sender=${entry3.senderId}`);
40625
+ console.error(`${TAG68} file-delivery reject reason=outside_account_directory sender=${entry3.senderId}`);
40456
40626
  return { ok: false, error: "outside-account" };
40457
40627
  }
40458
40628
  return { ok: true };
40459
40629
  } catch (err) {
40460
40630
  const code = err.code;
40461
40631
  console.error(
40462
- `${TAG66} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry3.senderId}`
40632
+ `${TAG68} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry3.senderId}`
40463
40633
  );
40464
40634
  return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
40465
40635
  }
@@ -40468,7 +40638,7 @@ function makeWebchatSendFile(entry3) {
40468
40638
  function makeWebchatFileDelivery(entry3) {
40469
40639
  return makeFileDelivery({
40470
40640
  entry: entry3,
40471
- tag: TAG66,
40641
+ tag: TAG68,
40472
40642
  channel: "webchat",
40473
40643
  sendFile: makeWebchatSendFile(entry3),
40474
40644
  deferUntilVerdict: true
@@ -40547,7 +40717,7 @@ function buildPublicWebchatSpawnRequest(input) {
40547
40717
  }
40548
40718
 
40549
40719
  // app/lib/whatsapp/inbound/file-delivery-bridge.ts
40550
- var TAG67 = "[whatsapp-adaptor]";
40720
+ var TAG69 = "[whatsapp-adaptor]";
40551
40721
  var SEND_USER_FILE2 = "SendUserFile";
40552
40722
  var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
40553
40723
  function platformRoot3() {
@@ -40565,7 +40735,7 @@ function makeWhatsAppSendFile(entry3, maxyAccountId) {
40565
40735
  });
40566
40736
  if (result.ok) return { ok: true };
40567
40737
  console.error(
40568
- `${TAG67} file-delivery reject reason=send-failed sender=${entry3.senderId} status=${result.status} message=${result.error}`
40738
+ `${TAG69} file-delivery reject reason=send-failed sender=${entry3.senderId} status=${result.status} message=${result.error}`
40569
40739
  );
40570
40740
  return { ok: false, error: result.error };
40571
40741
  };
@@ -40573,7 +40743,7 @@ function makeWhatsAppSendFile(entry3, maxyAccountId) {
40573
40743
  function makeWhatsAppFileDelivery(entry3, maxyAccountId) {
40574
40744
  const shared = makeFileDelivery({
40575
40745
  entry: entry3,
40576
- tag: TAG67,
40746
+ tag: TAG69,
40577
40747
  channel: "whatsapp",
40578
40748
  sendFile: makeWhatsAppSendFile(entry3, maxyAccountId)
40579
40749
  });
@@ -40608,7 +40778,7 @@ function makeWhatsAppFileDelivery(entry3, maxyAccountId) {
40608
40778
  if (!delivered) {
40609
40779
  const fileField = call2.filePath !== void 0 ? ` file=${call2.filePath}` : "";
40610
40780
  console.error(
40611
- `${TAG67} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
40781
+ `${TAG69} file-delivery-unreconciled sender=${entry3.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
40612
40782
  );
40613
40783
  }
40614
40784
  }
@@ -40774,7 +40944,7 @@ function whatsappDoorLabel(doorId) {
40774
40944
  }
40775
40945
 
40776
40946
  // app/lib/channel-delivery/refusal-notice.ts
40777
- var TAG68 = "[channel-delivery]";
40947
+ var TAG70 = "[channel-delivery]";
40778
40948
  var notified = /* @__PURE__ */ new Set();
40779
40949
  function refusalNoticeText(reason) {
40780
40950
  return reason === "claude-auth-dead" ? "Your message arrived but no assistant could be started: the Claude sign-in on this install is not active. An operator has to sign in again; send this again once they have." : `Your message arrived but no assistant could be started (${reason}). Nothing was lost; try again shortly.`;
@@ -40783,19 +40953,19 @@ async function sendRefusalNotice(input) {
40783
40953
  if (notified.has(input.doorId)) return;
40784
40954
  const fields = `channel=${input.channel} sender=${input.sender} reason=${input.reason}`;
40785
40955
  if (!input.send) {
40786
- console.error(`${TAG68} op=refusal-notice-failed ${fields} error=no-target`);
40956
+ console.error(`${TAG70} op=refusal-notice-failed ${fields} error=no-target`);
40787
40957
  return;
40788
40958
  }
40789
40959
  try {
40790
40960
  await input.send(guardOutbound(input.sender, refusalNoticeText(input.reason)));
40791
40961
  } catch (e) {
40792
40962
  console.error(
40793
- `${TAG68} op=refusal-notice-failed ${fields} error=${e instanceof Error ? e.message : String(e)}`
40963
+ `${TAG70} op=refusal-notice-failed ${fields} error=${e instanceof Error ? e.message : String(e)}`
40794
40964
  );
40795
40965
  return;
40796
40966
  }
40797
40967
  notified.add(input.doorId);
40798
- console.error(`${TAG68} op=refusal-notice ${fields} status=${input.status}`);
40968
+ console.error(`${TAG70} op=refusal-notice ${fields} status=${input.status}`);
40799
40969
  }
40800
40970
  function clearRefusalNotice(doorId) {
40801
40971
  notified.delete(doorId);
@@ -41455,10 +41625,10 @@ function buildTelegramSpawnRequest(input) {
41455
41625
  }
41456
41626
 
41457
41627
  // server/telegram-ensure-session.ts
41458
- var TAG69 = "[telegram-inbound]";
41628
+ var TAG71 = "[telegram-inbound]";
41459
41629
  function reportReused(botId, channelKey, result) {
41460
41630
  if (!result.reused) return;
41461
- console.error(`${TAG69} op=spawn-reused botId=${botId} key=${channelKey} sessionId=${result.sessionId}`);
41631
+ console.error(`${TAG71} op=spawn-reused botId=${botId} key=${channelKey} sessionId=${result.sessionId}`);
41462
41632
  }
41463
41633
  function buildTelegramEnsureSession(deps) {
41464
41634
  return async (input) => {
@@ -41522,10 +41692,10 @@ function buildTelegramEnsureSession(deps) {
41522
41692
  return;
41523
41693
  }
41524
41694
  console.error(
41525
- `${TAG69} op=telegram-spawn-door botId=${input.botId} role=specialist door=rc specialist=${input.specialist}`
41695
+ `${TAG71} op=telegram-spawn-door botId=${input.botId} role=specialist door=rc specialist=${input.specialist}`
41526
41696
  );
41527
41697
  console.error(
41528
- `${TAG69} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=specialist specialist=${input.specialist}`
41698
+ `${TAG71} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=specialist specialist=${input.specialist}`
41529
41699
  );
41530
41700
  reportReused(input.botId, req.channelKey, result2);
41531
41701
  noteSpawnOk2(input.botId);
@@ -41560,10 +41730,10 @@ function buildTelegramEnsureSession(deps) {
41560
41730
  return;
41561
41731
  }
41562
41732
  console.error(
41563
- `${TAG69} op=telegram-spawn-door botId=${input.botId} role=public door=rc agent=${input.agentSlug}`
41733
+ `${TAG71} op=telegram-spawn-door botId=${input.botId} role=public door=rc agent=${input.agentSlug}`
41564
41734
  );
41565
41735
  console.error(
41566
- `${TAG69} op=spawn botId=${input.botId} sessionId=${result2.sessionId} targetAccountId=${input.accountId} role=public`
41736
+ `${TAG71} op=spawn botId=${input.botId} sessionId=${result2.sessionId} targetAccountId=${input.accountId} role=public`
41567
41737
  );
41568
41738
  reportReused(input.botId, req.channelKey, result2);
41569
41739
  noteSpawnOk2(input.botId);
@@ -41587,7 +41757,7 @@ function buildTelegramEnsureSession(deps) {
41587
41757
  return;
41588
41758
  }
41589
41759
  console.error(
41590
- `${TAG69} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=admin`
41760
+ `${TAG71} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=admin`
41591
41761
  );
41592
41762
  reportReused(input.botId, req.channelKey, result);
41593
41763
  noteSpawnOk2(input.botId);
@@ -41606,7 +41776,7 @@ function buildTelegramEnsureSession(deps) {
41606
41776
  import { realpathSync as realpathSync10 } from "fs";
41607
41777
  import { readFile as readFile15, stat as stat10 } from "fs/promises";
41608
41778
  import { resolve as resolve51, basename as basename18 } from "path";
41609
- var TAG70 = "[telegram:outbound]";
41779
+ var TAG72 = "[telegram:outbound]";
41610
41780
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
41611
41781
  async function sendTelegramDocument(input) {
41612
41782
  const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
@@ -41623,10 +41793,10 @@ async function sendTelegramDocument(input) {
41623
41793
  } catch (err) {
41624
41794
  const code = err.code;
41625
41795
  if (code === "ENOENT") {
41626
- console.error(`${TAG70} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
41796
+ console.error(`${TAG72} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
41627
41797
  return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
41628
41798
  }
41629
- console.error(`${TAG70} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
41799
+ console.error(`${TAG72} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
41630
41800
  return { ok: false, status: 500, error: String(err) };
41631
41801
  }
41632
41802
  let resolvedPath;
@@ -41635,14 +41805,14 @@ async function sendTelegramDocument(input) {
41635
41805
  } catch (err) {
41636
41806
  const code = err.code;
41637
41807
  if (code === "ENOENT") {
41638
- console.error(`${TAG70} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
41808
+ console.error(`${TAG72} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
41639
41809
  return { ok: false, status: 404, error: `File not found: ${filePath}` };
41640
41810
  }
41641
- console.error(`${TAG70} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
41811
+ console.error(`${TAG72} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
41642
41812
  return { ok: false, status: 500, error: String(err) };
41643
41813
  }
41644
41814
  if (!resolvedPath.startsWith(accountResolved + "/")) {
41645
- console.error(`${TAG70} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
41815
+ console.error(`${TAG72} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
41646
41816
  return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
41647
41817
  }
41648
41818
  const fileStat = await stat10(resolvedPath);
@@ -41675,24 +41845,24 @@ async function sendTelegramDocument(input) {
41675
41845
  error = e instanceof Error ? e.message : String(e);
41676
41846
  }
41677
41847
  console.error(
41678
- `${TAG70} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok2}` + (messageId !== void 0 ? ` id=${messageId}` : "")
41848
+ `${TAG72} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok2}` + (messageId !== void 0 ? ` id=${messageId}` : "")
41679
41849
  );
41680
41850
  return ok2 ? { ok: true, messageId } : { ok: false, status: 500, error };
41681
41851
  }
41682
41852
 
41683
41853
  // app/lib/telegram/outbound/file-delivery.ts
41684
- var TAG71 = "[telegram:outbound]";
41854
+ var TAG73 = "[telegram:outbound]";
41685
41855
  function platformRoot4() {
41686
41856
  return process.env.MAXY_PLATFORM_ROOT || "";
41687
41857
  }
41688
41858
  function makeTelegramSendFile(entry3, botToken) {
41689
41859
  return async (filePath, caption) => {
41690
41860
  if (!botToken) {
41691
- console.error(`${TAG71} file-delivery reject reason=no-bot-token sender=${entry3.senderId} role=${entry3.role}`);
41861
+ console.error(`${TAG73} file-delivery reject reason=no-bot-token sender=${entry3.senderId} role=${entry3.role}`);
41692
41862
  return { ok: false, error: "no-bot-token" };
41693
41863
  }
41694
41864
  if (entry3.replyTarget == null) {
41695
- console.error(`${TAG71} file-delivery reject reason=no-reply-target sender=${entry3.senderId} role=${entry3.role}`);
41865
+ console.error(`${TAG73} file-delivery reject reason=no-reply-target sender=${entry3.senderId} role=${entry3.role}`);
41696
41866
  return { ok: false, error: "no-reply-target" };
41697
41867
  }
41698
41868
  const result = await sendTelegramDocument({
@@ -41709,7 +41879,7 @@ function makeTelegramSendFile(entry3, botToken) {
41709
41879
  function makeTelegramFileDelivery(entry3, botToken) {
41710
41880
  return makeFileDelivery({
41711
41881
  entry: entry3,
41712
- tag: TAG71,
41882
+ tag: TAG73,
41713
41883
  channel: "telegram",
41714
41884
  sendFile: makeTelegramSendFile(entry3, botToken)
41715
41885
  });
@@ -42120,7 +42290,7 @@ function adminFanTargets(p) {
42120
42290
 
42121
42291
  // app/lib/channel-pty-bridge/public-session-end-review.ts
42122
42292
  import { randomUUID as randomUUID14 } from "crypto";
42123
- var TAG72 = "[public-session-review]";
42293
+ var TAG74 = "[public-session-review]";
42124
42294
  var CONSUMED_CAP = 500;
42125
42295
  var consumed = /* @__PURE__ */ new Set();
42126
42296
  function consumeOnce(sessionId) {
@@ -42147,7 +42317,7 @@ async function fetchJsonl(sessionId) {
42147
42317
  return await res.text();
42148
42318
  } catch (err) {
42149
42319
  console.error(
42150
- `${TAG72} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
42320
+ `${TAG74} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
42151
42321
  );
42152
42322
  return null;
42153
42323
  }
@@ -42171,7 +42341,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
42171
42341
  const res = await fetch(url);
42172
42342
  if (!res.ok) {
42173
42343
  console.error(
42174
- `${TAG72} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
42344
+ `${TAG74} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
42175
42345
  );
42176
42346
  return [];
42177
42347
  }
@@ -42179,7 +42349,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
42179
42349
  return Array.isArray(body.writes) ? body.writes : [];
42180
42350
  } catch (err) {
42181
42351
  console.error(
42182
- `${TAG72} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
42352
+ `${TAG74} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
42183
42353
  );
42184
42354
  return [];
42185
42355
  }
@@ -42208,7 +42378,7 @@ function composeInitialMessage(input) {
42208
42378
  }
42209
42379
  async function dispatchReviewer(input, initialMessage) {
42210
42380
  const sessionId = randomUUID14();
42211
- console.log(`${TAG72} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
42381
+ console.log(`${TAG74} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
42212
42382
  const spawned = await managerRcSpawn({
42213
42383
  sessionId,
42214
42384
  initialMessage,
@@ -42232,21 +42402,21 @@ async function firePublicSessionEndReview(input) {
42232
42402
  const dispatchedAt = Date.now();
42233
42403
  if (consumed.has(input.sessionId)) {
42234
42404
  console.log(
42235
- `${TAG72} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
42405
+ `${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
42236
42406
  );
42237
42407
  return;
42238
42408
  }
42239
42409
  const jsonl = await fetchJsonl(input.sessionId);
42240
42410
  if (!jsonl) {
42241
42411
  console.log(
42242
- `${TAG72} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
42412
+ `${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
42243
42413
  );
42244
42414
  return;
42245
42415
  }
42246
42416
  const operatorTurns = countOperatorTurns(jsonl);
42247
42417
  if (operatorTurns === 0) {
42248
42418
  console.log(
42249
- `${TAG72} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
42419
+ `${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
42250
42420
  );
42251
42421
  return;
42252
42422
  }
@@ -42260,19 +42430,19 @@ async function firePublicSessionEndReview(input) {
42260
42430
  });
42261
42431
  if (!consumeOnce(input.sessionId)) {
42262
42432
  console.log(
42263
- `${TAG72} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
42433
+ `${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
42264
42434
  );
42265
42435
  return;
42266
42436
  }
42267
42437
  const dispatched = await dispatchReviewer(input, initialMessage);
42268
42438
  if (!dispatched.ok) {
42269
42439
  console.error(
42270
- `${TAG72} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
42440
+ `${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
42271
42441
  );
42272
42442
  return;
42273
42443
  }
42274
42444
  console.log(
42275
- `${TAG72} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
42445
+ `${TAG74} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
42276
42446
  );
42277
42447
  }
42278
42448
 
@@ -42541,10 +42711,10 @@ function* walkTelegramSidecars() {
42541
42711
  }
42542
42712
 
42543
42713
  // server/telegram-group-census.ts
42544
- var TAG73 = "[telegram-audit]";
42714
+ var TAG75 = "[telegram-audit]";
42545
42715
  var PRESENT_STATUSES = /* @__PURE__ */ new Set(["member", "administrator", "creator"]);
42546
42716
  function buildGroupCensusLine(c) {
42547
- return `${TAG73} op=group-census bots=${c.bots} groups=${c.groups} present=${c.present} absent=${c.absent} privacyOff=${c.privacyOff}`;
42717
+ return `${TAG75} op=group-census bots=${c.bots} groups=${c.groups} present=${c.present} absent=${c.absent} privacyOff=${c.privacyOff}`;
42548
42718
  }
42549
42719
  async function runTelegramGroupCensus(accounts, deps) {
42550
42720
  const counts = { bots: 0, groups: 0, present: 0, absent: 0, privacyOff: 0 };
@@ -42575,10 +42745,10 @@ async function runTelegramGroupCensus(accounts, deps) {
42575
42745
  }
42576
42746
 
42577
42747
  // server/telegram-channel-census.ts
42578
- var TAG74 = "[telegram-audit]";
42748
+ var TAG76 = "[telegram-audit]";
42579
42749
  var ADMIN_STATUSES = /* @__PURE__ */ new Set(["administrator", "creator"]);
42580
42750
  function buildChannelCensusLine(c) {
42581
- return `${TAG74} op=channel-census bots=${c.bots} channels=${c.channels} admin=${c.admin} notAdmin=${c.notAdmin} noPostRight=${c.noPostRight}`;
42751
+ return `${TAG76} op=channel-census bots=${c.bots} channels=${c.channels} admin=${c.admin} notAdmin=${c.notAdmin} noPostRight=${c.noPostRight}`;
42582
42752
  }
42583
42753
  async function runTelegramChannelCensus(accounts, deps) {
42584
42754
  const counts = { bots: 0, channels: 0, admin: 0, notAdmin: 0, noPostRight: 0 };
@@ -44204,6 +44374,9 @@ app80.route("/api/webchat", createWebchatRoutes({
44204
44374
  // Task 940 — the permission relay's pointer read + verdict write.
44205
44375
  pendingPromptFor: (key2) => webchatGateway.pendingPromptFor(key2),
44206
44376
  deliveryFailureFor: (key2) => webchatGateway.deliveryFailureFor(key2),
44377
+ // Task 2439 — the deferred send continuation's only way to report that a
44378
+ // staged upload will never produce a turn.
44379
+ markDeliveryFailure: (key2, messageId) => webchatGateway.markDeliveryFailure(key2, messageId),
44207
44380
  resolvePermissionVerdict: (key2, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key2, requestId, behavior)
44208
44381
  }));
44209
44382
  app80.route("/api/webchat/greeting", webchat_greeting_default);