@rubytech/create-sitedesk-code 0.1.521 → 0.1.522

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 (255) hide show
  1. package/dist/index.js +17 -3
  2. package/package.json +1 -1
  3. package/payload/platform/lib/account-schema-regions/package-lock.json +12 -0
  4. package/payload/platform/lib/active-rules/package-lock.json +12 -0
  5. package/payload/platform/lib/mcp-lifeline/package-lock.json +12 -0
  6. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +43 -6
  7. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
  8. package/payload/platform/plugins/docs/references/admin-ui.md +10 -0
  9. package/payload/platform/plugins/docs/references/internals.md +4 -0
  10. package/payload/platform/plugins/docs/references/outlook-guide.md +27 -4
  11. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
  12. package/payload/platform/plugins/outlook/PLUGIN.md +9 -1
  13. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.d.ts +2 -0
  14. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.d.ts.map +1 -0
  15. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.js +151 -0
  16. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-resolve.test.js.map +1 -0
  17. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.d.ts +2 -0
  18. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.d.ts.map +1 -0
  19. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.js +151 -0
  20. package/payload/platform/plugins/outlook/mcp/dist/__tests__/delegated-store.test.js.map +1 -0
  21. package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js +38 -4
  22. package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js.map +1 -1
  23. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.d.ts +2 -0
  24. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.d.ts.map +1 -0
  25. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.js +146 -0
  26. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client-prefix-wiring.test.js.map +1 -0
  27. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.d.ts +2 -0
  28. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.d.ts.map +1 -0
  29. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.js +120 -0
  30. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list-delegated.test.js.map +1 -0
  31. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js +8 -8
  32. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js.map +1 -1
  33. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.d.ts +2 -0
  34. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.d.ts.map +1 -0
  35. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.js +27 -0
  36. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-path-prefix.test.js.map +1 -0
  37. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.d.ts +2 -0
  38. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.d.ts.map +1 -0
  39. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.js +70 -0
  40. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mail-only-guard.test.js.map +1 -0
  41. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.d.ts +2 -0
  42. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.d.ts.map +1 -0
  43. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.js +152 -0
  44. package/payload/platform/plugins/outlook/mcp/dist/__tests__/shared-mailbox-add.test.js.map +1 -0
  45. package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.d.ts +57 -0
  46. package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.d.ts.map +1 -0
  47. package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.js +163 -0
  48. package/payload/platform/plugins/outlook/mcp/dist/auth/delegated-store.js.map +1 -0
  49. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts +12 -0
  50. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts.map +1 -1
  51. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js +21 -1
  52. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js.map +1 -1
  53. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts +35 -4
  54. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts.map +1 -1
  55. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js +92 -10
  56. package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js.map +1 -1
  57. package/payload/platform/plugins/outlook/mcp/dist/index.js +106 -3
  58. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
  59. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +49 -0
  60. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -1
  61. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +126 -8
  62. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
  63. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts +13 -0
  64. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts.map +1 -1
  65. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js +9 -0
  66. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js.map +1 -1
  67. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts +42 -8
  68. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts.map +1 -1
  69. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js +59 -19
  70. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js.map +1 -1
  71. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.d.ts +47 -0
  72. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.d.ts.map +1 -0
  73. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.js +67 -0
  74. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-add.js.map +1 -0
  75. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.d.ts +12 -0
  76. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.d.ts.map +1 -0
  77. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.js +18 -0
  78. package/payload/platform/plugins/outlook/mcp/dist/tools/shared-mailbox-remove.js.map +1 -0
  79. package/payload/platform/plugins/outlook/references/auth.md +15 -2
  80. package/payload/platform/plugins/outlook/references/graph-surfaces.md +8 -0
  81. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +21 -1
  82. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  83. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
  84. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  85. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  86. package/payload/server/{chunk-AZLT4LVO.js → chunk-K7CJGZPU.js} +419 -189
  87. package/payload/server/{manager-CQBSUJXR.js → manager-RKL7JZ4Y.js} +3 -1
  88. package/payload/server/public/activity.html +5 -5
  89. package/payload/server/public/agents.html +4 -4
  90. package/payload/server/public/assets/{AdminLoginScreens-Dar_MMJm.js → AdminLoginScreens-zc2_qqh-.js} +1 -1
  91. package/payload/server/public/assets/AdminLoginScreens-zc2_qqh-.js.br +0 -0
  92. package/payload/server/public/assets/AdminLoginScreens-zc2_qqh-.js.gz +0 -0
  93. package/payload/server/public/assets/{AdminShell-CpaI2F_p.js → AdminShell-IGUdTx5q.js} +1 -1
  94. package/payload/server/public/assets/AdminShell-IGUdTx5q.js.br +0 -0
  95. package/payload/server/public/assets/{AdminShell-CpaI2F_p.js.gz → AdminShell-IGUdTx5q.js.gz} +0 -0
  96. package/payload/server/public/assets/{activity-B1rt4GIy.js → activity-DVgO8YuM.js} +1 -1
  97. package/payload/server/public/assets/activity-DVgO8YuM.js.br +0 -0
  98. package/payload/server/public/assets/activity-DVgO8YuM.js.gz +0 -0
  99. package/payload/server/public/assets/admin-xtpM7fgl.js +1 -0
  100. package/payload/server/public/assets/admin-xtpM7fgl.js.br +0 -0
  101. package/payload/server/public/assets/admin-xtpM7fgl.js.gz +0 -0
  102. package/payload/server/public/assets/{agents-BXq8woVf.js → agents-P0nTIxo-.js} +1 -1
  103. package/payload/server/public/assets/agents-P0nTIxo-.js.br +0 -0
  104. package/payload/server/public/assets/agents-P0nTIxo-.js.gz +0 -0
  105. package/payload/server/public/assets/{browser-1QSCPl3X.js → browser-Mw7DY3ft.js} +1 -1
  106. package/payload/server/public/assets/browser-Mw7DY3ft.js.br +0 -0
  107. package/payload/server/public/assets/browser-Mw7DY3ft.js.gz +0 -0
  108. package/payload/server/public/assets/{calendar-D009qWVV.js → calendar-B9gvL_1_.js} +1 -1
  109. package/payload/server/public/assets/calendar-B9gvL_1_.js.br +0 -0
  110. package/payload/server/public/assets/calendar-B9gvL_1_.js.gz +0 -0
  111. package/payload/server/public/assets/chat-DBGqh4wg.js +1 -0
  112. package/payload/server/public/assets/chat-DBGqh4wg.js.br +2 -0
  113. package/payload/server/public/assets/chat-DBGqh4wg.js.gz +0 -0
  114. package/payload/server/public/assets/chevron-left-Bl4vpOM0.js +1 -0
  115. package/payload/server/public/assets/chevron-left-Bl4vpOM0.js.br +0 -0
  116. package/payload/server/public/assets/chevron-right-BExigCnp.js +1 -0
  117. package/payload/server/public/assets/chevron-right-BExigCnp.js.br +0 -0
  118. package/payload/server/public/assets/clock-D8TJvgJC.js +1 -0
  119. package/payload/server/public/assets/clock-D8TJvgJC.js.br +0 -0
  120. package/payload/server/public/assets/data-HfFSxaC2.js +1 -0
  121. package/payload/server/public/assets/data-HfFSxaC2.js.br +0 -0
  122. package/payload/server/public/assets/data-HfFSxaC2.js.gz +0 -0
  123. package/payload/server/public/assets/{file-text-DwGAfCsd.js → file-text-dYBnXNEX.js} +1 -1
  124. package/payload/server/public/assets/file-text-dYBnXNEX.js.br +0 -0
  125. package/payload/server/public/assets/file-text-dYBnXNEX.js.gz +0 -0
  126. package/payload/server/public/assets/{graph-D-DGlfhW.js → graph-CDyzd1Et.js} +1 -1
  127. package/payload/server/public/assets/graph-CDyzd1Et.js.br +0 -0
  128. package/payload/server/public/assets/graph-CDyzd1Et.js.gz +0 -0
  129. package/payload/server/public/assets/{graph-labels-BbX3fXzl.js → graph-labels-D1LkKiJr.js} +1 -1
  130. package/payload/server/public/assets/graph-labels-D1LkKiJr.js.br +0 -0
  131. package/payload/server/public/assets/graph-labels-D1LkKiJr.js.gz +0 -0
  132. package/payload/server/public/assets/{maximize-2-C_-KapxH.js → maximize-2-M-iSaznd.js} +1 -1
  133. package/payload/server/public/assets/maximize-2-M-iSaznd.js.br +0 -0
  134. package/payload/server/public/assets/maximize-2-M-iSaznd.js.gz +0 -0
  135. package/payload/server/public/assets/{operator-CFrZVcv6.js → operator-9jfCv1Fg.js} +1 -1
  136. package/payload/server/public/assets/operator-9jfCv1Fg.js.br +0 -0
  137. package/payload/server/public/assets/operator-9jfCv1Fg.js.gz +0 -0
  138. package/payload/server/public/assets/{page-E74MYB18.js → page-CZ-73FAk.js} +1 -1
  139. package/payload/server/public/assets/page-CZ-73FAk.js.br +0 -0
  140. package/payload/server/public/assets/page-CZ-73FAk.js.gz +0 -0
  141. package/payload/server/public/assets/{page-CHt62f1_.js → page-CjwSt7kx.js} +1 -1
  142. package/payload/server/public/assets/page-CjwSt7kx.js.br +0 -0
  143. package/payload/server/public/assets/page-CjwSt7kx.js.gz +0 -0
  144. package/payload/server/public/assets/{public-CI6K1sNW.js → public-CN-ltC8x.js} +1 -1
  145. package/payload/server/public/assets/public-CN-ltC8x.js.br +0 -0
  146. package/payload/server/public/assets/public-CN-ltC8x.js.gz +0 -0
  147. package/payload/server/public/assets/{rotate-ccw-PWu_QGrD.js → rotate-ccw-Buopsc22.js} +1 -1
  148. package/payload/server/public/assets/rotate-ccw-Buopsc22.js.br +0 -0
  149. package/payload/server/public/assets/rotate-ccw-Buopsc22.js.gz +0 -0
  150. package/payload/server/public/assets/{routines-Cp3_XS7S.js → routines-C-yr8ddT.js} +1 -1
  151. package/payload/server/public/assets/routines-C-yr8ddT.js.br +0 -0
  152. package/payload/server/public/assets/routines-C-yr8ddT.js.gz +0 -0
  153. package/payload/server/public/assets/{skills-g8HvunPA.js → skills-DiiuVzDK.js} +1 -1
  154. package/payload/server/public/assets/skills-DiiuVzDK.js.br +0 -0
  155. package/payload/server/public/assets/skills-DiiuVzDK.js.gz +0 -0
  156. package/payload/server/public/assets/tasks-CnHIfn2_.js +1 -0
  157. package/payload/server/public/assets/tasks-CnHIfn2_.js.br +0 -0
  158. package/payload/server/public/assets/tasks-CnHIfn2_.js.gz +0 -0
  159. package/payload/server/public/assets/{time-entry-format-BXWuQ6Sw.js → time-entry-format-BBokCF-D.js} +1 -1
  160. package/payload/server/public/assets/time-entry-format-BBokCF-D.js.br +0 -0
  161. package/payload/server/public/assets/time-entry-format-BBokCF-D.js.gz +0 -0
  162. package/payload/server/public/assets/{triangle-alert-BNshRC13.js → triangle-alert-C_AcpTW5.js} +1 -1
  163. package/payload/server/public/assets/triangle-alert-C_AcpTW5.js.br +0 -0
  164. package/payload/server/public/assets/triangle-alert-C_AcpTW5.js.gz +0 -0
  165. package/payload/server/public/assets/{useCopyFeedback-CwTZ9DqH.js → useCopyFeedback-TdimmPVR.js} +1 -1
  166. package/payload/server/public/assets/useCopyFeedback-TdimmPVR.js.br +0 -0
  167. package/payload/server/public/assets/useCopyFeedback-TdimmPVR.js.gz +0 -0
  168. package/payload/server/public/assets/{useSubAccountSwitcher-BuUYMDWl.js → useSubAccountSwitcher-BwHqV55p.js} +1 -1
  169. package/payload/server/public/assets/useSubAccountSwitcher-BwHqV55p.js.br +0 -0
  170. package/payload/server/public/assets/{useSubAccountSwitcher-BuUYMDWl.js.gz → useSubAccountSwitcher-BwHqV55p.js.gz} +0 -0
  171. package/payload/server/public/assets/{useSubAccountSwitcher-dzDnmWq9.css → useSubAccountSwitcher-CsrPYqtm.css} +1 -1
  172. package/payload/server/public/assets/useSubAccountSwitcher-CsrPYqtm.css.br +0 -0
  173. package/payload/server/public/assets/{useSubAccountSwitcher-dzDnmWq9.css.gz → useSubAccountSwitcher-CsrPYqtm.css.gz} +0 -0
  174. package/payload/server/public/assets/{useVoiceRecorder-BGqV5R6u.js → useVoiceRecorder-BT2738ZS.js} +1 -1
  175. package/payload/server/public/assets/useVoiceRecorder-BT2738ZS.js.br +0 -0
  176. package/payload/server/public/assets/useVoiceRecorder-BT2738ZS.js.gz +0 -0
  177. package/payload/server/public/assets/{wrench-DQ045Pyk.js → wrench-B51s5kGA.js} +1 -1
  178. package/payload/server/public/assets/wrench-B51s5kGA.js.br +0 -0
  179. package/payload/server/public/assets/wrench-B51s5kGA.js.gz +0 -0
  180. package/payload/server/public/browser.html +4 -4
  181. package/payload/server/public/calendar.html +7 -7
  182. package/payload/server/public/chat.html +13 -13
  183. package/payload/server/public/data.html +11 -11
  184. package/payload/server/public/graph.html +9 -9
  185. package/payload/server/public/index.html +14 -14
  186. package/payload/server/public/operator.html +14 -14
  187. package/payload/server/public/public.html +13 -13
  188. package/payload/server/public/routines.html +6 -6
  189. package/payload/server/public/skills.html +5 -5
  190. package/payload/server/public/tasks.html +6 -6
  191. package/payload/server/server.js +1006 -606
  192. package/payload/server/public/assets/AdminLoginScreens-Dar_MMJm.js.br +0 -0
  193. package/payload/server/public/assets/AdminLoginScreens-Dar_MMJm.js.gz +0 -0
  194. package/payload/server/public/assets/AdminShell-CpaI2F_p.js.br +0 -0
  195. package/payload/server/public/assets/activity-B1rt4GIy.js.br +0 -0
  196. package/payload/server/public/assets/activity-B1rt4GIy.js.gz +0 -0
  197. package/payload/server/public/assets/admin-DE3lLNje.js +0 -1
  198. package/payload/server/public/assets/admin-DE3lLNje.js.br +0 -0
  199. package/payload/server/public/assets/admin-DE3lLNje.js.gz +0 -0
  200. package/payload/server/public/assets/agents-BXq8woVf.js.br +0 -0
  201. package/payload/server/public/assets/agents-BXq8woVf.js.gz +0 -0
  202. package/payload/server/public/assets/browser-1QSCPl3X.js.br +0 -0
  203. package/payload/server/public/assets/browser-1QSCPl3X.js.gz +0 -0
  204. package/payload/server/public/assets/calendar-D009qWVV.js.br +0 -0
  205. package/payload/server/public/assets/calendar-D009qWVV.js.gz +0 -0
  206. package/payload/server/public/assets/chat-CUg1fTqJ.js +0 -1
  207. package/payload/server/public/assets/chat-CUg1fTqJ.js.br +0 -1
  208. package/payload/server/public/assets/chat-CUg1fTqJ.js.gz +0 -0
  209. package/payload/server/public/assets/chevron-left-C2JEy7uU.js +0 -1
  210. package/payload/server/public/assets/chevron-left-C2JEy7uU.js.br +0 -0
  211. package/payload/server/public/assets/chevron-right-DWa047Ys.js +0 -1
  212. package/payload/server/public/assets/chevron-right-DWa047Ys.js.br +0 -0
  213. package/payload/server/public/assets/clock-C3OqfCnn.js +0 -1
  214. package/payload/server/public/assets/clock-C3OqfCnn.js.br +0 -0
  215. package/payload/server/public/assets/clock-C3OqfCnn.js.gz +0 -0
  216. package/payload/server/public/assets/data-Bu_yCScC.js +0 -1
  217. package/payload/server/public/assets/data-Bu_yCScC.js.br +0 -0
  218. package/payload/server/public/assets/data-Bu_yCScC.js.gz +0 -0
  219. package/payload/server/public/assets/file-text-DwGAfCsd.js.br +0 -0
  220. package/payload/server/public/assets/file-text-DwGAfCsd.js.gz +0 -0
  221. package/payload/server/public/assets/graph-D-DGlfhW.js.br +0 -0
  222. package/payload/server/public/assets/graph-D-DGlfhW.js.gz +0 -0
  223. package/payload/server/public/assets/graph-labels-BbX3fXzl.js.br +0 -0
  224. package/payload/server/public/assets/graph-labels-BbX3fXzl.js.gz +0 -0
  225. package/payload/server/public/assets/maximize-2-C_-KapxH.js.br +0 -0
  226. package/payload/server/public/assets/maximize-2-C_-KapxH.js.gz +0 -0
  227. package/payload/server/public/assets/operator-CFrZVcv6.js.br +0 -0
  228. package/payload/server/public/assets/operator-CFrZVcv6.js.gz +0 -0
  229. package/payload/server/public/assets/page-CHt62f1_.js.br +0 -0
  230. package/payload/server/public/assets/page-CHt62f1_.js.gz +0 -0
  231. package/payload/server/public/assets/page-E74MYB18.js.br +0 -0
  232. package/payload/server/public/assets/page-E74MYB18.js.gz +0 -0
  233. package/payload/server/public/assets/public-CI6K1sNW.js.br +0 -0
  234. package/payload/server/public/assets/public-CI6K1sNW.js.gz +0 -0
  235. package/payload/server/public/assets/rotate-ccw-PWu_QGrD.js.br +0 -0
  236. package/payload/server/public/assets/rotate-ccw-PWu_QGrD.js.gz +0 -0
  237. package/payload/server/public/assets/routines-Cp3_XS7S.js.br +0 -0
  238. package/payload/server/public/assets/routines-Cp3_XS7S.js.gz +0 -0
  239. package/payload/server/public/assets/skills-g8HvunPA.js.br +0 -0
  240. package/payload/server/public/assets/skills-g8HvunPA.js.gz +0 -0
  241. package/payload/server/public/assets/tasks-CMC_jDVm.js +0 -1
  242. package/payload/server/public/assets/tasks-CMC_jDVm.js.br +0 -0
  243. package/payload/server/public/assets/tasks-CMC_jDVm.js.gz +0 -0
  244. package/payload/server/public/assets/time-entry-format-BXWuQ6Sw.js.br +0 -2
  245. package/payload/server/public/assets/time-entry-format-BXWuQ6Sw.js.gz +0 -0
  246. package/payload/server/public/assets/triangle-alert-BNshRC13.js.br +0 -0
  247. package/payload/server/public/assets/triangle-alert-BNshRC13.js.gz +0 -0
  248. package/payload/server/public/assets/useCopyFeedback-CwTZ9DqH.js.br +0 -0
  249. package/payload/server/public/assets/useCopyFeedback-CwTZ9DqH.js.gz +0 -0
  250. package/payload/server/public/assets/useSubAccountSwitcher-BuUYMDWl.js.br +0 -0
  251. package/payload/server/public/assets/useSubAccountSwitcher-dzDnmWq9.css.br +0 -0
  252. package/payload/server/public/assets/useVoiceRecorder-BGqV5R6u.js.br +0 -0
  253. package/payload/server/public/assets/useVoiceRecorder-BGqV5R6u.js.gz +0 -0
  254. package/payload/server/public/assets/wrench-DQ045Pyk.js.br +0 -0
  255. package/payload/server/public/assets/wrench-DQ045Pyk.js.gz +0 -0
@@ -103,6 +103,7 @@ import {
103
103
  findGrantByMagicToken,
104
104
  foldReactions,
105
105
  formatError,
106
+ formatSenderPhone,
106
107
  generateNewMagicToken,
107
108
  getAccountsDirFromEnv,
108
109
  getAuthAgeMs,
@@ -110,6 +111,7 @@ import {
110
111
  getStatus,
111
112
  getStatusCode,
112
113
  getWhatsAppConfig,
114
+ groupEntriesFromUpdates,
113
115
  guardInstalled,
114
116
  hasCredsSync,
115
117
  init,
@@ -124,6 +126,7 @@ import {
124
126
  isWithinOwnAccountPartition,
125
127
  jidToE164,
126
128
  listConnectionPlatformAccountIds,
129
+ listConnections,
127
130
  listLedgerAccounts,
128
131
  listStoreAccountKeys,
129
132
  listStoredAccountIds,
@@ -137,6 +140,7 @@ import {
137
140
  phonesMatch,
138
141
  pruneLedger,
139
142
  readAllConversations,
143
+ readChatMetadata,
140
144
  readConversation,
141
145
  readConversationSummaries,
142
146
  readDeclined,
@@ -176,8 +180,9 @@ import {
176
180
  validateAccountIdEnv,
177
181
  validateFilePathInAccount,
178
182
  waitForConnection,
179
- warnNonUuidAccount
180
- } from "./chunk-AZLT4LVO.js";
183
+ warnNonUuidAccount,
184
+ writeChatMetadataMerged
185
+ } from "./chunk-K7CJGZPU.js";
181
186
  import {
182
187
  ACCOUNTS_DIR,
183
188
  BIN_DIR,
@@ -1721,7 +1726,7 @@ var require_dist5 = __commonJS({
1721
1726
  import { readFileSync as readFileSync44, existsSync as existsSync48, watchFile, readdirSync as readdirSync28, statSync as statSync24 } from "fs";
1722
1727
  import { spawn as spawn3 } from "child_process";
1723
1728
  import { createHash as createHash7 } from "crypto";
1724
- import { resolve as resolve42, join as join50, basename as basename15 } from "path";
1729
+ import { resolve as resolve42, join as join51, basename as basename16 } from "path";
1725
1730
  import { homedir as homedir4 } from "os";
1726
1731
 
1727
1732
  // server/lib/route-cache-watchers.ts
@@ -2287,11 +2292,11 @@ function staticCacheHeaders(root) {
2287
2292
  }
2288
2293
 
2289
2294
  // server/lib/static-mounts.ts
2290
- function mountStaticFiles(app73, root) {
2291
- app73.use("/*", staticCacheHeaders(root));
2292
- app73.use("/assets/*", assetsVary);
2293
- app73.use("/assets/*", serveStatic({ root, precompressed: true }));
2294
- app73.use("/*", serveStatic({ root }));
2295
+ function mountStaticFiles(app75, root) {
2296
+ app75.use("/*", staticCacheHeaders(root));
2297
+ app75.use("/assets/*", assetsVary);
2298
+ app75.use("/assets/*", serveStatic({ root, precompressed: true }));
2299
+ app75.use("/*", serveStatic({ root }));
2295
2300
  }
2296
2301
  var assetsVary = async (c, next) => {
2297
2302
  await next();
@@ -3502,8 +3507,8 @@ function webchatTurnTimeoutMs() {
3502
3507
  return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
3503
3508
  }
3504
3509
  function createChatRoutes(deps) {
3505
- const app73 = new Hono();
3506
- app73.post("/", async (c) => {
3510
+ const app75 = new Hono();
3511
+ app75.post("/", async (c) => {
3507
3512
  console.log(`[chat-route] entered route=public method=POST`);
3508
3513
  const contentType = c.req.header("content-type") ?? "";
3509
3514
  const account = resolveAccount();
@@ -3775,7 +3780,7 @@ ${result.result.text}` : result.result.text;
3775
3780
  }
3776
3781
  });
3777
3782
  });
3778
- return app73;
3783
+ return app75;
3779
3784
  }
3780
3785
 
3781
3786
  // app/lib/channel-pty-bridge/admin-session-id.ts
@@ -3809,8 +3814,8 @@ function isLoopbackAddr(addr) {
3809
3814
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
3810
3815
  }
3811
3816
  function createScheduleInjectRoutes(deps) {
3812
- const app73 = new Hono();
3813
- app73.post("/", async (c) => {
3817
+ const app75 = new Hono();
3818
+ app75.post("/", async (c) => {
3814
3819
  const env = c.env;
3815
3820
  const remoteAddr = env?.incoming?.socket?.remoteAddress ?? "";
3816
3821
  if (!isLoopbackAddr(remoteAddr)) {
@@ -3911,7 +3916,7 @@ function createScheduleInjectRoutes(deps) {
3911
3916
  console.error(`${TAG5} op=inject-spawn eventId=${eventId} sessionId=${sessionId} result=ok status=-`);
3912
3917
  return c.json({ ok: true }, 200);
3913
3918
  });
3914
- return app73;
3919
+ return app75;
3915
3920
  }
3916
3921
 
3917
3922
  // server/index.ts
@@ -4017,7 +4022,7 @@ async function defaultHttpGet(url) {
4017
4022
  }
4018
4023
  }
4019
4024
  async function defaultResolve(accountId) {
4020
- const { resolveSocket: resolveSocket2 } = await import("./manager-CQBSUJXR.js");
4025
+ const { resolveSocket: resolveSocket2 } = await import("./manager-RKL7JZ4Y.js");
4021
4026
  return resolveSocket2(accountId);
4022
4027
  }
4023
4028
  async function fetchAvatar(accountId, jid, deps = {}) {
@@ -4148,8 +4153,60 @@ async function sweepAvatars() {
4148
4153
  return note;
4149
4154
  }
4150
4155
 
4156
+ // app/lib/whatsapp/chat-metadata-sweep.ts
4157
+ var TAG8 = "[wa-chatmeta]";
4158
+ function diffStoredAgainstLive(stored, live) {
4159
+ const out = [];
4160
+ for (const entry of stored.values()) {
4161
+ if (!entry.isGroup) continue;
4162
+ const seen = live.get(entry.jid);
4163
+ if (seen === void 0) continue;
4164
+ if (seen.name !== entry.name) {
4165
+ out.push({ jid: entry.jid, stored: entry.name, live: seen.name, observedAt: seen.observedAt });
4166
+ }
4167
+ }
4168
+ return out;
4169
+ }
4170
+ async function sweepChatMetadata() {
4171
+ const started2 = Date.now();
4172
+ let groups = 0;
4173
+ let checked = 0;
4174
+ let drifted = 0;
4175
+ let unreachable = 0;
4176
+ for (const conn of listConnections()) {
4177
+ if (!conn.sock) continue;
4178
+ const sock = conn.sock;
4179
+ const stored = readChatMetadata(conn.platformAccountId);
4180
+ const live = /* @__PURE__ */ new Map();
4181
+ for (const entry of stored.values()) {
4182
+ if (!entry.isGroup) continue;
4183
+ groups += 1;
4184
+ try {
4185
+ const meta = await sock.groupMetadata(entry.jid);
4186
+ if (typeof meta.subject === "string" && meta.subject.length > 0) {
4187
+ live.set(entry.jid, { name: meta.subject, observedAt: (/* @__PURE__ */ new Date()).toISOString() });
4188
+ checked += 1;
4189
+ }
4190
+ } catch {
4191
+ unreachable += 1;
4192
+ }
4193
+ }
4194
+ const drift = diffStoredAgainstLive(stored, live);
4195
+ const corrections = [];
4196
+ for (const d of drift) {
4197
+ console.error(`${TAG8} op=drift jid=${d.jid} stored=${d.stored} live=${d.live} observedAt=${d.observedAt}`);
4198
+ corrections.push(...groupEntriesFromUpdates([{ id: d.jid, subject: d.live }], d.observedAt));
4199
+ }
4200
+ drifted += drift.length;
4201
+ if (corrections.length > 0) writeChatMetadataMerged(conn.platformAccountId, corrections);
4202
+ }
4203
+ const summary = `groups=${groups} checked=${checked} drifted=${drifted} unreachable=${unreachable} ms=${Date.now() - started2}`;
4204
+ console.error(`${TAG8} op=sweep ${summary}`);
4205
+ return summary;
4206
+ }
4207
+
4151
4208
  // app/lib/whatsapp/group-outbound-audit.ts
4152
- var TAG8 = "[wa-manual-send]";
4209
+ var TAG9 = "[wa-manual-send]";
4153
4210
  var OFFENDER_CAP = 10;
4154
4211
  function auditGroupOutbound() {
4155
4212
  let convos = 0;
@@ -4179,7 +4236,7 @@ function auditGroupOutboundNote() {
4179
4236
  const a = auditGroupOutbound();
4180
4237
  const tail = a.agent > 0 ? ` offenders=${a.offenders.join(",")}` : "";
4181
4238
  const note = `convos=${a.convos} outbound=${a.outbound} operator=${a.operator} agent=${a.agent} unstamped=${a.unstamped}${tail}`;
4182
- console.log(`${TAG8} op=group-outbound-audit ${note}`);
4239
+ console.log(`${TAG9} op=group-outbound-audit ${note}`);
4183
4240
  return note;
4184
4241
  }
4185
4242
 
@@ -4236,7 +4293,7 @@ import { randomUUID as randomUUID2 } from "crypto";
4236
4293
  // app/lib/whatsapp/config-persist.ts
4237
4294
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
4238
4295
  import { resolve as resolve4, join as join7, dirname, basename } from "path";
4239
- var TAG9 = "[whatsapp:config]";
4296
+ var TAG10 = "[whatsapp:config]";
4240
4297
  function configPath(accountDir) {
4241
4298
  return resolve4(accountDir, "account.json");
4242
4299
  }
@@ -4253,9 +4310,9 @@ function reloadManagerConfig(accountDir) {
4253
4310
  try {
4254
4311
  const config = readConfig(accountDir);
4255
4312
  reloadConfig(config);
4256
- console.error(`${TAG9} reloaded manager config`);
4313
+ console.error(`${TAG10} reloaded manager config`);
4257
4314
  } catch (err) {
4258
- console.error(`${TAG9} manager config reload failed: ${String(err)}`);
4315
+ console.error(`${TAG10} manager config reload failed: ${String(err)}`);
4259
4316
  }
4260
4317
  }
4261
4318
  var E164_PATTERN = /^\+\d{7,15}$/;
@@ -4281,25 +4338,25 @@ function persistAfterPairing(accountDir, accountId, selfPhone) {
4281
4338
  const adminPhones = wa.adminPhones;
4282
4339
  if (!adminPhones.includes(normalized)) {
4283
4340
  adminPhones.push(normalized);
4284
- console.error(`${TAG9} added selfPhone=${normalized} to adminPhones`);
4341
+ console.error(`${TAG10} added selfPhone=${normalized} to adminPhones`);
4285
4342
  }
4286
4343
  } else {
4287
- console.error(`${TAG9} skipping adminPhones \u2014 selfPhone is null account=${accountId}`);
4344
+ console.error(`${TAG10} skipping adminPhones \u2014 selfPhone is null account=${accountId}`);
4288
4345
  }
4289
4346
  const parsed = WhatsAppConfigSchema.safeParse(wa);
4290
4347
  if (!parsed.success) {
4291
4348
  const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
4292
- console.error(`${TAG9} validation failed after pairing: ${msg}`);
4349
+ console.error(`${TAG10} validation failed after pairing: ${msg}`);
4293
4350
  return { ok: false, error: `Validation failed: ${msg}` };
4294
4351
  }
4295
4352
  config.whatsapp = parsed.data;
4296
4353
  writeConfig(accountDir, config);
4297
- console.error(`${TAG9} persisted after pairing account=${accountId} phone=${selfPhone ?? "null"}`);
4354
+ console.error(`${TAG10} persisted after pairing account=${accountId} phone=${selfPhone ?? "null"}`);
4298
4355
  reloadManagerConfig(accountDir);
4299
4356
  return { ok: true };
4300
4357
  } catch (err) {
4301
4358
  const msg = err instanceof Error ? err.message : String(err);
4302
- console.error(`${TAG9} persist failed account=${accountId}: ${msg}`);
4359
+ console.error(`${TAG10} persist failed account=${accountId}: ${msg}`);
4303
4360
  return { ok: false, error: msg };
4304
4361
  }
4305
4362
  }
@@ -4313,7 +4370,7 @@ function addAdminPhone(accountDir, phone) {
4313
4370
  const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename(resolve4(accountDir));
4314
4371
  const socketOwner = resolveHouseOrSoleAccountId(dirname(resolve4(accountDir)));
4315
4372
  if (targetId !== socketOwner) {
4316
- console.error(`${TAG9} add-admin-phone rejected accountId=${targetId} reason=not-socket-account`);
4373
+ console.error(`${TAG10} add-admin-phone rejected accountId=${targetId} reason=not-socket-account`);
4317
4374
  return {
4318
4375
  ok: false,
4319
4376
  reason: "not-socket-account",
@@ -4342,12 +4399,12 @@ function addAdminPhone(accountDir, phone) {
4342
4399
  }
4343
4400
  config.whatsapp = parsed.data;
4344
4401
  writeConfig(accountDir, config);
4345
- console.error(`${TAG9} added admin phone=${normalized}`);
4402
+ console.error(`${TAG10} added admin phone=${normalized}`);
4346
4403
  reloadManagerConfig(accountDir);
4347
4404
  return { ok: true, message: `Added ${normalized} as admin phone. Messages from this number will route to the admin agent.` };
4348
4405
  } catch (err) {
4349
4406
  const msg = err instanceof Error ? err.message : String(err);
4350
- console.error(`${TAG9} addAdminPhone failed: ${msg}`);
4407
+ console.error(`${TAG10} addAdminPhone failed: ${msg}`);
4351
4408
  return { ok: false, error: msg };
4352
4409
  }
4353
4410
  }
@@ -4375,12 +4432,12 @@ function removeAdminPhone(accountDir, phone) {
4375
4432
  }
4376
4433
  config.whatsapp = parsed.data;
4377
4434
  writeConfig(accountDir, config);
4378
- console.error(`${TAG9} removed admin phone=${normalized}`);
4435
+ console.error(`${TAG10} removed admin phone=${normalized}`);
4379
4436
  reloadManagerConfig(accountDir);
4380
4437
  return { ok: true, message: `Removed ${normalized} from admin phones. Messages from this number will now route to the public agent.` };
4381
4438
  } catch (err) {
4382
4439
  const msg = err instanceof Error ? err.message : String(err);
4383
- console.error(`${TAG9} removeAdminPhone failed: ${msg}`);
4440
+ console.error(`${TAG10} removeAdminPhone failed: ${msg}`);
4384
4441
  return { ok: false, error: msg };
4385
4442
  }
4386
4443
  }
@@ -4506,7 +4563,7 @@ function setAccountManager(accountDir, phone, subAccountId, mode = "active") {
4506
4563
  return { ok: false, error: `Could not resolve the house account to validate the binding: ${err instanceof Error ? err.message : String(err)}. Try again.` };
4507
4564
  }
4508
4565
  if (sub === houseId) {
4509
- console.error(`${TAG9} set-account-manager rejected phone=${normalized} reason=house-account-binding`);
4566
+ console.error(`${TAG10} set-account-manager rejected phone=${normalized} reason=house-account-binding`);
4510
4567
  return {
4511
4568
  ok: false,
4512
4569
  reason: "house-account-binding",
@@ -4517,7 +4574,7 @@ function setAccountManager(accountDir, phone, subAccountId, mode = "active") {
4517
4574
  const config = readConfig(accountDir);
4518
4575
  const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename(resolve4(accountDir));
4519
4576
  if (targetId !== houseId) {
4520
- console.error(`${TAG9} set-account-manager rejected phone=${normalized} reason=not-socket-account`);
4577
+ console.error(`${TAG10} set-account-manager rejected phone=${normalized} reason=not-socket-account`);
4521
4578
  return {
4522
4579
  ok: false,
4523
4580
  reason: "not-socket-account",
@@ -4546,13 +4603,13 @@ function setAccountManager(accountDir, phone, subAccountId, mode = "active") {
4546
4603
  }
4547
4604
  config.whatsapp = parsed.data;
4548
4605
  writeConfig(accountDir, config);
4549
- console.error(`${TAG9} bound account manager phone=${normalized} managesAccount=${sub} mode=${mode}`);
4606
+ console.error(`${TAG10} bound account manager phone=${normalized} managesAccount=${sub} mode=${mode}`);
4550
4607
  reloadManagerConfig(accountDir);
4551
4608
  const behaviour = mode === "passive" ? `Their WhatsApp messages will each file one task scoped to that sub-account; the agent sends nothing back.` : `Their WhatsApp messages will reach that sub-account's admin agent; replies still go out over this account's WhatsApp device.`;
4552
4609
  return { ok: true, message: `Bound ${normalized} as ${mode} account manager for sub-account ${sub}. ${behaviour}` };
4553
4610
  } catch (err) {
4554
4611
  const msg = err instanceof Error ? err.message : String(err);
4555
- console.error(`${TAG9} setAccountManager failed: ${msg}`);
4612
+ console.error(`${TAG10} setAccountManager failed: ${msg}`);
4556
4613
  return { ok: false, error: msg };
4557
4614
  }
4558
4615
  }
@@ -4589,12 +4646,12 @@ function setDispatchInbound(accountDir, accountId, value) {
4589
4646
  }
4590
4647
  config.whatsapp = parsed.data;
4591
4648
  writeConfig(accountDir, config);
4592
- console.error(`${TAG9} set dispatchInbound account=${id} value=${value}`);
4649
+ console.error(`${TAG10} set dispatchInbound account=${id} value=${value}`);
4593
4650
  reloadManagerConfig(accountDir);
4594
4651
  return { ok: true };
4595
4652
  } catch (err) {
4596
4653
  const msg = err instanceof Error ? err.message : String(err);
4597
- console.error(`${TAG9} setDispatchInbound failed: ${msg}`);
4654
+ console.error(`${TAG10} setDispatchInbound failed: ${msg}`);
4598
4655
  return { ok: false, error: msg };
4599
4656
  }
4600
4657
  }
@@ -4619,12 +4676,12 @@ function clearAccountManager(accountDir, phone) {
4619
4676
  }
4620
4677
  config.whatsapp = parsed.data;
4621
4678
  writeConfig(accountDir, config);
4622
- console.error(`${TAG9} cleared account manager phone=${normalized}`);
4679
+ console.error(`${TAG10} cleared account manager phone=${normalized}`);
4623
4680
  reloadManagerConfig(accountDir);
4624
4681
  return { ok: true, message: `Cleared the account-manager binding for ${normalized}.` };
4625
4682
  } catch (err) {
4626
4683
  const msg = err instanceof Error ? err.message : String(err);
4627
- console.error(`${TAG9} clearAccountManager failed: ${msg}`);
4684
+ console.error(`${TAG10} clearAccountManager failed: ${msg}`);
4628
4685
  return { ok: false, error: msg };
4629
4686
  }
4630
4687
  }
@@ -4671,12 +4728,12 @@ function setPublicAgent(accountDir, slug) {
4671
4728
  }
4672
4729
  config.whatsapp = parsed.data;
4673
4730
  writeConfig(accountDir, config);
4674
- console.error(`${TAG9} publicAgent set to ${trimmed}`);
4731
+ console.error(`${TAG10} publicAgent set to ${trimmed}`);
4675
4732
  reloadManagerConfig(accountDir);
4676
4733
  return { ok: true, message: `Public agent set to "${trimmed}". WhatsApp messages from non-admin phones will be handled by this agent.` };
4677
4734
  } catch (err) {
4678
4735
  const msg = err instanceof Error ? err.message : String(err);
4679
- console.error(`${TAG9} setPublicAgent failed: ${msg}`);
4736
+ console.error(`${TAG10} setPublicAgent failed: ${msg}`);
4680
4737
  return { ok: false, error: msg };
4681
4738
  }
4682
4739
  }
@@ -4717,17 +4774,17 @@ function updateConfig(accountDir, fields) {
4717
4774
  const parsed = WhatsAppConfigSchema.safeParse(wa);
4718
4775
  if (!parsed.success) {
4719
4776
  const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
4720
- console.error(`${TAG9} update validation failed: ${msg}`);
4777
+ console.error(`${TAG10} update validation failed: ${msg}`);
4721
4778
  return { ok: false, error: `Validation failed: ${msg}` };
4722
4779
  }
4723
4780
  config.whatsapp = parsed.data;
4724
4781
  writeConfig(accountDir, config);
4725
- console.error(`${TAG9} updated fields=[${fieldNames.join(",")}]`);
4782
+ console.error(`${TAG10} updated fields=[${fieldNames.join(",")}]`);
4726
4783
  reloadManagerConfig(accountDir);
4727
4784
  return { ok: true, message: `Updated WhatsApp config: ${fieldNames.join(", ")}.` };
4728
4785
  } catch (err) {
4729
4786
  const msg = err instanceof Error ? err.message : String(err);
4730
- console.error(`${TAG9} updateConfig failed: ${msg}`);
4787
+ console.error(`${TAG10} updateConfig failed: ${msg}`);
4731
4788
  return { ok: false, error: msg };
4732
4789
  }
4733
4790
  }
@@ -4764,17 +4821,17 @@ function migrateRemovedConfigKeys(accountDir) {
4764
4821
  }
4765
4822
  writeConfig(accountDir, config);
4766
4823
  console.error(
4767
- `${TAG9} migration: stripped unknown keys=[${result.droppedKeys.join(",")}] from account.json`
4824
+ `${TAG10} migration: stripped unknown keys=[${result.droppedKeys.join(",")}] from account.json`
4768
4825
  );
4769
4826
  return { dropped: result.droppedKeys };
4770
4827
  } catch (err) {
4771
- console.error(`${TAG9} migration failed: ${String(err)}`);
4828
+ console.error(`${TAG10} migration failed: ${String(err)}`);
4772
4829
  return { dropped: [] };
4773
4830
  }
4774
4831
  }
4775
4832
 
4776
4833
  // app/lib/whatsapp/login.ts
4777
- var TAG10 = "[whatsapp:login]";
4834
+ var TAG11 = "[whatsapp:login]";
4778
4835
  function maskPhone(digits) {
4779
4836
  if (digits.length <= 4) return "*".repeat(digits.length);
4780
4837
  return digits.slice(0, 2) + "*".repeat(digits.length - 4) + digits.slice(-2);
@@ -4785,7 +4842,7 @@ function closeSocket(sock) {
4785
4842
  try {
4786
4843
  sock.ws?.close?.();
4787
4844
  } catch (err) {
4788
- console.warn(`${TAG10} socket close error during cleanup: ${String(err)}`);
4845
+ console.warn(`${TAG11} socket close error during cleanup: ${String(err)}`);
4789
4846
  }
4790
4847
  }
4791
4848
  function resetActiveLogin(accountId) {
@@ -4812,18 +4869,18 @@ async function runPostPairing(login) {
4812
4869
  const masked = selfPhone ? `${selfPhone.slice(0, 4)}***` : "null";
4813
4870
  console.error(`[whatsapp-persist] wa-persist-on-connect account=${login.accountId} phone=${masked}`);
4814
4871
  } else {
4815
- console.error(`${TAG10} wa-persist-on-connect FAILED account=${login.accountId}: ${result.error}`);
4872
+ console.error(`${TAG11} wa-persist-on-connect FAILED account=${login.accountId}: ${result.error}`);
4816
4873
  }
4817
4874
  } catch (err) {
4818
- console.error(`${TAG10} wa-persist-on-connect error account=${login.accountId}: ${String(err)}`);
4875
+ console.error(`${TAG11} wa-persist-on-connect error account=${login.accountId}: ${String(err)}`);
4819
4876
  }
4820
4877
  } else {
4821
- console.error(`${TAG10} wa-persist-on-connect skipped \u2014 no accountDir account=${login.accountId}`);
4878
+ console.error(`${TAG11} wa-persist-on-connect skipped \u2014 no accountDir account=${login.accountId}`);
4822
4879
  }
4823
4880
  try {
4824
4881
  await registerLoginSocket(login.accountId, login.sock, login.authDir);
4825
4882
  } catch (err) {
4826
- console.error(`${TAG10} registerLoginSocket failed account=${login.accountId}: ${String(err)}`);
4883
+ console.error(`${TAG11} registerLoginSocket failed account=${login.accountId}: ${String(err)}`);
4827
4884
  }
4828
4885
  }
4829
4886
  async function loginConnectionLoop(accountId, login) {
@@ -4832,7 +4889,7 @@ async function loginConnectionLoop(accountId, login) {
4832
4889
  const logTerminal = (outcome, errMsg) => {
4833
4890
  const fc = credsCensus(login.authDir);
4834
4891
  console.error(
4835
- `${TAG10} op=terminal cid=${cidShort} outcome=${outcome} credsFinal={registered=${fc.registered},account=${fc.hasAccountSignature},me=${fc.e164 ?? "null"}}` + (errMsg ? ` error="${errMsg}"` : "")
4892
+ `${TAG11} op=terminal cid=${cidShort} outcome=${outcome} credsFinal={registered=${fc.registered},account=${fc.hasAccountSignature},me=${fc.e164 ?? "null"}}` + (errMsg ? ` error="${errMsg}"` : "")
4836
4893
  );
4837
4894
  };
4838
4895
  while (true) {
@@ -4842,7 +4899,7 @@ async function loginConnectionLoop(accountId, login) {
4842
4899
  if (current?.id === login.id) {
4843
4900
  await runPostPairing(current);
4844
4901
  current.connected = true;
4845
- console.error(`${TAG10} loginConnectionLoop: connected account=${accountId} attempt=${attempt} configPersisted=${current.configPersisted}`);
4902
+ console.error(`${TAG11} loginConnectionLoop: connected account=${accountId} attempt=${attempt} configPersisted=${current.configPersisted}`);
4846
4903
  logTerminal("connected");
4847
4904
  }
4848
4905
  return;
@@ -4854,7 +4911,7 @@ async function loginConnectionLoop(accountId, login) {
4854
4911
  if (!preRetryCensus.hasAccountSignature) {
4855
4912
  current.error = "WhatsApp accepted the code but did not finish linking. This usually means the number has reached its linked-device limit or has a stale linked device. On the phone, open WhatsApp, Linked Devices, remove existing devices, then ask for a new code.";
4856
4913
  console.error(
4857
- `${TAG10} op=pairing-incomplete cid=${cidShort} closeKind=${closeKind(getStatusCode(err), false)} reason=no-account-signature`
4914
+ `${TAG11} op=pairing-incomplete cid=${cidShort} closeKind=${closeKind(getStatusCode(err), false)} reason=no-account-signature`
4858
4915
  );
4859
4916
  return;
4860
4917
  }
@@ -4862,7 +4919,7 @@ async function loginConnectionLoop(accountId, login) {
4862
4919
  if (!classification.shouldRetry || attempt >= LOGIN_MAX_RECONNECTS) {
4863
4920
  if (attempt >= LOGIN_MAX_RECONNECTS) {
4864
4921
  console.error(
4865
- `${TAG10} login reconnect attempts exhausted (${attempt}/${LOGIN_MAX_RECONNECTS}) \u2014 surfacing error to agent`
4922
+ `${TAG11} login reconnect attempts exhausted (${attempt}/${LOGIN_MAX_RECONNECTS}) \u2014 surfacing error to agent`
4866
4923
  );
4867
4924
  current.error = `Login failed after ${attempt} reconnect attempts: ${formatError(err)}`;
4868
4925
  } else {
@@ -4875,7 +4932,7 @@ async function loginConnectionLoop(accountId, login) {
4875
4932
  attempt++;
4876
4933
  const delay = LOGIN_RECONNECT_DELAYS[attempt - 1] ?? 8e3;
4877
4934
  console.error(
4878
- `${TAG10} status=${classification.statusCode ?? "unknown"} restart required \u2014 reconnecting with saved creds (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}) delay=${delay}ms`
4935
+ `${TAG11} status=${classification.statusCode ?? "unknown"} restart required \u2014 reconnecting with saved creds (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}) delay=${delay}ms`
4879
4936
  );
4880
4937
  closeSocket(current.sock);
4881
4938
  await new Promise((r) => setTimeout(r, delay));
@@ -4883,14 +4940,14 @@ async function loginConnectionLoop(accountId, login) {
4883
4940
  if (afterDelay?.id !== login.id) return;
4884
4941
  const rc = credsCensus(login.authDir);
4885
4942
  console.error(
4886
- `${TAG10} op=reconnect cid=${cidShort} attempt=${attempt}/${LOGIN_MAX_RECONNECTS} withRegistered=${rc.registered} withAccount=${rc.hasAccountSignature}`
4943
+ `${TAG11} op=reconnect cid=${cidShort} attempt=${attempt}/${LOGIN_MAX_RECONNECTS} withRegistered=${rc.registered} withAccount=${rc.hasAccountSignature}`
4887
4944
  );
4888
4945
  try {
4889
4946
  const newSock = await createWaSocket({ authDir: login.authDir, correlationId: cidShort, account: accountId });
4890
4947
  current.sock = newSock;
4891
4948
  } catch (sockErr) {
4892
4949
  console.error(
4893
- `${TAG10} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
4950
+ `${TAG11} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
4894
4951
  );
4895
4952
  current.error = `Reconnection failed: ${String(sockErr)}`;
4896
4953
  logTerminal("error", current.error);
@@ -4907,7 +4964,7 @@ async function startLogin(opts) {
4907
4964
  const hasAuth = await authExists(authDir);
4908
4965
  const selfId = readSelfId(authDir);
4909
4966
  console.error(
4910
- `${TAG10} op=start cid=${cid} account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasCode=${!!existing0.pairingCode}}` : " activeLogin=none")
4967
+ `${TAG11} op=start cid=${cid} account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasCode=${!!existing0.pairingCode}}` : " activeLogin=none")
4911
4968
  );
4912
4969
  if (hasAuth && !force) {
4913
4970
  const who = selfId.e164 ?? selfId.jid ?? "unknown";
@@ -4922,7 +4979,7 @@ async function startLogin(opts) {
4922
4979
  }
4923
4980
  const existing = activeLogins.get(accountId);
4924
4981
  if (existing && isLoginFresh(existing) && existing.pairingCode && !force) {
4925
- console.error(`${TAG10} startLogin account=${accountId} guard: returning existing pairing code (age=${Math.round((Date.now() - existing.startedAt) / 1e3)}s)`);
4982
+ console.error(`${TAG11} startLogin account=${accountId} guard: returning existing pairing code (age=${Math.round((Date.now() - existing.startedAt) / 1e3)}s)`);
4926
4983
  return {
4927
4984
  pairingCode: existing.pairingCode,
4928
4985
  phone: existing.phone,
@@ -4930,7 +4987,7 @@ async function startLogin(opts) {
4930
4987
  };
4931
4988
  }
4932
4989
  if (existing) {
4933
- console.error(`${TAG10} startLogin account=${accountId} ${force ? "force override" : "stale/no-code"}, resetting active login`);
4990
+ console.error(`${TAG11} startLogin account=${accountId} ${force ? "force override" : "stale/no-code"}, resetting active login`);
4934
4991
  }
4935
4992
  resetActiveLogin(accountId);
4936
4993
  await clearAuth(authDir);
@@ -4961,7 +5018,7 @@ async function startLogin(opts) {
4961
5018
  if (requested) return;
4962
5019
  requested = true;
4963
5020
  console.error(
4964
- `${TAG10} op=pairing-request cid=${cid} account=${accountId} qrRef=#1 sinceOpenMs=${socketOpenTs ? Date.now() - socketOpenTs : 0}`
5021
+ `${TAG11} op=pairing-request cid=${cid} account=${accountId} qrRef=#1 sinceOpenMs=${socketOpenTs ? Date.now() - socketOpenTs : 0}`
4965
5022
  );
4966
5023
  void sock.requestPairingCode(digits).then((code) => {
4967
5024
  clearTimeout(codeTimer);
@@ -4970,7 +5027,7 @@ async function startLogin(opts) {
4970
5027
  if (current?.id !== login.id) return;
4971
5028
  if (!current.pairingCode) current.pairingCode = code;
4972
5029
  console.error(
4973
- `${TAG10} op=code-issued cid=${cid} account=${accountId} phone=${maskPhone(digits)} codeLen=${code.length} sinceOpenMs=${socketOpenTs ? codeIssuedTs - socketOpenTs : 0}`
5030
+ `${TAG11} op=code-issued cid=${cid} account=${accountId} phone=${maskPhone(digits)} codeLen=${code.length} sinceOpenMs=${socketOpenTs ? codeIssuedTs - socketOpenTs : 0}`
4974
5031
  );
4975
5032
  resolveCode?.(code);
4976
5033
  }).catch((err) => {
@@ -5001,7 +5058,7 @@ async function startLogin(opts) {
5001
5058
  const ttlTimer = setTimeout(() => {
5002
5059
  const current = activeLogins.get(accountId);
5003
5060
  if (current?.id === login.id && !current.connected) {
5004
- console.error(`${TAG10} pairing-window-elapsed account=${accountId} (ttl sweep)`);
5061
+ console.error(`${TAG11} pairing-window-elapsed account=${accountId} (ttl sweep)`);
5005
5062
  resetActiveLogin(accountId);
5006
5063
  }
5007
5064
  }, ACTIVE_LOGIN_TTL_MS);
@@ -5009,7 +5066,7 @@ async function startLogin(opts) {
5009
5066
  ttlTimer.unref();
5010
5067
  }
5011
5068
  loginConnectionLoop(accountId, login).catch((err) => {
5012
- console.error(`${TAG10} loginConnectionLoop unexpected error: ${String(err)}`);
5069
+ console.error(`${TAG11} loginConnectionLoop unexpected error: ${String(err)}`);
5013
5070
  const current = activeLogins.get(accountId);
5014
5071
  if (current?.id === login.id) {
5015
5072
  current.error = `Unexpected login error: ${String(err)}`;
@@ -5034,13 +5091,13 @@ async function waitForLogin(opts) {
5034
5091
  const { accountId, timeoutMs = 6e4 } = opts;
5035
5092
  const login = activeLogins.get(accountId);
5036
5093
  console.error(
5037
- `${TAG10} waitForLogin account=${accountId} timeout=${timeoutMs}ms` + (login ? ` login={id=${login.id.slice(0, 8)},age=${Math.round((Date.now() - login.startedAt) / 1e3)}s,connected=${login.connected},hasCode=${!!login.pairingCode}}` : " login=none")
5094
+ `${TAG11} waitForLogin account=${accountId} timeout=${timeoutMs}ms` + (login ? ` login={id=${login.id.slice(0, 8)},age=${Math.round((Date.now() - login.startedAt) / 1e3)}s,connected=${login.connected},hasCode=${!!login.pairingCode}}` : " login=none")
5038
5095
  );
5039
5096
  if (!login) {
5040
5097
  return { connected: false, message: "No active WhatsApp login in progress.", configPersisted: false };
5041
5098
  }
5042
5099
  if (!isLoginFresh(login)) {
5043
- console.error(`${TAG10} pairing-window-elapsed account=${accountId}`);
5100
+ console.error(`${TAG11} pairing-window-elapsed account=${accountId}`);
5044
5101
  resetActiveLogin(accountId);
5045
5102
  return { connected: false, message: "The pairing window expired. Ask me to generate a new code.", configPersisted: false };
5046
5103
  }
@@ -5048,8 +5105,8 @@ async function waitForLogin(opts) {
5048
5105
  while (Date.now() < deadline) {
5049
5106
  if (login.connected) {
5050
5107
  const selfId = readSelfId(login.authDir);
5051
- console.error(`${TAG10} pairing-connected account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
5052
- console.error(`${TAG10} login complete for account=${accountId} phone=${selfId.e164 ?? "unknown"} configPersisted=${login.configPersisted}`);
5108
+ console.error(`${TAG11} pairing-connected account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
5109
+ console.error(`${TAG11} login complete for account=${accountId} phone=${selfId.e164 ?? "unknown"} configPersisted=${login.configPersisted}`);
5053
5110
  const configPersisted = login.configPersisted;
5054
5111
  activeLogins.delete(accountId);
5055
5112
  return {
@@ -5067,7 +5124,7 @@ async function waitForLogin(opts) {
5067
5124
  await new Promise((r) => setTimeout(r, 1e3));
5068
5125
  }
5069
5126
  const elapsed = Math.round((Date.now() - (deadline - timeoutMs)) / 1e3);
5070
- console.error(`${TAG10} waitForLogin poll timeout account=${accountId} elapsed=${elapsed}s \u2014 login kept alive (pairing code still valid)`);
5127
+ console.error(`${TAG11} waitForLogin poll timeout account=${accountId} elapsed=${elapsed}s \u2014 login kept alive (pairing code still valid)`);
5071
5128
  return { connected: false, message: "Still waiting for you to enter the pairing code. The code is still valid \u2014 ask me to keep waiting, or request a new code.", configPersisted: false };
5072
5129
  }
5073
5130
  function listActiveLoginAccountIds() {
@@ -5089,7 +5146,7 @@ function reconcileMessageStoreAccountKeys(input) {
5089
5146
  import { realpathSync } from "fs";
5090
5147
  import { readFile, stat } from "fs/promises";
5091
5148
  import { resolve as resolve5, basename as basename2 } from "path";
5092
- var TAG11 = "[whatsapp:outbound]";
5149
+ var TAG12 = "[whatsapp:outbound]";
5093
5150
  var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
5094
5151
  var lastRouteDocumentOutboundAt = /* @__PURE__ */ new Map();
5095
5152
  function normalizeJid(to) {
@@ -5122,10 +5179,10 @@ async function sendWhatsAppDocument(input) {
5122
5179
  } catch (err) {
5123
5180
  const code = err.code;
5124
5181
  if (code === "ENOENT") {
5125
- console.error(`${TAG11} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
5182
+ console.error(`${TAG12} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
5126
5183
  return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
5127
5184
  }
5128
- console.error(`${TAG11} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
5185
+ console.error(`${TAG12} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
5129
5186
  return { ok: false, status: 500, error: String(err) };
5130
5187
  }
5131
5188
  let resolvedPath;
@@ -5134,15 +5191,15 @@ async function sendWhatsAppDocument(input) {
5134
5191
  } catch (err) {
5135
5192
  const code = err.code;
5136
5193
  if (code === "ENOENT") {
5137
- console.error(`${TAG11} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
5194
+ console.error(`${TAG12} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
5138
5195
  return { ok: false, status: 404, error: `File not found: ${filePath}` };
5139
5196
  }
5140
- console.error(`${TAG11} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
5197
+ console.error(`${TAG12} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
5141
5198
  return { ok: false, status: 500, error: String(err) };
5142
5199
  }
5143
5200
  if (!resolvedPath.startsWith(accountResolved + "/")) {
5144
5201
  const sanitised = filePath.replace(accountDir, "<account>/");
5145
- console.error(`${TAG11} document REJECTED path=${sanitised} reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
5202
+ console.error(`${TAG12} document REJECTED path=${sanitised} reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
5146
5203
  return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
5147
5204
  }
5148
5205
  const fileStat = await stat(resolvedPath);
@@ -5158,7 +5215,7 @@ async function sendWhatsAppDocument(input) {
5158
5215
  const res = resolveSocket(accountId);
5159
5216
  if (!res.ok) {
5160
5217
  const reason = formatSocketResolutionReason(res);
5161
- console.error(`${TAG11} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=false reason=${reason}`);
5218
+ console.error(`${TAG12} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=false reason=${reason}`);
5162
5219
  return { ok: false, status: 503, error: formatSocketResolutionMessage(res, accountId) };
5163
5220
  }
5164
5221
  const sock = res.sock;
@@ -5171,7 +5228,7 @@ async function sendWhatsAppDocument(input) {
5171
5228
  { accountId: res.accountId }
5172
5229
  );
5173
5230
  console.error(
5174
- `${TAG11} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=${result.success}` + (result.messageId ? ` id=${result.messageId}` : "")
5231
+ `${TAG12} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=${result.success}` + (result.messageId ? ` id=${result.messageId}` : "")
5175
5232
  );
5176
5233
  if (result.success) {
5177
5234
  recordDocumentOutbound(to);
@@ -5291,7 +5348,7 @@ function serializeWhatsAppSchema() {
5291
5348
  // app/lib/whatsapp/status-reconcile.ts
5292
5349
  import { readdirSync as readdirSync3 } from "fs";
5293
5350
  import { join as join8 } from "path";
5294
- var TAG12 = "[whatsapp:reconcile]";
5351
+ var TAG13 = "[whatsapp:reconcile]";
5295
5352
  var HALF_REGISTERED_MIN_AGE_MS = 5 * 6e4;
5296
5353
  function listCredsAccountIds(credsRoot) {
5297
5354
  try {
@@ -5317,14 +5374,14 @@ function reconcileCredsOnDisk(opts) {
5317
5374
  const ageMs2 = getAuthAgeMs(authDir);
5318
5375
  const abandoned = !inFlight2 && ageMs2 !== null && ageMs2 >= HALF_REGISTERED_MIN_AGE_MS;
5319
5376
  if (!abandoned) {
5320
- console.error(`${TAG12} op=half-registered account=${accountId} registered=true hasAccount=false inFlight=${inFlight2} ageMs=${ageMs2 ?? "null"}`);
5377
+ console.error(`${TAG13} op=half-registered account=${accountId} registered=true hasAccount=false inFlight=${inFlight2} ageMs=${ageMs2 ?? "null"}`);
5321
5378
  entries2.push({ accountId, connected: false, linkedUnconfigured: true });
5322
5379
  continue;
5323
5380
  }
5324
- console.error(`${TAG12} op=discard-half-registered account=${accountId} registered=true hasAccount=false ageMs=${ageMs2}`);
5381
+ console.error(`${TAG13} op=discard-half-registered account=${accountId} registered=true hasAccount=false ageMs=${ageMs2}`);
5325
5382
  const removed = discardAuthDirSync(authDir);
5326
5383
  if (!removed) {
5327
- console.error(`${TAG12} op=discard-half-registered-failed account=${accountId} \u2014 residue persists`);
5384
+ console.error(`${TAG13} op=discard-half-registered-failed account=${accountId} \u2014 residue persists`);
5328
5385
  entries2.push({ accountId, connected: false, linkedUnconfigured: true });
5329
5386
  }
5330
5387
  continue;
@@ -5332,14 +5389,14 @@ function reconcileCredsOnDisk(opts) {
5332
5389
  const selfPhone = readSelfId(authDir).e164 ?? void 0;
5333
5390
  const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
5334
5391
  console.error(
5335
- `${TAG12} wa-link-unconfigured account=${accountId} creds=present config=${configured ? "present" : "absent"}`
5392
+ `${TAG13} wa-link-unconfigured account=${accountId} creds=present config=${configured ? "present" : "absent"}`
5336
5393
  );
5337
5394
  if (!configured && accountDir) {
5338
5395
  const result = persistAfterPairing(accountDir, accountId, selfPhone ?? null);
5339
5396
  if (result.ok) {
5340
- console.error(`${TAG12} self-healed account=${accountId}`);
5397
+ console.error(`${TAG13} self-healed account=${accountId}`);
5341
5398
  } else {
5342
- console.error(`${TAG12} self-heal FAILED account=${accountId}: ${result.error}`);
5399
+ console.error(`${TAG13} self-heal FAILED account=${accountId}: ${result.error}`);
5343
5400
  }
5344
5401
  }
5345
5402
  entries2.push({ accountId, selfPhone, connected: false, linkedUnconfigured: !configured });
@@ -5355,6 +5412,18 @@ function admitReply(input) {
5355
5412
  return { ok: true };
5356
5413
  }
5357
5414
 
5415
+ // app/lib/reader/conversation-preview.ts
5416
+ var ATTACHMENT_LABEL = "Attachment";
5417
+ function buildConversationPreview(input, maxLen = 80) {
5418
+ const text = input.body.replace(/\s+/g, " ").trim();
5419
+ const subject = text.length > 0 ? text : input.hasAttachment ? ATTACHMENT_LABEL : "";
5420
+ if (subject.length === 0) return "";
5421
+ const clipped = subject.length > maxLen ? `${subject.slice(0, maxLen)}\u2026` : subject;
5422
+ if (input.fromMe) return `You: ${clipped}`;
5423
+ if (input.isGroup && input.senderName) return `${input.senderName}: ${clipped}`;
5424
+ return clipped;
5425
+ }
5426
+
5358
5427
  // app/lib/reader/select-sessions.ts
5359
5428
  function isReaderChannelSession(role, channel) {
5360
5429
  return role === "admin" && (channel === "whatsapp" || channel === "telegram") || role === "public" && (channel === "whatsapp" || channel === "webchat");
@@ -5404,11 +5473,12 @@ function storePushNamesBySender(summaries) {
5404
5473
  }
5405
5474
  return out;
5406
5475
  }
5407
- function buildStoreConversationRows(accountId, summaries) {
5476
+ function buildStoreConversationRows(accountId, summaries, chatMeta) {
5408
5477
  const rows = [];
5409
5478
  for (const [remoteJid, { first, last, firstNamedSender }] of summaries) {
5410
5479
  const scope = last.scope;
5411
5480
  const senderTelephone = conversationCounterpartyPhone(remoteJid, first.senderTelephone);
5481
+ const isGroup = remoteJid.endsWith("@g.us");
5412
5482
  rows.push({
5413
5483
  sessionId: "",
5414
5484
  projectDir: "",
@@ -5425,7 +5495,16 @@ function buildStoreConversationRows(accountId, summaries) {
5425
5495
  source: "store",
5426
5496
  accountId,
5427
5497
  remoteJid,
5428
- scope
5498
+ scope,
5499
+ chatName: chatMeta?.get(remoteJid)?.name ?? null,
5500
+ isGroup,
5501
+ preview: buildConversationPreview({
5502
+ body: last.body,
5503
+ fromMe: last.fromMe,
5504
+ senderName: last.senderName,
5505
+ hasAttachment: last.attachmentId !== void 0,
5506
+ isGroup
5507
+ })
5429
5508
  });
5430
5509
  }
5431
5510
  return rows.sort((a, b) => (b.lastMessageAt ?? "").localeCompare(a.lastMessageAt ?? ""));
@@ -5482,7 +5561,7 @@ function authorizeRecallRead(input) {
5482
5561
  }
5483
5562
 
5484
5563
  // server/routes/whatsapp.ts
5485
- var TAG13 = "[whatsapp:api]";
5564
+ var TAG14 = "[whatsapp:api]";
5486
5565
  var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT || "";
5487
5566
  function recallAttachment(storeAccountId, attachmentId) {
5488
5567
  if (!attachmentId) return void 0;
@@ -5527,16 +5606,16 @@ function houseSocketScopeDenial(c, op) {
5527
5606
  const houseAccountId = resolveAccount()?.accountId ?? "";
5528
5607
  const { decision, callerAccountId, houseAdminScope } = evaluateCallerScope(c, houseAccountId);
5529
5608
  if (decision.authorized) return null;
5530
- console.error(`${TAG13} op=authz-deny route=${op} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
5609
+ console.error(`${TAG14} op=authz-deny route=${op} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
5531
5610
  return c.json({ ok: false, error: "Not authorized. The WhatsApp connection and its settings are house-scoped; this session may only act on its own account." }, 403);
5532
5611
  }
5533
5612
  function selfOrHouseScopeDenial(c, targetAccountId, op) {
5534
5613
  const { decision, callerAccountId, houseAdminScope } = evaluateCallerScope(c, targetAccountId);
5535
5614
  if (decision.authorized) {
5536
- console.error(`${TAG13} op=authz-ok route=${op} target=${targetAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
5615
+ console.error(`${TAG14} op=authz-ok route=${op} target=${targetAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
5537
5616
  return null;
5538
5617
  }
5539
- console.error(`${TAG13} op=authz-deny route=${op} target=${targetAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
5618
+ console.error(`${TAG14} op=authz-deny route=${op} target=${targetAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
5540
5619
  return c.json({ ok: false, error: "Not authorized. This session may only pair or manage its own account." }, 403);
5541
5620
  }
5542
5621
  var app2 = new Hono();
@@ -5556,7 +5635,7 @@ app2.get("/status", (c) => {
5556
5635
  dispatchInbound: shouldDispatchInbound(cfg, a.accountId)
5557
5636
  }));
5558
5637
  const summary = accounts.map((a) => `${a.accountId}:${a.connected ? "up" : a.linkedUnconfigured ? "linked-unconfigured" : "down"}:${a.dispatchInbound ? "dispatch" : "observe"}`).join(", ");
5559
- console.error(`${TAG13} status accounts=${accounts.length} [${summary}]`);
5638
+ console.error(`${TAG14} status accounts=${accounts.length} [${summary}]`);
5560
5639
  const reachableAccountIds = [
5561
5640
  .../* @__PURE__ */ new Set([...listStoredAccountIds(), ...listConnectionPlatformAccountIds()])
5562
5641
  ];
@@ -5565,11 +5644,11 @@ app2.get("/status", (c) => {
5565
5644
  reachableAccountIds
5566
5645
  });
5567
5646
  if (!storeKeyReconcile.ok) {
5568
- console.warn(`${TAG13} store-key-drift orphanLiveKeys=[${storeKeyReconcile.orphanLiveKeys.join(",")}] \u2014 in-memory cache keyed by a value with no disk account; read tools will miss`);
5647
+ console.warn(`${TAG14} store-key-drift orphanLiveKeys=[${storeKeyReconcile.orphanLiveKeys.join(",")}] \u2014 in-memory cache keyed by a value with no disk account; read tools will miss`);
5569
5648
  }
5570
5649
  return c.json({ accounts, storeKeyReconcile });
5571
5650
  } catch (err) {
5572
- console.error(`${TAG13} status error: ${String(err)}`);
5651
+ console.error(`${TAG14} status error: ${String(err)}`);
5573
5652
  return c.json({ error: String(err) }, 500);
5574
5653
  }
5575
5654
  });
@@ -5587,10 +5666,10 @@ app2.post("/login/start", async (c) => {
5587
5666
  const authDir = join9(MAXY_DIR, "credentials", "whatsapp", accountId);
5588
5667
  const accountDir = resolveAccount()?.accountDir ?? null;
5589
5668
  const result = await startLogin({ accountId, authDir, phone, accountDir, force });
5590
- console.error(`${TAG13} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
5669
+ console.error(`${TAG14} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
5591
5670
  return c.json(result);
5592
5671
  } catch (err) {
5593
- console.error(`${TAG13} login/start error: ${String(err)}`);
5672
+ console.error(`${TAG14} login/start error: ${String(err)}`);
5594
5673
  return c.json({ error: String(err) }, 500);
5595
5674
  }
5596
5675
  });
@@ -5602,7 +5681,7 @@ app2.post("/login/wait", async (c) => {
5602
5681
  if (denial) return denial;
5603
5682
  const timeoutMs = body.timeoutMs ?? 6e4;
5604
5683
  const result = await waitForLogin({ accountId, timeoutMs });
5605
- console.error(`${TAG13} login/wait result account=${accountId} connected=${result.connected}${result.selfPhone ? ` phone=${result.selfPhone}` : ""} configPersisted=${result.configPersisted}`);
5684
+ console.error(`${TAG14} login/wait result account=${accountId} connected=${result.connected}${result.selfPhone ? ` phone=${result.selfPhone}` : ""} configPersisted=${result.configPersisted}`);
5606
5685
  return c.json({
5607
5686
  connected: result.connected,
5608
5687
  message: result.message,
@@ -5610,7 +5689,7 @@ app2.post("/login/wait", async (c) => {
5610
5689
  configPersisted: result.configPersisted
5611
5690
  });
5612
5691
  } catch (err) {
5613
- console.error(`${TAG13} login/wait error: ${String(err)}`);
5692
+ console.error(`${TAG14} login/wait error: ${String(err)}`);
5614
5693
  return c.json({ error: String(err) }, 500);
5615
5694
  }
5616
5695
  });
@@ -5623,7 +5702,7 @@ app2.post("/disconnect", async (c) => {
5623
5702
  await stopConnection(accountId);
5624
5703
  return c.json({ disconnected: true, accountId });
5625
5704
  } catch (err) {
5626
- console.error(`${TAG13} disconnect error: ${String(err)}`);
5705
+ console.error(`${TAG14} disconnect error: ${String(err)}`);
5627
5706
  return c.json({ error: String(err) }, 500);
5628
5707
  }
5629
5708
  });
@@ -5636,7 +5715,7 @@ app2.post("/reconnect", async (c) => {
5636
5715
  await startConnection(accountId);
5637
5716
  return c.json({ reconnecting: true, accountId });
5638
5717
  } catch (err) {
5639
- console.error(`${TAG13} reconnect error: ${String(err)}`);
5718
+ console.error(`${TAG14} reconnect error: ${String(err)}`);
5640
5719
  return c.json({ error: String(err) }, 500);
5641
5720
  }
5642
5721
  });
@@ -5660,7 +5739,7 @@ app2.post("/config", async (c) => {
5660
5739
  const acct = resolveAccount();
5661
5740
  if (!acct) return c.json({ ok: false, error: "No account configured." }, 500);
5662
5741
  const result = setDispatchInbound(acct.accountDir, target, body.dispatchInbound);
5663
- console.error(`${TAG13} config action=set-dispatch-inbound account=${target} dispatchInbound=${body.dispatchInbound} ok=${result.ok}`);
5742
+ console.error(`${TAG14} config action=set-dispatch-inbound account=${target} dispatchInbound=${body.dispatchInbound} ok=${result.ok}`);
5664
5743
  return c.json(result, result.ok ? 200 : 400);
5665
5744
  }
5666
5745
  const denial = houseSocketScopeDenial(c, `config action=${action}`);
@@ -5676,7 +5755,7 @@ app2.post("/config", async (c) => {
5676
5755
  }
5677
5756
  const result = addAdminPhone(account.accountDir, phone);
5678
5757
  const reasonTail = !result.ok && result.reason ? ` reason=${result.reason}` : "";
5679
- console.error(`${TAG13} config action=add-admin-phone accountId=${account.accountId} phone=${phone} ok=${result.ok}${reasonTail}`);
5758
+ console.error(`${TAG14} config action=add-admin-phone accountId=${account.accountId} phone=${phone} ok=${result.ok}${reasonTail}`);
5680
5759
  return c.json(result, result.ok ? 200 : 400);
5681
5760
  }
5682
5761
  case "remove-admin-phone": {
@@ -5684,12 +5763,12 @@ app2.post("/config", async (c) => {
5684
5763
  return c.json({ ok: false, error: 'Missing required field "phone".' }, 400);
5685
5764
  }
5686
5765
  const result = removeAdminPhone(account.accountDir, phone);
5687
- console.error(`${TAG13} config action=remove-admin-phone phone=${phone} ok=${result.ok}`);
5766
+ console.error(`${TAG14} config action=remove-admin-phone phone=${phone} ok=${result.ok}`);
5688
5767
  return c.json(result, result.ok ? 200 : 400);
5689
5768
  }
5690
5769
  case "list-admin-phones": {
5691
5770
  const phones = readAdminPhones(account.accountDir);
5692
- console.error(`${TAG13} config action=list-admin-phones count=${phones.length}`);
5771
+ console.error(`${TAG14} config action=list-admin-phones count=${phones.length}`);
5693
5772
  return c.json({ ok: true, phones });
5694
5773
  }
5695
5774
  case "add-account-manager": {
@@ -5702,7 +5781,7 @@ app2.post("/config", async (c) => {
5702
5781
  const managerMode = mode === "passive" ? "passive" : "active";
5703
5782
  const result = setAccountManager(account.accountDir, phone, managesAccount, managerMode);
5704
5783
  const managerReasonTail = !result.ok && result.reason ? ` reason=${result.reason}` : "";
5705
- console.error(`${TAG13} config action=add-account-manager phone=${phone} managesAccount=${managesAccount} mode=${managerMode} ok=${result.ok}${managerReasonTail}`);
5784
+ console.error(`${TAG14} config action=add-account-manager phone=${phone} managesAccount=${managesAccount} mode=${managerMode} ok=${result.ok}${managerReasonTail}`);
5706
5785
  return c.json(result, result.ok ? 200 : 400);
5707
5786
  }
5708
5787
  case "remove-account-manager": {
@@ -5710,12 +5789,12 @@ app2.post("/config", async (c) => {
5710
5789
  return c.json({ ok: false, error: 'Missing required field "phone".' }, 400);
5711
5790
  }
5712
5791
  const result = clearAccountManager(account.accountDir, phone);
5713
- console.error(`${TAG13} config action=remove-account-manager phone=${phone} ok=${result.ok}`);
5792
+ console.error(`${TAG14} config action=remove-account-manager phone=${phone} ok=${result.ok}`);
5714
5793
  return c.json(result, result.ok ? 200 : 400);
5715
5794
  }
5716
5795
  case "list-account-managers": {
5717
5796
  const accountManagers = readAccountManagers(account.accountDir);
5718
- console.error(`${TAG13} config action=list-account-managers count=${Object.keys(accountManagers).length}`);
5797
+ console.error(`${TAG14} config action=list-account-managers count=${Object.keys(accountManagers).length}`);
5719
5798
  return c.json({ ok: true, accountManagers });
5720
5799
  }
5721
5800
  case "set-public-agent": {
@@ -5723,13 +5802,13 @@ app2.post("/config", async (c) => {
5723
5802
  return c.json({ ok: false, error: 'Missing required field "slug" (the agent directory name, e.g. "my-agent").' }, 400);
5724
5803
  }
5725
5804
  const result = setPublicAgent(account.accountDir, slug);
5726
- console.error(`${TAG13} config action=set-public-agent slug=${slug} ok=${result.ok}`);
5805
+ console.error(`${TAG14} config action=set-public-agent slug=${slug} ok=${result.ok}`);
5727
5806
  return c.json(result, result.ok ? 200 : 400);
5728
5807
  }
5729
5808
  case "get-public-agent": {
5730
5809
  const targetAccount = typeof accountId === "string" && accountId.trim() ? accountId.trim() : "default";
5731
5810
  const resolved = resolvePublicAgent(account.accountDir, { accountId: targetAccount });
5732
- console.error(`${TAG13} config action=get-public-agent accountId=${targetAccount} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
5811
+ console.error(`${TAG14} config action=get-public-agent accountId=${targetAccount} slug=${resolved?.slug ?? "none"} source=${resolved?.source ?? "none"}`);
5733
5812
  return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
5734
5813
  }
5735
5814
  case "list-public-agents": {
@@ -5746,26 +5825,26 @@ app2.post("/config", async (c) => {
5746
5825
  const config = JSON.parse(readFileSync7(configPath2, "utf-8"));
5747
5826
  agents.push({ slug: entry.name, displayName: config.displayName ?? entry.name });
5748
5827
  } catch {
5749
- console.error(`${TAG13} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
5828
+ console.error(`${TAG14} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
5750
5829
  }
5751
5830
  }
5752
5831
  } catch (err) {
5753
- console.error(`${TAG13} config action=list-public-agents error="failed to scan agents directory: ${String(err)}"`);
5832
+ console.error(`${TAG14} config action=list-public-agents error="failed to scan agents directory: ${String(err)}"`);
5754
5833
  }
5755
5834
  }
5756
- console.error(`${TAG13} config action=list-public-agents count=${agents.length}`);
5835
+ console.error(`${TAG14} config action=list-public-agents count=${agents.length}`);
5757
5836
  return c.json({ ok: true, agents });
5758
5837
  }
5759
5838
  case "schema": {
5760
5839
  const text = serializeWhatsAppSchema();
5761
- console.error(`${TAG13} config action=schema`);
5840
+ console.error(`${TAG14} config action=schema`);
5762
5841
  return c.json({ ok: true, text });
5763
5842
  }
5764
5843
  case "list-groups": {
5765
5844
  const groupAccountId = accountId ?? "default";
5766
5845
  const groupRes = resolveSocket(groupAccountId);
5767
5846
  if (!groupRes.ok) {
5768
- console.error(`${TAG13} config action=list-groups error="${formatSocketResolutionReason(groupRes)}" accountId=${groupAccountId}`);
5847
+ console.error(`${TAG14} config action=list-groups error="${formatSocketResolutionReason(groupRes)}" accountId=${groupAccountId}`);
5769
5848
  return c.json({ ok: false, error: formatSocketResolutionMessage(groupRes, groupAccountId) });
5770
5849
  }
5771
5850
  const sock = groupRes.sock;
@@ -5776,10 +5855,10 @@ app2.post("/config", async (c) => {
5776
5855
  name: g.subject ?? g.id,
5777
5856
  participantCount: Array.isArray(g.participants) ? g.participants.length : 0
5778
5857
  }));
5779
- console.error(`${TAG13} config action=list-groups count=${groups.length} accountId=${groupAccountId}`);
5858
+ console.error(`${TAG14} config action=list-groups count=${groups.length} accountId=${groupAccountId}`);
5780
5859
  return c.json({ ok: true, groups });
5781
5860
  } catch (err) {
5782
- console.error(`${TAG13} config action=list-groups error="${String(err)}" accountId=${groupAccountId}`);
5861
+ console.error(`${TAG14} config action=list-groups error="${String(err)}" accountId=${groupAccountId}`);
5783
5862
  return c.json({ ok: false, error: `Failed to fetch groups: ${String(err)}` });
5784
5863
  }
5785
5864
  }
@@ -5789,12 +5868,12 @@ app2.post("/config", async (c) => {
5789
5868
  }
5790
5869
  const result = updateConfig(account.accountDir, fields);
5791
5870
  const fieldNames = Object.keys(fields);
5792
- console.error(`${TAG13} config action=update-config fields=[${fieldNames.join(",")}] ok=${result.ok}`);
5871
+ console.error(`${TAG14} config action=update-config fields=[${fieldNames.join(",")}] ok=${result.ok}`);
5793
5872
  return c.json(result, result.ok ? 200 : 400);
5794
5873
  }
5795
5874
  case "get-config": {
5796
5875
  const waConfig = getConfig(account.accountDir);
5797
- console.error(`${TAG13} config action=get-config`);
5876
+ console.error(`${TAG14} config action=get-config`);
5798
5877
  return c.json({ ok: true, config: waConfig });
5799
5878
  }
5800
5879
  default:
@@ -5804,7 +5883,7 @@ app2.post("/config", async (c) => {
5804
5883
  );
5805
5884
  }
5806
5885
  } catch (err) {
5807
- console.error(`${TAG13} config error: ${String(err)}`);
5886
+ console.error(`${TAG14} config error: ${String(err)}`);
5808
5887
  return c.json({ ok: false, error: String(err) }, 500);
5809
5888
  }
5810
5889
  });
@@ -5825,7 +5904,7 @@ app2.post("/send-document", async (c) => {
5825
5904
  recordRouteDocumentOutbound(to, filePath);
5826
5905
  return c.json({ success: true, messageId: result.messageId });
5827
5906
  } catch (err) {
5828
- console.error(`${TAG13} send-document error: ${String(err)}`);
5907
+ console.error(`${TAG14} send-document error: ${String(err)}`);
5829
5908
  return c.json({ error: String(err) }, 500);
5830
5909
  }
5831
5910
  });
@@ -5870,7 +5949,7 @@ app2.post("/send-admin", async (c) => {
5870
5949
  console.error(`[whatsapp:outbound] op=send-admin-ok via=${via} to=${phone}`);
5871
5950
  return c.json({ success: true, messageId: result.messageId });
5872
5951
  } catch (err) {
5873
- console.error(`${TAG13} send-admin error: ${String(err)}`);
5952
+ console.error(`${TAG14} send-admin error: ${String(err)}`);
5874
5953
  return c.json({ error: String(err) }, 500);
5875
5954
  }
5876
5955
  });
@@ -5930,7 +6009,7 @@ app2.post("/reply", async (c) => {
5930
6009
  console.error(`[whatsapp:observe] op=reply-sent sendId=${sendId} account=${accountId} socket=${res.accountId} waMessageId=${sent.messageId ?? ""}`);
5931
6010
  return c.json({ success: true, messageId: sent.messageId });
5932
6011
  } catch (err) {
5933
- console.error(`${TAG13} reply error: ${String(err)}`);
6012
+ console.error(`${TAG14} reply error: ${String(err)}`);
5934
6013
  return c.json({ error: String(err) }, 500);
5935
6014
  }
5936
6015
  });
@@ -5940,11 +6019,11 @@ app2.get("/activity", (c) => {
5940
6019
  const result = getChannelActivity(accountId);
5941
6020
  const total = result.accounts.reduce((sum, a) => sum + a.total, 0);
5942
6021
  console.error(
5943
- `${TAG13} activity accounts=${result.accounts.length} total=${total} recentEvents=${result.recentEvents.length}` + (accountId ? ` filter=${accountId}` : "")
6022
+ `${TAG14} activity accounts=${result.accounts.length} total=${total} recentEvents=${result.recentEvents.length}` + (accountId ? ` filter=${accountId}` : "")
5944
6023
  );
5945
6024
  return c.json(result);
5946
6025
  } catch (err) {
5947
- console.error(`${TAG13} activity error: ${String(err)}`);
6026
+ console.error(`${TAG14} activity error: ${String(err)}`);
5948
6027
  return c.json({ error: String(err) }, 500);
5949
6028
  }
5950
6029
  });
@@ -5972,10 +6051,10 @@ app2.get("/conversations", (c) => {
5972
6051
  };
5973
6052
  });
5974
6053
  conversations.sort((a, b) => (b.lastMessageTimestamp ?? 0) - (a.lastMessageTimestamp ?? 0));
5975
- console.error(`${TAG13} conversations requested=${requestedAccountId} caller=${callerAccountId ?? "none"} account=${storeAccountId} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${allConversations.size > 0} count=${conversations.length}`);
6054
+ console.error(`${TAG14} conversations requested=${requestedAccountId} caller=${callerAccountId ?? "none"} account=${storeAccountId} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${allConversations.size > 0} count=${conversations.length}`);
5976
6055
  return c.json({ conversations });
5977
6056
  } catch (err) {
5978
- console.error(`${TAG13} conversations error: ${String(err)}`);
6057
+ console.error(`${TAG14} conversations error: ${String(err)}`);
5979
6058
  return c.json({ error: String(err) }, 500);
5980
6059
  }
5981
6060
  });
@@ -6028,10 +6107,10 @@ app2.get("/messages", (c) => {
6028
6107
  ...reactions && reactions.length > 0 ? { reactions } : {}
6029
6108
  };
6030
6109
  });
6031
- console.error(`${TAG13} messages requested=${requestedAccountId} caller=${callerAccountId ?? "none"} account=${storeAccountId} jid=${jid} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${storeMessages.length > 0} limit=${effectiveLimit ?? "all"} returned=${messages.length} withAttachments=${withAttachments}`);
6110
+ console.error(`${TAG14} messages requested=${requestedAccountId} caller=${callerAccountId ?? "none"} account=${storeAccountId} jid=${jid} projected=${projecting} storeAccount=${projecting ? storeAccountId : "self"} managerPhonesBound=${managerPhonesBound} storeKeyFound=${storeMessages.length > 0} limit=${effectiveLimit ?? "all"} returned=${messages.length} withAttachments=${withAttachments}`);
6032
6111
  return c.json({ messages });
6033
6112
  } catch (err) {
6034
- console.error(`${TAG13} messages error: ${String(err)}`);
6113
+ console.error(`${TAG14} messages error: ${String(err)}`);
6035
6114
  return c.json({ error: String(err) }, 500);
6036
6115
  }
6037
6116
  });
@@ -6133,7 +6212,7 @@ app2.get("/conversation-graph-state", async (c) => {
6133
6212
  ms
6134
6213
  });
6135
6214
  } catch (err) {
6136
- console.error(`${TAG13} conversation-graph-state error: ${String(err)}`);
6215
+ console.error(`${TAG14} conversation-graph-state error: ${String(err)}`);
6137
6216
  return c.json({ error: String(err) }, 500);
6138
6217
  }
6139
6218
  });
@@ -6145,12 +6224,12 @@ app2.get("/group-info", async (c) => {
6145
6224
  return c.json({ error: "Missing required parameter: jid" }, 400);
6146
6225
  }
6147
6226
  if (!isGroupJid(jid)) {
6148
- console.error(`${TAG13} group-info error="not a group JID" jid=${jid} account=${accountId}`);
6227
+ console.error(`${TAG14} group-info error="not a group JID" jid=${jid} account=${accountId}`);
6149
6228
  return c.json({ error: `"${jid}" is not a group JID. Group JIDs end with @g.us.` }, 400);
6150
6229
  }
6151
6230
  const res = resolveSocket(accountId);
6152
6231
  if (!res.ok) {
6153
- console.error(`${TAG13} group-info error="${formatSocketResolutionReason(res)}" account=${accountId}`);
6232
+ console.error(`${TAG14} group-info error="${formatSocketResolutionReason(res)}" account=${accountId}`);
6154
6233
  return c.json({ error: formatSocketResolutionMessage(res, accountId) }, 400);
6155
6234
  }
6156
6235
  const sock = res.sock;
@@ -6164,10 +6243,10 @@ app2.get("/group-info", async (c) => {
6164
6243
  participantCount: meta.participants.length,
6165
6244
  participants: meta.participants.map((p) => ({ jid: p.id, admin: p.admin ?? null }))
6166
6245
  };
6167
- console.error(`${TAG13} group-info jid=${jid} subject="${meta.subject}" participants=${meta.participants.length} account=${accountId}`);
6246
+ console.error(`${TAG14} group-info jid=${jid} subject="${meta.subject}" participants=${meta.participants.length} account=${accountId}`);
6168
6247
  return c.json(result);
6169
6248
  } catch (err) {
6170
- console.error(`${TAG13} group-info error="${String(err)}" jid=${jid} account=${accountId}`);
6249
+ console.error(`${TAG14} group-info error="${String(err)}" jid=${jid} account=${accountId}`);
6171
6250
  return c.json({ error: `Failed to fetch group info: ${String(err)}` }, 500);
6172
6251
  }
6173
6252
  });
@@ -7096,7 +7175,7 @@ function resolveExposedDirs(schemaText, exposeFolders = []) {
7096
7175
  }
7097
7176
 
7098
7177
  // server/portal-uploads-pull.ts
7099
- var TAG14 = "[portal-pull]";
7178
+ var TAG15 = "[portal-pull]";
7100
7179
  var PORTAL_UPLOADS_PULL_INTERVAL_MS = 6e4;
7101
7180
  var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
7102
7181
  function safeSegment(s) {
@@ -7157,17 +7236,17 @@ async function pullAccount(opts) {
7157
7236
  }
7158
7237
  const dest = resolveDestination(accountDir, row, exposed);
7159
7238
  const idField = dest.ok || dest.reason !== "bad-fileid" ? ` fileId=${row.fileId}` : "";
7160
- const head = `${TAG14} op=claim account=${accountId}${idField} bytes=${row.size}`;
7239
+ const head = `${TAG15} op=claim account=${accountId}${idField} bytes=${row.size}`;
7161
7240
  if (!dest.ok) {
7162
7241
  failed++;
7163
7242
  log2(
7164
- `${TAG14} op=route account=${accountId}${idField} target="${row.targetPath}" result=refused reason=${dest.reason}`
7243
+ `${TAG15} op=route account=${accountId}${idField} target="${row.targetPath}" result=refused reason=${dest.reason}`
7165
7244
  );
7166
7245
  log2(`${head} result=${dest.reason}`);
7167
7246
  continue;
7168
7247
  }
7169
7248
  log2(
7170
- `${TAG14} op=route account=${accountId}${idField} target="${row.targetPath}" result=${row.targetPath ? "exposed" : "default"}`
7249
+ `${TAG15} op=route account=${accountId}${idField} target="${row.targetPath}" result=${row.targetPath ? "exposed" : "default"}`
7171
7250
  );
7172
7251
  let bytes;
7173
7252
  try {
@@ -7180,7 +7259,7 @@ async function pullAccount(opts) {
7180
7259
  const finalPath = nextFreePath(dest.final);
7181
7260
  if (finalPath !== dest.final) {
7182
7261
  log2(
7183
- `${TAG14} op=collision account=${accountId}${idField} suffix="${basename3(finalPath)}" result=suffixed`
7262
+ `${TAG15} op=collision account=${accountId}${idField} suffix="${basename3(finalPath)}" result=suffixed`
7184
7263
  );
7185
7264
  }
7186
7265
  const relPath = relative(resolve8(accountDir), finalPath).split(sep2).join("/");
@@ -7224,7 +7303,7 @@ async function pullAccount(opts) {
7224
7303
  deleteErr = err instanceof Error ? err.message : String(err);
7225
7304
  }
7226
7305
  log2(
7227
- `${TAG14} op=move account=${accountId}${idField} r2Deleted=${r2Deleted}` + (deleteErr ? ` err="${deleteErr}"` : "")
7306
+ `${TAG15} op=move account=${accountId}${idField} r2Deleted=${r2Deleted}` + (deleteErr ? ` err="${deleteErr}"` : "")
7228
7307
  );
7229
7308
  pulled++;
7230
7309
  log2(`${head} result=written`);
@@ -7234,10 +7313,10 @@ async function pullAccount(opts) {
7234
7313
  async function withdrawRow(opts) {
7235
7314
  const { accountDir, accountId, dbName, exposed, row, cf, log: log2 } = opts;
7236
7315
  if (!UUID.test(row.fileId)) {
7237
- log2(`${TAG14} op=delete-propagate account=${accountId} result=bad-fileid`);
7316
+ log2(`${TAG15} op=delete-propagate account=${accountId} result=bad-fileid`);
7238
7317
  return false;
7239
7318
  }
7240
- const head = `${TAG14} op=delete-propagate account=${accountId} fileId=${row.fileId}`;
7319
+ const head = `${TAG15} op=delete-propagate account=${accountId} fileId=${row.fileId}`;
7241
7320
  const segments = row.devicePath.split("/");
7242
7321
  if (!row.devicePath || !segments.every(safeSegment) || !exposedOrOwnUploads(segments, exposed, row.ownerId)) {
7243
7322
  log2(`${head} removed=false result=bad-path`);
@@ -7346,7 +7425,7 @@ async function runPortalUploadsPull(root) {
7346
7425
  await cf.d1Query(portal.portalDbName, pendingSelect(portal))
7347
7426
  );
7348
7427
  if (malformed > 0) {
7349
- console.error(`${TAG14} op=malformed account=${portal.accountId} rows=${malformed}`);
7428
+ console.error(`${TAG15} op=malformed account=${portal.accountId} rows=${malformed}`);
7350
7429
  }
7351
7430
  if (rows.length === 0) continue;
7352
7431
  const accountDir = join11(accountsRoot, portal.accountId);
@@ -7366,12 +7445,12 @@ async function runPortalUploadsPull(root) {
7366
7445
  failedTotal += r.failed;
7367
7446
  withdrawnTotal += r.withdrawn;
7368
7447
  console.error(
7369
- `${TAG14} op=done account=${portal.accountId} pulled=${r.pulled} withdrawn=${r.withdrawn} failed=${r.failed}`
7448
+ `${TAG15} op=done account=${portal.accountId} pulled=${r.pulled} withdrawn=${r.withdrawn} failed=${r.failed}`
7370
7449
  );
7371
7450
  } catch (err) {
7372
7451
  failedTotal++;
7373
7452
  console.error(
7374
- `${TAG14} op=failed account=${portal.accountId} err="${err instanceof Error ? err.message : String(err)}"`
7453
+ `${TAG15} op=failed account=${portal.accountId} err="${err instanceof Error ? err.message : String(err)}"`
7375
7454
  );
7376
7455
  }
7377
7456
  }
@@ -7446,7 +7525,7 @@ function createD1Client(opts) {
7446
7525
  }
7447
7526
 
7448
7527
  // ../plugins/cloudflare/bin/portal-index-push.mjs
7449
- var TAG15 = "[portal-index]";
7528
+ var TAG16 = "[portal-index]";
7450
7529
  function readEnvFile(path) {
7451
7530
  const out = {};
7452
7531
  if (!existsSync8(path)) return out;
@@ -7511,17 +7590,17 @@ async function pushAccount(opts) {
7511
7590
  const exposeFolders = Array.isArray(opts.exposeFolders) ? opts.exposeFolders : [];
7512
7591
  const r = resolveExposedDirs(schemaText, exposeFolders);
7513
7592
  log2(
7514
- `${TAG15} op=resolve account=${accountId} schemaPresent=${r.schemaPresent} allowed=${r.allowed.length} domainBuckets=${r.domainBuckets.join(",") || "none"} extraFolders=${exposeFolders.length} exposed=${r.exposed.join(",") || "none"}`
7593
+ `${TAG16} op=resolve account=${accountId} schemaPresent=${r.schemaPresent} allowed=${r.allowed.length} domainBuckets=${r.domainBuckets.join(",") || "none"} extraFolders=${exposeFolders.length} exposed=${r.exposed.join(",") || "none"}`
7515
7594
  );
7516
7595
  for (const c of r.collisions) {
7517
- log2(`${TAG15} op=collision account=${accountId} dir=${c} claimedBy=plugin-owned`);
7596
+ log2(`${TAG16} op=collision account=${accountId} dir=${c} claimedBy=plugin-owned`);
7518
7597
  }
7519
7598
  if (opts.previousExposed) {
7520
7599
  const added = r.exposed.filter((d) => !opts.previousExposed.includes(d));
7521
7600
  const removed = opts.previousExposed.filter((d) => !r.exposed.includes(d));
7522
7601
  if (added.length || removed.length) {
7523
7602
  log2(
7524
- `${TAG15} op=exposed-changed account=${accountId} added=${added.join(",") || "none"} removed=${removed.join(",") || "none"}`
7603
+ `${TAG16} op=exposed-changed account=${accountId} added=${added.join(",") || "none"} removed=${removed.join(",") || "none"}`
7525
7604
  );
7526
7605
  }
7527
7606
  }
@@ -7545,7 +7624,7 @@ async function pushAccount(opts) {
7545
7624
  [accountId, row.relPath, row.sizeBytes, row.modifiedAt, nowIso, row.isDir ? 1 : 0, next]
7546
7625
  );
7547
7626
  }
7548
- log2(`${TAG15} op=stage account=${accountId} generation=${next} inserted=${rows.length}`);
7627
+ log2(`${TAG16} op=stage account=${accountId} generation=${next} inserted=${rows.length}`);
7549
7628
  await client.query(
7550
7629
  "INSERT INTO directory_state (accountId, currentGeneration) VALUES (?, ?) ON CONFLICT (accountId) DO UPDATE SET currentGeneration = excluded.currentGeneration WHERE excluded.currentGeneration > directory_state.currentGeneration",
7551
7630
  [accountId, next]
@@ -7557,7 +7636,7 @@ async function pushAccount(opts) {
7557
7636
  const pointer = Number(flipped[0]?.currentGeneration ?? 0);
7558
7637
  if (pointer !== next) {
7559
7638
  log2(
7560
- `${TAG15} op=stage-contended account=${accountId} generation=${next} pointer=${pointer} action=superseded`
7639
+ `${TAG16} op=stage-contended account=${accountId} generation=${next} pointer=${pointer} action=superseded`
7561
7640
  );
7562
7641
  return {
7563
7642
  exposed: r.exposed,
@@ -7567,7 +7646,7 @@ async function pushAccount(opts) {
7567
7646
  superseded: true
7568
7647
  };
7569
7648
  }
7570
- log2(`${TAG15} op=flip account=${accountId} generation=${next}`);
7649
+ log2(`${TAG16} op=flip account=${accountId} generation=${next}`);
7571
7650
  try {
7572
7651
  await client.query("DELETE FROM directory WHERE accountId = ? AND generation < ?", [
7573
7652
  accountId,
@@ -7575,7 +7654,7 @@ async function pushAccount(opts) {
7575
7654
  ]);
7576
7655
  } catch (err) {
7577
7656
  log2(
7578
- `${TAG15} op=sweep account=${accountId} generation=${next} result=failed err="${err instanceof Error ? err.message : String(err)}"`
7657
+ `${TAG16} op=sweep account=${accountId} generation=${next} result=failed err="${err instanceof Error ? err.message : String(err)}"`
7579
7658
  );
7580
7659
  }
7581
7660
  const check = await client.query(
@@ -7583,7 +7662,7 @@ async function pushAccount(opts) {
7583
7662
  [accountId]
7584
7663
  );
7585
7664
  const after = Number(check[0]?.n ?? -1);
7586
- log2(`${TAG15} op=verify account=${accountId} rowsAfter=${after} expected=${rows.length}`);
7665
+ log2(`${TAG16} op=verify account=${accountId} rowsAfter=${after} expected=${rows.length}`);
7587
7666
  return { exposed: r.exposed, rows: rows.length, schemaPresent: true, generation: next };
7588
7667
  }
7589
7668
  function stateFilePath(platformRoot5) {
@@ -7604,7 +7683,7 @@ function recordSuccess(platformRoot5, accountId, entry) {
7604
7683
  writeFileSync5(path, JSON.stringify(state, null, 1));
7605
7684
  } catch (err) {
7606
7685
  console.error(
7607
- `${TAG15} op=state-write-failed account=${accountId} path="${path}" err="${err instanceof Error ? err.message : String(err)}"`
7686
+ `${TAG16} op=state-write-failed account=${accountId} path="${path}" err="${err instanceof Error ? err.message : String(err)}"`
7608
7687
  );
7609
7688
  }
7610
7689
  }
@@ -7628,7 +7707,7 @@ async function portalAccounts(accountsRoot) {
7628
7707
  const exposeFolders = Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
7629
7708
  out.push({ accountDir, accountId, dbName: cfg.portalDbName, exposeFolders });
7630
7709
  } else {
7631
- console.error(`${TAG15} op=skip account=${accountId} reason=no-portalDbName`);
7710
+ console.error(`${TAG16} op=skip account=${accountId} reason=no-portalDbName`);
7632
7711
  }
7633
7712
  } catch {
7634
7713
  }
@@ -7656,7 +7735,7 @@ function resolveCloudflareCredentials(platformRoot5) {
7656
7735
  async function pushAllAccounts(platformRoot5) {
7657
7736
  const accountsRoot = resolve9(platformRoot5, "..", "data", "accounts");
7658
7737
  const targets = await portalAccounts(accountsRoot);
7659
- console.error(`${TAG15} op=enumerate accountsRoot="${accountsRoot}" accounts=${targets.length}`);
7738
+ console.error(`${TAG16} op=enumerate accountsRoot="${accountsRoot}" accounts=${targets.length}`);
7660
7739
  if (targets.length === 0) return { accounts: 0, pushed: 0, failed: 0 };
7661
7740
  const cred = resolveCloudflareCredentials(platformRoot5);
7662
7741
  if ("error" in cred) {
@@ -7690,11 +7769,11 @@ async function runTargets(platformRoot5, cred, targets) {
7690
7769
  });
7691
7770
  }
7692
7771
  pushed++;
7693
- console.error(`${TAG15} op=done account=${t.accountId} rows=${r.rows}`);
7772
+ console.error(`${TAG16} op=done account=${t.accountId} rows=${r.rows}`);
7694
7773
  } catch (err) {
7695
7774
  failed++;
7696
7775
  console.error(
7697
- `${TAG15} op=failed account=${t.accountId} err="${err instanceof Error ? err.message : String(err)}"`
7776
+ `${TAG16} op=failed account=${t.accountId} err="${err instanceof Error ? err.message : String(err)}"`
7698
7777
  );
7699
7778
  }
7700
7779
  }
@@ -7703,7 +7782,7 @@ async function runTargets(platformRoot5, cred, targets) {
7703
7782
  async function main() {
7704
7783
  const platformRoot5 = process.env.PLATFORM_ROOT;
7705
7784
  if (!platformRoot5) {
7706
- console.error(`${TAG15} op=usage reason=no-platform-root PLATFORM_ROOT is required`);
7785
+ console.error(`${TAG16} op=usage reason=no-platform-root PLATFORM_ROOT is required`);
7707
7786
  process.exit(1);
7708
7787
  }
7709
7788
  if (process.argv.includes("--all-accounts")) {
@@ -7711,7 +7790,7 @@ async function main() {
7711
7790
  const r2 = await pushAllAccounts(platformRoot5);
7712
7791
  if (r2.failed > 0) process.exit(1);
7713
7792
  } catch (err) {
7714
- console.error(`${TAG15} op=skip reason=${err instanceof Error ? err.message : String(err)}`);
7793
+ console.error(`${TAG16} op=skip reason=${err instanceof Error ? err.message : String(err)}`);
7715
7794
  process.exit(1);
7716
7795
  }
7717
7796
  return;
@@ -7720,12 +7799,12 @@ async function main() {
7720
7799
  const accountId = arg("--account");
7721
7800
  const dbName = arg("--db");
7722
7801
  if (!accountDir || !accountId || !dbName) {
7723
- console.error(`${TAG15} op=usage --account-dir <dir> --account <id> --db <name>`);
7802
+ console.error(`${TAG16} op=usage --account-dir <dir> --account <id> --db <name>`);
7724
7803
  process.exit(1);
7725
7804
  }
7726
7805
  const cred = resolveCloudflareCredentials(platformRoot5);
7727
7806
  if ("error" in cred) {
7728
- console.error(`${TAG15} op=skip reason=${cred.error}`);
7807
+ console.error(`${TAG16} op=skip reason=${cred.error}`);
7729
7808
  process.exit(1);
7730
7809
  }
7731
7810
  const r = await runTargets(platformRoot5, cred, [
@@ -8751,11 +8830,11 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
8751
8830
  } catch {
8752
8831
  return null;
8753
8832
  }
8754
- const basename16 = `${sessionId}.jsonl`;
8833
+ const basename17 = `${sessionId}.jsonl`;
8755
8834
  for (const slug of slugs) {
8756
- const live = join17(projectsRoot, slug, basename16);
8835
+ const live = join17(projectsRoot, slug, basename17);
8757
8836
  if (existsSync13(live)) return live;
8758
- const archived = join17(projectsRoot, slug, "archive", basename16);
8837
+ const archived = join17(projectsRoot, slug, "archive", basename17);
8759
8838
  if (existsSync13(archived)) return archived;
8760
8839
  }
8761
8840
  return null;
@@ -10031,6 +10110,80 @@ var session_reader_default = app6;
10031
10110
  // server/routes/operator-conversations.ts
10032
10111
  import { readFileSync as readFileSync16 } from "fs";
10033
10112
  import { basename as basename7, dirname as dirname8, join as join21 } from "path";
10113
+
10114
+ // app/lib/reader/operator-conversations.ts
10115
+ function operatorConvName(row) {
10116
+ if (row.isGroup === true) return row.chatName ?? row.title;
10117
+ const name = row.operatorName ?? row.chatName ?? row.whatsappName;
10118
+ const senderId = row.senderId != null && row.channel === "whatsapp" ? formatSenderPhone(row.senderId) : row.senderId;
10119
+ if (name) return senderId ? `${name} ${senderId}` : name;
10120
+ return senderId ?? row.title;
10121
+ }
10122
+ function operatorConvNameSource(row) {
10123
+ if (row.isGroup === true) return row.chatName ? "chatmeta" : "jid";
10124
+ if (row.operatorName) return "operator";
10125
+ if (row.chatName) return "chatmeta";
10126
+ if (row.whatsappName) return "inbound-pushname";
10127
+ if (row.senderId != null) return "counterparty-number";
10128
+ return "jid";
10129
+ }
10130
+
10131
+ // app/lib/reader/label-census.ts
10132
+ function selfPushNames(summaries) {
10133
+ const out = /* @__PURE__ */ new Set();
10134
+ for (const { first, last } of summaries.values()) {
10135
+ for (const r of [first, last]) {
10136
+ if (r.fromMe && r.senderName) out.add(r.senderName);
10137
+ }
10138
+ }
10139
+ return out;
10140
+ }
10141
+ function fallbackLabelSources(rows) {
10142
+ const out = [];
10143
+ for (const r of rows) {
10144
+ if (r.source !== "store") continue;
10145
+ const source = operatorConvNameSource(r);
10146
+ if (source === "chatmeta" || source === "operator") continue;
10147
+ out.push({ jid: r.remoteJid ?? r.title, source });
10148
+ }
10149
+ return out;
10150
+ }
10151
+ function buildLabelCensus(rows, selfNames) {
10152
+ const c = {
10153
+ chats: 0,
10154
+ withMeta: 0,
10155
+ groups: 0,
10156
+ groupsWithSubject: 0,
10157
+ labelledByMember: 0,
10158
+ dms: 0,
10159
+ namedDms: 0,
10160
+ labelledBySelfPushName: 0
10161
+ };
10162
+ for (const r of rows) {
10163
+ if (r.source !== "store") continue;
10164
+ c.chats += 1;
10165
+ if (r.chatName) c.withMeta += 1;
10166
+ const source = operatorConvNameSource(r);
10167
+ if (r.isGroup === true) {
10168
+ c.groups += 1;
10169
+ if (r.chatName) c.groupsWithSubject += 1;
10170
+ if (source === "inbound-pushname") c.labelledByMember += 1;
10171
+ } else {
10172
+ c.dms += 1;
10173
+ if (source === "operator" || source === "chatmeta" || source === "inbound-pushname") c.namedDms += 1;
10174
+ }
10175
+ const shown = operatorConvName(r);
10176
+ for (const self of selfNames) {
10177
+ if (shown === self || shown.startsWith(`${self} `)) {
10178
+ c.labelledBySelfPushName += 1;
10179
+ break;
10180
+ }
10181
+ }
10182
+ }
10183
+ return c;
10184
+ }
10185
+
10186
+ // server/routes/operator-conversations.ts
10034
10187
  var app7 = new Hono();
10035
10188
  app7.get("/conversations", requireAdminSession, async (c) => {
10036
10189
  const cacheKey = c.var.cacheKey;
@@ -10157,7 +10310,8 @@ app7.get("/conversations", requireAdminSession, async (c) => {
10157
10310
  ...r,
10158
10311
  operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
10159
10312
  }));
10160
- const storeRows = account ? buildStoreConversationRows(account.accountId, readConversationSummaries(account.accountId)) : [];
10313
+ const summaries = account ? readConversationSummaries(account.accountId) : /* @__PURE__ */ new Map();
10314
+ const storeRows = account ? buildStoreConversationRows(account.accountId, summaries, readChatMetadata(account.accountId)) : [];
10161
10315
  let houseId = null;
10162
10316
  if (multiAccount) {
10163
10317
  try {
@@ -10174,9 +10328,11 @@ app7.get("/conversations", requireAdminSession, async (c) => {
10174
10328
  const managerPhones = managerPhonesForAccount(readAccountManagers(houseAccount.accountDir), account.accountId);
10175
10329
  managerPhonesBound = managerPhones.length;
10176
10330
  if (managerPhones.length > 0) {
10177
- managedRows = buildStoreConversationRows(houseId, readConversationSummaries(houseId)).filter(
10178
- (r) => counterpartyBoundToSubAccount(managerPhones, r.senderId)
10179
- );
10331
+ managedRows = buildStoreConversationRows(
10332
+ houseId,
10333
+ readConversationSummaries(houseId),
10334
+ readChatMetadata(houseId)
10335
+ ).filter((r) => counterpartyBoundToSubAccount(managerPhones, r.senderId));
10180
10336
  }
10181
10337
  }
10182
10338
  }
@@ -10185,6 +10341,13 @@ app7.get("/conversations", requireAdminSession, async (c) => {
10185
10341
  );
10186
10342
  const adminScope = allStoreRows.filter((r) => r.scope === "admin").length;
10187
10343
  const publicScope = allStoreRows.length - adminScope;
10344
+ const census = buildLabelCensus(allStoreRows, selfPushNames(summaries));
10345
+ for (const f of fallbackLabelSources(allStoreRows)) {
10346
+ console.log(`[wa-label] op=row-label jid=${f.jid} source=${f.source} route=conversations`);
10347
+ }
10348
+ console.log(
10349
+ `[wa-label-census] route=conversations chats=${census.chats} withMeta=${census.withMeta} groups=${census.groups} groupsWithSubject=${census.groupsWithSubject} labelledByMember=${census.labelledByMember} dms=${census.dms} namedDms=${census.namedDms} labelledBySelfPushName=${census.labelledBySelfPushName}`
10350
+ );
10188
10351
  const sessionRowCount = sessionConversations.length;
10189
10352
  console.log(
10190
10353
  `[wa-reader] op=list pinnedAccount=${scopeAccountId?.slice(0, 8) ?? "null"} resolvedAccount=${account?.accountId.slice(0, 8) ?? "null"} multiAccount=${multiAccount} conversations=${sessionRowCount + allStoreRows.length} sessionRows=${sessionRowCount} storeRows=${allStoreRows.length} adminScope=${adminScope} publicScope=${publicScope} sessionRowsExcludedUntagged=${sessionRowsExcludedUntagged} houseResolved=${houseId ? houseId.slice(0, 8) : "null"} managerPhonesBound=${managerPhonesBound} managedStoreRows=${managedRows.length}`
@@ -10326,12 +10489,20 @@ app7.get("/conversations-all", requireAdminSession, async (c) => {
10326
10489
  const distinct = [...new Set(sessionRows.map((r) => r.senderId).filter((s) => !!s))];
10327
10490
  const resolved = await resolveOperatorNamesBySender(users, admins, distinct);
10328
10491
  const nameBySender = /* @__PURE__ */ new Map();
10329
- for (const senderId of distinct) nameBySender.set(senderId, resolved.get(senderId)?.name ?? null);
10492
+ for (const senderId of distinct) {
10493
+ const { name, reason } = resolved.get(senderId) ?? { name: null, reason: "no-binding" };
10494
+ if (reason) console.error(`[wa-reader] op=operator-unresolved senderId=${senderId} reason=${reason} route=conversations-all`);
10495
+ nameBySender.set(senderId, name);
10496
+ }
10330
10497
  const named = sessionRows.map((r) => ({
10331
10498
  ...r,
10332
10499
  operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
10333
10500
  }));
10334
- const storeRows = buildStoreConversationRows(account.accountId, readConversationSummaries(account.accountId));
10501
+ const storeRows = buildStoreConversationRows(
10502
+ account.accountId,
10503
+ readConversationSummaries(account.accountId),
10504
+ readChatMetadata(account.accountId)
10505
+ );
10335
10506
  perAccount.push({ isHouse, rows: [...named, ...storeRows] });
10336
10507
  }
10337
10508
  const houseAccount = validAccounts.find((a) => a.accountId === houseId) ?? null;
@@ -10346,6 +10517,17 @@ app7.get("/conversations-all", requireAdminSession, async (c) => {
10346
10517
  }
10347
10518
  const merged = tagAndMergeInstallConversations(perAccount);
10348
10519
  const conversations = dropHouseRowsOwnedBySubAccount(merged, subManagerPhones);
10520
+ const allSummaries = /* @__PURE__ */ new Map();
10521
+ for (const account of validAccounts) {
10522
+ for (const [jid, s] of readConversationSummaries(account.accountId)) allSummaries.set(`${account.accountId}:${jid}`, s);
10523
+ }
10524
+ const census = buildLabelCensus(conversations, selfPushNames(allSummaries));
10525
+ for (const f of fallbackLabelSources(conversations)) {
10526
+ console.log(`[wa-label] op=row-label jid=${f.jid} source=${f.source} route=conversations-all`);
10527
+ }
10528
+ console.log(
10529
+ `[wa-label-census] route=conversations-all chats=${census.chats} withMeta=${census.withMeta} groups=${census.groups} groupsWithSubject=${census.groupsWithSubject} labelledByMember=${census.labelledByMember} dms=${census.dms} namedDms=${census.namedDms} labelledBySelfPushName=${census.labelledBySelfPushName}`
10530
+ );
10349
10531
  const houseRows = conversations.filter((r) => r.isHouse).length;
10350
10532
  console.log(
10351
10533
  `[wa-reader] op=conversations-all accounts=${validAccounts.length} rows=${conversations.length} house=${houseRows} sub=${conversations.length - houseRows} deduped=${merged.length - conversations.length}`
@@ -10406,7 +10588,7 @@ function resolveOpenVisitorSession(rows, visitorId, agentSlug) {
10406
10588
 
10407
10589
  // server/routes/public-reader.ts
10408
10590
  var app8 = new Hono();
10409
- var TAG16 = "[public-webchat]";
10591
+ var TAG17 = "[public-webchat]";
10410
10592
  function parseAccessSessionId(cookieHeader) {
10411
10593
  if (!cookieHeader) return null;
10412
10594
  const part = cookieHeader.split(";").map((p) => p.trim()).find((p) => p.startsWith("__access_session="));
@@ -10454,7 +10636,7 @@ function enumeratePublicRows() {
10454
10636
  app8.get("/session", (c) => {
10455
10637
  const visitor = resolveVisitor(c);
10456
10638
  if (!visitor) {
10457
- console.error(`${TAG16} op=reader-refused reason=no-anchor path=/session`);
10639
+ console.error(`${TAG17} op=reader-refused reason=no-anchor path=/session`);
10458
10640
  return c.json({ error: "gate-required" }, 401);
10459
10641
  }
10460
10642
  const rows = enumeratePublicRows();
@@ -10473,11 +10655,11 @@ app8.get("/session", (c) => {
10473
10655
  found = effectiveSlug ? resolveOpenVisitorSession(rows, visitor.visitorId, effectiveSlug) : null;
10474
10656
  }
10475
10657
  if (found) {
10476
- console.log(`${TAG16} op=session-resume anchor=${visitor.kind} key=${(found.senderId ?? "").slice(0, 8)} sessionId=${found.sessionId.slice(0, 8)}`);
10658
+ console.log(`${TAG17} op=session-resume anchor=${visitor.kind} key=${(found.senderId ?? "").slice(0, 8)} sessionId=${found.sessionId.slice(0, 8)}`);
10477
10659
  return c.json({ sessionId: found.sessionId, projectDir: found.projectDir, sessionKey: found.senderId });
10478
10660
  }
10479
10661
  const sessionKey = crypto.randomUUID();
10480
- console.log(`${TAG16} op=session-new anchor=${visitor.kind} key=${sessionKey.slice(0, 8)}`);
10662
+ console.log(`${TAG17} op=session-new anchor=${visitor.kind} key=${sessionKey.slice(0, 8)}`);
10481
10663
  return c.json({ sessionId: null, projectDir: null, sessionKey });
10482
10664
  });
10483
10665
  function publicUploadsDir(accountId, sessionId) {
@@ -10506,7 +10688,7 @@ function readFrom2(path, from) {
10506
10688
  app8.get("/stream", (c) => {
10507
10689
  const visitor = resolveVisitor(c);
10508
10690
  if (!visitor) {
10509
- console.error(`${TAG16} op=reader-refused reason=no-anchor path=/stream`);
10691
+ console.error(`${TAG17} op=reader-refused reason=no-anchor path=/stream`);
10510
10692
  return c.json({ error: "gate-required" }, 401);
10511
10693
  }
10512
10694
  const sessionId = c.req.query("sessionId") ?? "";
@@ -10524,12 +10706,12 @@ app8.get("/stream", (c) => {
10524
10706
  const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
10525
10707
  const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
10526
10708
  if (!(isPublicWebchat && owns)) {
10527
- console.error(`${TAG16} op=reader-refused reason=not-owner anchor=${visitor.kind} sessionId=${sessionId.slice(0, 8)}`);
10709
+ console.error(`${TAG17} op=reader-refused reason=not-owner anchor=${visitor.kind} sessionId=${sessionId.slice(0, 8)}`);
10528
10710
  return c.json({ error: "forbidden" }, 403);
10529
10711
  }
10530
10712
  const senderShort = (meta.senderId ?? "").slice(0, 8);
10531
10713
  const encoder = new TextEncoder();
10532
- console.log(`${TAG16} op=reader-open anchor=${visitor.kind} key=${senderShort} mode=delivered-only sessionId=${sessionId.slice(0, 8)}`);
10714
+ console.log(`${TAG17} op=reader-open anchor=${visitor.kind} key=${senderShort} mode=delivered-only sessionId=${sessionId.slice(0, 8)}`);
10533
10715
  const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
10534
10716
  data: ${JSON.stringify(turn)}
10535
10717
 
@@ -10544,7 +10726,7 @@ data: ${JSON.stringify(turn)}
10544
10726
  const { turns, dropped } = filterDeliveredFrames(lines);
10545
10727
  if (uploadsDir) enrichPublicAttachments(turns, listSessionAttachmentsInDir(uploadsDir), attachmentCursor);
10546
10728
  for (const turn of turns) send(controller, turn, offset);
10547
- if (dropped > 0) console.log(`${TAG16} op=reader-filtered key=${senderShort} dropped=${dropped}`);
10729
+ if (dropped > 0) console.log(`${TAG17} op=reader-filtered key=${senderShort} dropped=${dropped}`);
10548
10730
  };
10549
10731
  try {
10550
10732
  const { buf, end } = readFrom2(jsonlPath, 0);
@@ -10579,7 +10761,7 @@ data: ${JSON.stringify(turn)}
10579
10761
  watcher?.close();
10580
10762
  clearInterval(poll);
10581
10763
  clearInterval(heartbeat);
10582
- console.log(`${TAG16} op=reader-close key=${senderShort}`);
10764
+ console.log(`${TAG17} op=reader-close key=${senderShort}`);
10583
10765
  try {
10584
10766
  controller.close();
10585
10767
  } catch {
@@ -11134,8 +11316,8 @@ async function reapplyLeversViaManager() {
11134
11316
  var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
11135
11317
  var sendSeq = 0;
11136
11318
  function createWebchatRoutes(deps) {
11137
- const app73 = new Hono();
11138
- app73.post("/send", requireAdminSession, async (c) => {
11319
+ const app75 = new Hono();
11320
+ app75.post("/send", requireAdminSession, async (c) => {
11139
11321
  let accountId;
11140
11322
  try {
11141
11323
  accountId = resolvePlatformAccountId();
@@ -11333,7 +11515,7 @@ ${note}` : note;
11333
11515
  if (turnTimer.unref) turnTimer.unref();
11334
11516
  return c.json({ ok: true });
11335
11517
  });
11336
- app73.post("/interrupt", requireAdminSession, async (c) => {
11518
+ app75.post("/interrupt", requireAdminSession, async (c) => {
11337
11519
  const cacheKey = c.get("cacheKey");
11338
11520
  const requesterUserId = (cacheKey ? getUserIdForSession(cacheKey) : void 0) ?? null;
11339
11521
  const primaryUserId = resolvePrimaryAdminUserId();
@@ -11361,7 +11543,7 @@ ${note}` : note;
11361
11543
  }
11362
11544
  return c.json({ ok: true, stopped: outcome.stopped, intId: outcome.intId, deadChild: outcome.deadChild }, 200);
11363
11545
  });
11364
- app73.post("/settings", requireAdminSession, async (c) => {
11546
+ app75.post("/settings", requireAdminSession, async (c) => {
11365
11547
  const body = await c.req.json().catch(() => null);
11366
11548
  const op = body?.op;
11367
11549
  const value = body?.value;
@@ -11397,7 +11579,7 @@ ${note}` : note;
11397
11579
  console.log(`[webchat:settings] op=${op} outcome=accepted accountId=${account.accountId.slice(0, 8)} value=${value} settingsApplied=${settingsApplied}`);
11398
11580
  return c.json({ ok: true, settingsApplied });
11399
11581
  });
11400
- app73.get("/session", requireAdminSession, async (c) => {
11582
+ app75.get("/session", requireAdminSession, async (c) => {
11401
11583
  let accountId;
11402
11584
  try {
11403
11585
  accountId = resolvePlatformAccountId();
@@ -11470,7 +11652,7 @@ ${note}` : note;
11470
11652
  const indicators = await fetchComposerIndicators(sessionId);
11471
11653
  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) });
11472
11654
  });
11473
- app73.post("/permission-verdict", requireAdminSession, async (c) => {
11655
+ app75.post("/permission-verdict", requireAdminSession, async (c) => {
11474
11656
  const body = await c.req.json().catch(() => null);
11475
11657
  const sessionId = body?.sessionId;
11476
11658
  const requestId = body?.request_id;
@@ -11487,7 +11669,7 @@ ${note}` : note;
11487
11669
  const ok = deps.resolvePermissionVerdict?.(`session:${sessionId}`, requestId, behavior) ?? false;
11488
11670
  return c.json({ ok });
11489
11671
  });
11490
- return app73;
11672
+ return app75;
11491
11673
  }
11492
11674
 
11493
11675
  // server/routes/webchat-greeting.ts
@@ -11688,7 +11870,7 @@ function routeTelegramUpdate(input) {
11688
11870
  }
11689
11871
 
11690
11872
  // server/routes/telegram.ts
11691
- var TAG17 = "[telegram-inbound]";
11873
+ var TAG18 = "[telegram-inbound]";
11692
11874
  function configDirName() {
11693
11875
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
11694
11876
  const brandPath = join27(platformRoot5, "config", "brand.json");
@@ -11709,18 +11891,18 @@ app10.post("/", async (c) => {
11709
11891
  const botParam = c.req.query("bot");
11710
11892
  const botType = botParam === "admin" ? "admin" : botParam === "public" ? "public" : null;
11711
11893
  if (!botType) {
11712
- console.error(`${TAG17} op=reject reason=missing-bot-param`);
11894
+ console.error(`${TAG18} op=reject reason=missing-bot-param`);
11713
11895
  return c.json({ ok: false }, 400);
11714
11896
  }
11715
11897
  const sp = secretPath(botType);
11716
11898
  if (!existsSync20(sp)) {
11717
- console.error(`${TAG17} op=reject reason=no-secret-file botType=${botType}`);
11899
+ console.error(`${TAG18} op=reject reason=no-secret-file botType=${botType}`);
11718
11900
  return c.json({ ok: false }, 401);
11719
11901
  }
11720
11902
  const expected = readFileSync22(sp, "utf-8").trim();
11721
11903
  const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
11722
11904
  if (got !== expected) {
11723
- console.error(`${TAG17} op=reject reason=bad-secret botType=${botType}`);
11905
+ console.error(`${TAG18} op=reject reason=bad-secret botType=${botType}`);
11724
11906
  return c.json({ ok: false }, 401);
11725
11907
  }
11726
11908
  let update;
@@ -11731,40 +11913,40 @@ app10.post("/", async (c) => {
11731
11913
  }
11732
11914
  const account = resolveAccount();
11733
11915
  if (!account) {
11734
- console.error(`${TAG17} op=reject reason=no-account`);
11916
+ console.error(`${TAG18} op=reject reason=no-account`);
11735
11917
  return c.json({ ok: true }, 200);
11736
11918
  }
11737
11919
  const decision = routeTelegramUpdate({ update, botType, config: account.config.telegram ?? {} });
11738
11920
  if (decision.kind === "ignore") {
11739
- console.error(`${TAG17} op=ignore reason=${decision.reason}`);
11921
+ console.error(`${TAG18} op=ignore reason=${decision.reason}`);
11740
11922
  return c.json({ ok: true }, 200);
11741
11923
  }
11742
11924
  if (decision.kind === "denied") {
11743
- console.error(`${TAG17} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
11925
+ console.error(`${TAG18} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
11744
11926
  return c.json({ ok: true }, 200);
11745
11927
  }
11746
11928
  const role = decision.agentType === "admin" ? "admin" : "public";
11747
11929
  const agentSlug = role === "admin" ? "admin" : resolveDefaultAgentSlug(account.accountDir);
11748
11930
  if (!agentSlug) {
11749
- console.error(`${TAG17} op=reject reason=no-default-agent`);
11931
+ console.error(`${TAG18} op=reject reason=no-default-agent`);
11750
11932
  return c.json({ ok: true }, 200);
11751
11933
  }
11752
- console.error(`${TAG17} op=update accountId=${account.accountId} from=${decision.senderId}`);
11934
+ console.error(`${TAG18} op=update accountId=${account.accountId} from=${decision.senderId}`);
11753
11935
  const botToken = botType === "admin" ? account.config.telegram?.adminBotToken : account.config.telegram?.publicBotToken;
11754
11936
  const { senderId, chatId, text } = decision;
11755
11937
  const gateway = getTelegramGateway();
11756
11938
  if (!gateway) {
11757
- console.error(`${TAG17} op=reject reason=gateway-not-ready from=${senderId}`);
11939
+ console.error(`${TAG18} op=reject reason=gateway-not-ready from=${senderId}`);
11758
11940
  return c.json({ ok: true }, 200);
11759
11941
  }
11760
11942
  const reply = async (replyText) => {
11761
11943
  if (!botToken) {
11762
11944
  const reason = account.config.telegram ? "no-bot-token" : "no-telegram-config";
11763
- console.error(`${TAG17} op=reply-dropped reason=${reason} botType=${botType} from=${senderId}`);
11945
+ console.error(`${TAG18} op=reply-dropped reason=${reason} botType=${botType} from=${senderId}`);
11764
11946
  return;
11765
11947
  }
11766
11948
  const sent = await sendTelegramText(botToken, chatId, replyText);
11767
- console.error(`${TAG17} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
11949
+ console.error(`${TAG18} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
11768
11950
  };
11769
11951
  void gateway.handleInbound({
11770
11952
  accountId: account.accountId,
@@ -11782,7 +11964,7 @@ var telegram_default = app10;
11782
11964
  // server/routes/quickbooks.ts
11783
11965
  import { join as join28 } from "path";
11784
11966
  import { existsSync as existsSync21, readFileSync as readFileSync23, writeFileSync as writeFileSync9, mkdirSync as mkdirSync4, rmSync as rmSync2, renameSync as renameSync5 } from "fs";
11785
- var TAG18 = "[quickbooks]";
11967
+ var TAG19 = "[quickbooks]";
11786
11968
  var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
11787
11969
  var STATE_RE = /^[A-Za-z0-9_-]+$/;
11788
11970
  function pendingPath(accountDir, state) {
@@ -11795,14 +11977,14 @@ async function completeConsent(args) {
11795
11977
  const { accountDir, code, realmId } = args;
11796
11978
  const state = args.state;
11797
11979
  if (!state || !STATE_RE.test(state) || !existsSync21(pendingPath(accountDir, state))) {
11798
- console.error(`${TAG18} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
11980
+ console.error(`${TAG19} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
11799
11981
  return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
11800
11982
  }
11801
11983
  const claimFile = `${pendingPath(accountDir, state)}.claimed`;
11802
11984
  try {
11803
11985
  renameSync5(pendingPath(accountDir, state), claimFile);
11804
11986
  } catch {
11805
- console.error(`${TAG18} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
11987
+ console.error(`${TAG19} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
11806
11988
  return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
11807
11989
  }
11808
11990
  try {
@@ -11810,14 +11992,14 @@ async function completeConsent(args) {
11810
11992
  try {
11811
11993
  pending = JSON.parse(readFileSync23(claimFile, "utf-8"));
11812
11994
  } catch {
11813
- console.error(`${TAG18} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
11995
+ console.error(`${TAG19} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
11814
11996
  return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
11815
11997
  }
11816
11998
  if (Date.now() > pending.expiresAt) {
11817
- console.error(`${TAG18} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
11999
+ console.error(`${TAG19} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
11818
12000
  return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
11819
12001
  }
11820
- console.error(`${TAG18} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
12002
+ console.error(`${TAG19} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
11821
12003
  if (!code || !realmId) {
11822
12004
  return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
11823
12005
  }
@@ -11841,12 +12023,12 @@ async function completeConsent(args) {
11841
12023
  });
11842
12024
  const text = await res.text();
11843
12025
  if (!res.ok) {
11844
- console.error(`${TAG18} op=token-exchange realmId=${realmId} persisted=false`);
12026
+ console.error(`${TAG19} op=token-exchange realmId=${realmId} persisted=false`);
11845
12027
  return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
11846
12028
  }
11847
12029
  const body = JSON.parse(text);
11848
12030
  if (!body.refresh_token) {
11849
- console.error(`${TAG18} op=token-exchange realmId=${realmId} persisted=false`);
12031
+ console.error(`${TAG19} op=token-exchange realmId=${realmId} persisted=false`);
11850
12032
  return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
11851
12033
  }
11852
12034
  const now = Date.now();
@@ -11859,7 +12041,7 @@ async function completeConsent(args) {
11859
12041
  mkdirSync4(join28(accountDir, "secrets"), { recursive: true });
11860
12042
  writeFileSync9(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
11861
12043
  const persisted = JSON.parse(readFileSync23(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
11862
- console.error(`${TAG18} op=token-exchange realmId=${realmId} persisted=${persisted}`);
12044
+ console.error(`${TAG19} op=token-exchange realmId=${realmId} persisted=${persisted}`);
11863
12045
  return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
11864
12046
  } finally {
11865
12047
  rmSync2(claimFile, { force: true });
@@ -11872,7 +12054,7 @@ var app11 = new Hono();
11872
12054
  app11.get("/callback", async (c) => {
11873
12055
  const account = resolveAccount();
11874
12056
  if (!account) {
11875
- console.error(`${TAG18} op=callback stateValid=false realmId= reason=no-account`);
12057
+ console.error(`${TAG19} op=callback stateValid=false realmId= reason=no-account`);
11876
12058
  return c.html(page("QuickBooks", "This install has no account configured."), 500);
11877
12059
  }
11878
12060
  const result = await completeConsent({
@@ -15279,7 +15461,7 @@ function resolveTunnelUrl() {
15279
15461
  if (!state) return null;
15280
15462
  return `https://${hostname2}.${state.domain}`;
15281
15463
  }
15282
- var TAG19 = "[claude-session-manager:wrapper]";
15464
+ var TAG20 = "[claude-session-manager:wrapper]";
15283
15465
  async function refuseIfClaudeAuthDead(c, route, sessionId) {
15284
15466
  const auth = await ensureAuth();
15285
15467
  if (auth.status !== "dead" && auth.status !== "missing") return null;
@@ -15297,12 +15479,12 @@ async function performSpawnWithInitialMessage(args) {
15297
15479
  const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
15298
15480
  const ownerMs = Date.now() - ownerStart;
15299
15481
  const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
15300
- console.log(`${TAG19} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
15482
+ console.log(`${TAG20} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
15301
15483
  const dormantPlugins = computeDormantPlugins(args.senderId);
15302
15484
  const activePlugins = computeActivePlugins(args.senderId);
15303
15485
  const specialistDomains = computeSpecialistDomains(args.senderId);
15304
15486
  const tunnelUrl = resolveTunnelUrl();
15305
- console.log(`${TAG19} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
15487
+ console.log(`${TAG20} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
15306
15488
  const upstreamPayload = JSON.stringify({
15307
15489
  senderId: args.senderId,
15308
15490
  // Task 205 — pass userId through to the manager so it lands as
@@ -15329,24 +15511,24 @@ async function performSpawnWithInitialMessage(args) {
15329
15511
  // unshapely values.
15330
15512
  conversationNodeId: args.conversationNodeId
15331
15513
  });
15332
- console.log(`${TAG19} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
15514
+ console.log(`${TAG20} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
15333
15515
  const forwardStart = Date.now();
15334
15516
  const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
15335
15517
  method: "POST",
15336
15518
  headers: { "content-type": "application/json" },
15337
15519
  body: upstreamPayload
15338
15520
  }).catch((err) => {
15339
- console.error(`${TAG19} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
15521
+ console.error(`${TAG20} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
15340
15522
  return null;
15341
15523
  });
15342
15524
  if (!upstream) return {
15343
15525
  response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
15344
15526
  claudeSessionId: null
15345
15527
  };
15346
- console.log(`${TAG19} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
15528
+ console.log(`${TAG20} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
15347
15529
  if (args.initialMessage) {
15348
15530
  const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
15349
- console.log(`${TAG19} initial-message-inlined bytes=${inputBytes}`);
15531
+ console.log(`${TAG20} initial-message-inlined bytes=${inputBytes}`);
15350
15532
  }
15351
15533
  const bodyText = await upstream.text().catch(() => "");
15352
15534
  let claudeSessionId = null;
@@ -15381,7 +15563,7 @@ app22.post("/", async (c) => {
15381
15563
  if (refusal) return refusal;
15382
15564
  const senderId = getAccountIdForSession(cacheKey) ?? "";
15383
15565
  if (!senderId) {
15384
- console.error(`${TAG19} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
15566
+ console.error(`${TAG20} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
15385
15567
  return c.json({ error: "admin-account-not-resolved" }, 500);
15386
15568
  }
15387
15569
  const userId = getUserIdForSession(cacheKey) ?? void 0;
@@ -15390,7 +15572,7 @@ app22.post("/", async (c) => {
15390
15572
  const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
15391
15573
  const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
15392
15574
  const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
15393
- console.log(`${TAG19} 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"}`);
15575
+ console.log(`${TAG20} 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"}`);
15394
15576
  const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
15395
15577
  const { response, claudeSessionId } = await performSpawnWithInitialMessage({
15396
15578
  senderId,
@@ -15409,13 +15591,13 @@ app22.post("/", async (c) => {
15409
15591
  claudeSessionId,
15410
15592
  senderId
15411
15593
  );
15412
- console.log(`${TAG19} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
15594
+ console.log(`${TAG20} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
15413
15595
  return response;
15414
15596
  });
15415
15597
  var claude_sessions_default = app22;
15416
15598
 
15417
15599
  // server/routes/admin/log-ingest.ts
15418
- var TAG20 = "[log-ingest]";
15600
+ var TAG21 = "[log-ingest]";
15419
15601
  var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
15420
15602
  var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
15421
15603
  var MAX_LINE_BYTES = 4096;
@@ -15426,7 +15608,7 @@ function isLoopbackAddr2(addr) {
15426
15608
  app23.post("/", async (c) => {
15427
15609
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
15428
15610
  if (!isLoopbackAddr2(remoteAddr)) {
15429
- console.error(`${TAG20} reject reason=non-loopback remoteAddr=${remoteAddr}`);
15611
+ console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
15430
15612
  return c.json({ error: "log-ingest-loopback-only" }, 403);
15431
15613
  }
15432
15614
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -15435,7 +15617,7 @@ app23.post("/", async (c) => {
15435
15617
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
15436
15618
  const offender = tokens.find((t) => !isLoopbackAddr2(t));
15437
15619
  if (offender !== void 0) {
15438
- console.error(`${TAG20} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
15620
+ console.error(`${TAG21} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
15439
15621
  return c.json({ error: "log-ingest-loopback-only" }, 403);
15440
15622
  }
15441
15623
  }
@@ -15483,18 +15665,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
15483
15665
  ]);
15484
15666
  var app24 = new Hono();
15485
15667
  app24.post("/", async (c) => {
15486
- const TAG46 = "[admin:events]";
15668
+ const TAG49 = "[admin:events]";
15487
15669
  let body;
15488
15670
  try {
15489
15671
  body = await c.req.json();
15490
15672
  } catch (err) {
15491
15673
  const detail = err instanceof Error ? err.message : String(err);
15492
- console.error(`${TAG46} reject reason=body-not-json detail=${detail}`);
15674
+ console.error(`${TAG49} reject reason=body-not-json detail=${detail}`);
15493
15675
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
15494
15676
  }
15495
15677
  const event = typeof body.event === "string" ? body.event : "";
15496
15678
  if (!ALLOWED_EVENTS.has(event)) {
15497
- console.error(`${TAG46} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
15679
+ console.error(`${TAG49} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
15498
15680
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
15499
15681
  }
15500
15682
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -20958,7 +21140,7 @@ function managerLogFollowUrl(sessionId, opts) {
20958
21140
  }
20959
21141
 
20960
21142
  // server/routes/admin/linkedin-ingest.ts
20961
- var TAG21 = "[linkedin-ingest-route]";
21143
+ var TAG22 = "[linkedin-ingest-route]";
20962
21144
  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}$/;
20963
21145
  var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
20964
21146
  var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
@@ -21062,29 +21244,29 @@ app42.post("/", requireAdminSession, async (c) => {
21062
21244
  try {
21063
21245
  body = await c.req.json();
21064
21246
  } catch {
21065
- console.error(TAG21 + " rejected status=400 reason=schema:body-not-json");
21247
+ console.error(TAG22 + " rejected status=400 reason=schema:body-not-json");
21066
21248
  return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
21067
21249
  }
21068
21250
  const v = validate(body);
21069
21251
  if (!v.ok) {
21070
- console.error(TAG21 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
21252
+ console.error(TAG22 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
21071
21253
  return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
21072
21254
  }
21073
21255
  const envelope = v.envelope;
21074
21256
  const cacheKey = c.var.cacheKey ?? "";
21075
21257
  const senderId = getAccountIdForSession(cacheKey) ?? "";
21076
21258
  if (!senderId) {
21077
- console.error(TAG21 + " rejected status=500 reason=admin-account-not-resolved");
21259
+ console.error(TAG22 + " rejected status=500 reason=admin-account-not-resolved");
21078
21260
  return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
21079
21261
  }
21080
21262
  const payloadBytes = JSON.stringify(envelope).length;
21081
21263
  console.log(
21082
- TAG21 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
21264
+ TAG22 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
21083
21265
  );
21084
21266
  const initialMessage = buildInitialMessage(envelope);
21085
21267
  const spawnStart = Date.now();
21086
21268
  const sessionId = randomUUID9();
21087
- console.log(TAG21 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
21269
+ console.log(TAG22 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
21088
21270
  const spawned = await managerRcSpawn({
21089
21271
  sessionId,
21090
21272
  initialMessage,
@@ -21093,12 +21275,12 @@ app42.post("/", requireAdminSession, async (c) => {
21093
21275
  });
21094
21276
  if ("error" in spawned) {
21095
21277
  console.error(
21096
- TAG21 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
21278
+ TAG22 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
21097
21279
  );
21098
21280
  return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
21099
21281
  }
21100
21282
  console.log(
21101
- TAG21 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
21283
+ TAG22 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
21102
21284
  );
21103
21285
  return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
21104
21286
  });
@@ -21106,7 +21288,7 @@ var linkedin_ingest_default = app42;
21106
21288
 
21107
21289
  // server/routes/admin/post-turn-context.ts
21108
21290
  import neo4j2 from "neo4j-driver";
21109
- var TAG22 = "[post-turn-context]";
21291
+ var TAG23 = "[post-turn-context]";
21110
21292
  var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
21111
21293
  "embedding",
21112
21294
  "passwordHash",
@@ -21148,7 +21330,7 @@ var app43 = new Hono();
21148
21330
  app43.get("/", async (c) => {
21149
21331
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
21150
21332
  if (!isLoopbackAddr3(remoteAddr)) {
21151
- console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21333
+ console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21152
21334
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
21153
21335
  }
21154
21336
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -21157,7 +21339,7 @@ app43.get("/", async (c) => {
21157
21339
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
21158
21340
  const offender = tokens.find((t) => !isLoopbackAddr3(t));
21159
21341
  if (offender !== void 0) {
21160
- console.error(`${TAG22} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21342
+ console.error(`${TAG23} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21161
21343
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
21162
21344
  }
21163
21345
  }
@@ -21189,7 +21371,7 @@ app43.get("/", async (c) => {
21189
21371
  writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
21190
21372
  const total = Date.now() - started2;
21191
21373
  console.log(
21192
- `${TAG22} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
21374
+ `${TAG23} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
21193
21375
  );
21194
21376
  return c.json({
21195
21377
  writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
@@ -21198,7 +21380,7 @@ app43.get("/", async (c) => {
21198
21380
  const elapsed = Date.now() - started2;
21199
21381
  const message = err instanceof Error ? err.message : String(err);
21200
21382
  console.error(
21201
- `${TAG22} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
21383
+ `${TAG23} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
21202
21384
  );
21203
21385
  return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
21204
21386
  } finally {
@@ -21311,7 +21493,7 @@ function formatPreviousContext(writes) {
21311
21493
  }
21312
21494
 
21313
21495
  // server/routes/admin/public-session-context.ts
21314
- var TAG23 = "[public-session-context]";
21496
+ var TAG24 = "[public-session-context]";
21315
21497
  function isLoopbackAddr4(addr) {
21316
21498
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
21317
21499
  }
@@ -21319,7 +21501,7 @@ var app44 = new Hono();
21319
21501
  app44.get("/", async (c) => {
21320
21502
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
21321
21503
  if (!isLoopbackAddr4(remoteAddr)) {
21322
- console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21504
+ console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21323
21505
  return c.json({ error: "public-session-context-loopback-only" }, 403);
21324
21506
  }
21325
21507
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -21328,7 +21510,7 @@ app44.get("/", async (c) => {
21328
21510
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
21329
21511
  const offender = tokens.find((t) => !isLoopbackAddr4(t));
21330
21512
  if (offender !== void 0) {
21331
- console.error(`${TAG23} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21513
+ console.error(`${TAG24} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21332
21514
  return c.json({ error: "public-session-context-loopback-only" }, 403);
21333
21515
  }
21334
21516
  }
@@ -21342,14 +21524,14 @@ app44.get("/", async (c) => {
21342
21524
  const writes = await fetchSliceWrites(session, sliceToken, accountId);
21343
21525
  const total = Date.now() - started2;
21344
21526
  console.log(
21345
- `${TAG23} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
21527
+ `${TAG24} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
21346
21528
  );
21347
21529
  return c.json({ writes });
21348
21530
  } catch (err) {
21349
21531
  const elapsed = Date.now() - started2;
21350
21532
  const message = err instanceof Error ? err.message : String(err);
21351
21533
  console.error(
21352
- `${TAG23} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
21534
+ `${TAG24} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
21353
21535
  );
21354
21536
  return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
21355
21537
  } finally {
@@ -21368,7 +21550,7 @@ function getWebchatGateway() {
21368
21550
  }
21369
21551
 
21370
21552
  // server/routes/admin/public-session-exit.ts
21371
- var TAG24 = "[public-session-exit-route]";
21553
+ var TAG25 = "[public-session-exit-route]";
21372
21554
  function isLoopbackAddr5(addr) {
21373
21555
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
21374
21556
  }
@@ -21376,7 +21558,7 @@ var app45 = new Hono();
21376
21558
  app45.post("/", async (c) => {
21377
21559
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
21378
21560
  if (!isLoopbackAddr5(remoteAddr)) {
21379
- console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21561
+ console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21380
21562
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
21381
21563
  }
21382
21564
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -21385,7 +21567,7 @@ app45.post("/", async (c) => {
21385
21567
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
21386
21568
  const offender = tokens.find((t) => !isLoopbackAddr5(t));
21387
21569
  if (offender !== void 0) {
21388
- console.error(`${TAG24} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21570
+ console.error(`${TAG25} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21389
21571
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
21390
21572
  }
21391
21573
  }
@@ -21399,7 +21581,7 @@ app45.post("/", async (c) => {
21399
21581
  if (!sessionId) return c.json({ error: "sessionId required" }, 400);
21400
21582
  const gateway = getWebchatGateway();
21401
21583
  if (!gateway) {
21402
- console.error(`${TAG24} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
21584
+ console.error(`${TAG25} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
21403
21585
  return c.json({ error: "webchat-gateway-unset" }, 503);
21404
21586
  }
21405
21587
  gateway.handlePublicSessionExit(sessionId);
@@ -21408,7 +21590,7 @@ app45.post("/", async (c) => {
21408
21590
  var public_session_exit_default = app45;
21409
21591
 
21410
21592
  // server/routes/admin/access-session-evict.ts
21411
- var TAG25 = "[access-session-evict]";
21593
+ var TAG26 = "[access-session-evict]";
21412
21594
  function isLoopbackAddr6(addr) {
21413
21595
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
21414
21596
  }
@@ -21416,7 +21598,7 @@ var app46 = new Hono();
21416
21598
  app46.post("/", async (c) => {
21417
21599
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
21418
21600
  if (!isLoopbackAddr6(remoteAddr)) {
21419
- console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21601
+ console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21420
21602
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
21421
21603
  }
21422
21604
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -21425,7 +21607,7 @@ app46.post("/", async (c) => {
21425
21607
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
21426
21608
  const offender = tokens.find((t) => !isLoopbackAddr6(t));
21427
21609
  if (offender !== void 0) {
21428
- console.error(`${TAG25} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21610
+ console.error(`${TAG26} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21429
21611
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
21430
21612
  }
21431
21613
  }
@@ -21438,13 +21620,13 @@ app46.post("/", async (c) => {
21438
21620
  const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
21439
21621
  if (!grantId) return c.json({ error: "grantId required" }, 400);
21440
21622
  const dropped = evictAccessSessionsByGrant(grantId);
21441
- console.log(`${TAG25} grantId=${grantId} dropped=${dropped}`);
21623
+ console.log(`${TAG26} grantId=${grantId} dropped=${dropped}`);
21442
21624
  return c.json({ ok: true, dropped });
21443
21625
  });
21444
21626
  var access_session_evict_default = app46;
21445
21627
 
21446
21628
  // server/routes/admin/enrol-person.ts
21447
- var TAG26 = "[enrol]";
21629
+ var TAG27 = "[enrol]";
21448
21630
  function isLoopbackAddr7(addr) {
21449
21631
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
21450
21632
  }
@@ -21453,7 +21635,7 @@ var app47 = new Hono();
21453
21635
  app47.post("/", async (c) => {
21454
21636
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
21455
21637
  if (!isLoopbackAddr7(remoteAddr)) {
21456
- console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21638
+ console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
21457
21639
  return c.json({ error: "enrol-person-loopback-only" }, 403);
21458
21640
  }
21459
21641
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -21462,7 +21644,7 @@ app47.post("/", async (c) => {
21462
21644
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
21463
21645
  const offender = tokens.find((t) => !isLoopbackAddr7(t));
21464
21646
  if (offender !== void 0) {
21465
- console.error(`${TAG26} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21647
+ console.error(`${TAG27} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
21466
21648
  return c.json({ error: "enrol-person-loopback-only" }, 403);
21467
21649
  }
21468
21650
  }
@@ -21487,7 +21669,7 @@ app47.post("/", async (c) => {
21487
21669
  }
21488
21670
  const accountId = process.env.ACCOUNT_ID ?? "";
21489
21671
  if (!accountId) {
21490
- console.error(`${TAG26} op=person result=no-account-id`);
21672
+ console.error(`${TAG27} op=person result=no-account-id`);
21491
21673
  return c.json({ error: "no-account-id" }, 500);
21492
21674
  }
21493
21675
  let personId;
@@ -21495,7 +21677,7 @@ app47.post("/", async (c) => {
21495
21677
  personId = await enrolPerson({ accountId, phone, email, agentSlug });
21496
21678
  } catch (err) {
21497
21679
  console.error(
21498
- `${TAG26} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
21680
+ `${TAG27} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
21499
21681
  );
21500
21682
  return c.json({ error: "enrol-failed" }, 500);
21501
21683
  }
@@ -21505,11 +21687,11 @@ app47.post("/", async (c) => {
21505
21687
  if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
21506
21688
  } catch (err) {
21507
21689
  console.error(
21508
- `${TAG26} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
21690
+ `${TAG27} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
21509
21691
  );
21510
21692
  }
21511
21693
  console.log(
21512
- `${TAG26} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
21694
+ `${TAG27} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
21513
21695
  );
21514
21696
  return c.json({ personId, grant }, 200);
21515
21697
  });
@@ -22384,6 +22566,9 @@ app52.delete("/:plugin/:skill", requireAdminSession, async (c) => {
22384
22566
  });
22385
22567
  var skills_default = app52;
22386
22568
 
22569
+ // server/routes/admin/tasks-list.ts
22570
+ import { basename as basename14, join as join45 } from "path";
22571
+
22387
22572
  // app/lib/time-entry-format.ts
22388
22573
  function secondsBetween(startIso, endIso) {
22389
22574
  const s = Date.parse(startIso);
@@ -22402,7 +22587,7 @@ function toNum(v) {
22402
22587
  }
22403
22588
 
22404
22589
  // server/routes/admin/tasks-list.ts
22405
- var TAG27 = "[task-timer]";
22590
+ var TAG28 = "[task-timer]";
22406
22591
  var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
22407
22592
  var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
22408
22593
  var app53 = new Hono();
@@ -22410,12 +22595,12 @@ app53.get("/", requireAdminSession, async (c) => {
22410
22595
  const cacheKey = c.var.cacheKey;
22411
22596
  const accountId = getAccountIdForSession(cacheKey);
22412
22597
  if (!accountId) {
22413
- console.error(`${TAG27} op=list auth-rejected reason="no account for session"`);
22598
+ console.error(`${TAG28} op=list auth-rejected reason="no account for session"`);
22414
22599
  return c.json({ error: "Account not found for session" }, 401);
22415
22600
  }
22416
22601
  const cacheStart = Date.now();
22417
22602
  const cached3 = await getOrCompute("tasks-list", accountId, () => computeTaskList(accountId));
22418
- console.log(`${TAG27} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
22603
+ console.log(`${TAG28} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
22419
22604
  if (cached3.value === null) {
22420
22605
  return c.json({ error: "tasks-list-failed" }, 500);
22421
22606
  }
@@ -22442,6 +22627,11 @@ async function computeTaskList(accountId) {
22442
22627
  // rather than a userId slice (Task 1982).
22443
22628
  OPTIONAL MATCH (assignee)-[:OWNS]->(ap:Person) WHERE ap.accountId = assignee.accountId
22444
22629
  WITH t, openTe, assignee, head(collect(ap)) AS assigneePerson
22630
+ // Task 2121 \u2014 the worked-in session. head(collect(...)) for the same
22631
+ // fan-out reason as the assignee match above: a second WORKED_ON_IN edge
22632
+ // would duplicate the row and double-count the census.
22633
+ OPTIONAL MATCH (t)-[:WORKED_ON_IN]->(conv:Conversation)
22634
+ WITH t, openTe, assignee, assigneePerson, head(collect(conv)) AS workConv
22445
22635
  RETURN t.taskId AS taskId, elementId(t) AS rowKey, t.name AS name, t.clientName AS clientName,
22446
22636
  t.propertyAddress AS propertyAddress, t.fee AS fee, t.status AS status,
22447
22637
  coalesce(t.secondsLogged, 0) AS secondsLogged,
@@ -22449,7 +22639,8 @@ async function computeTaskList(accountId) {
22449
22639
  t.createdAt AS createdAt,
22450
22640
  assignee.userId AS assigneeUserId,
22451
22641
  assigneePerson.givenName AS assigneeGivenName,
22452
- assigneePerson.familyName AS assigneeFamilyName
22642
+ assigneePerson.familyName AS assigneeFamilyName,
22643
+ workConv.sessionId AS sessionId
22453
22644
  ORDER BY t.createdAt DESC`,
22454
22645
  { accountId }
22455
22646
  );
@@ -22463,6 +22654,7 @@ async function computeTaskList(accountId) {
22463
22654
  let missingTaskId = 0;
22464
22655
  let missingCreatedAt = 0;
22465
22656
  let assigned = 0;
22657
+ let sessionLinked = 0;
22466
22658
  for (const rec of result.records) {
22467
22659
  const status = rec.get("status") ?? "pending";
22468
22660
  const runningStartedAt = rec.get("runningStartedAt") ?? null;
@@ -22477,6 +22669,8 @@ async function computeTaskList(accountId) {
22477
22669
  const assigneeGivenName = rec.get("assigneeGivenName") ?? null;
22478
22670
  const assigneeFamilyName = rec.get("assigneeFamilyName") ?? null;
22479
22671
  const assigneeName = assigneeGivenName && assigneeGivenName.trim().length > 0 ? assigneeFamilyName && assigneeFamilyName.trim().length > 0 ? `${assigneeGivenName.trim()} ${assigneeFamilyName.trim()}` : assigneeGivenName.trim() : null;
22672
+ const sessionId = rec.get("sessionId") ?? null;
22673
+ if (sessionId !== null) sessionLinked++;
22480
22674
  const row = {
22481
22675
  taskId,
22482
22676
  rowKey: rec.get("rowKey"),
@@ -22490,23 +22684,73 @@ async function computeTaskList(accountId) {
22490
22684
  runningStartedAt,
22491
22685
  createdAt,
22492
22686
  assigneeUserId,
22493
- assigneeName
22687
+ assigneeName,
22688
+ sessionId
22494
22689
  };
22495
22690
  if (COMPLETED.has(status)) completed.push(row);
22496
22691
  else if (!HIDDEN_FROM_OPEN.has(status)) open3.push(row);
22497
22692
  }
22693
+ let orphans = 0;
22694
+ try {
22695
+ const orphanResult = await session.run(
22696
+ `MATCH (t:Task {accountId: $accountId})
22697
+ WHERE t.sessionSpawnRequestedAt IS NOT NULL AND NOT (t)-[:WORKED_ON_IN]->(:Conversation)
22698
+ RETURN count(t) AS orphans`,
22699
+ { accountId }
22700
+ );
22701
+ orphans = orphanResult.records.length > 0 ? toNum(orphanResult.records[0].get("orphans")) : 0;
22702
+ } catch (err) {
22703
+ console.error(
22704
+ `${TAG28} op=session-orphans-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
22705
+ );
22706
+ orphans = -1;
22707
+ }
22708
+ if (orphans > 0) {
22709
+ console.error(
22710
+ `${TAG28} 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"`
22711
+ );
22712
+ }
22713
+ const linkedIds = [...open3, ...completed].map((r) => r.sessionId).filter((s) => s !== null);
22714
+ let dangling = null;
22715
+ const cfg = claudeConfigDir();
22716
+ if (linkedIds.length === 0) {
22717
+ dangling = 0;
22718
+ } else if (cfg !== null) {
22719
+ try {
22720
+ const walk = enumerateJsonlsWithSkips(join45(cfg, "projects"));
22721
+ if (walk.skipped > 0) {
22722
+ console.error(
22723
+ `${TAG28} 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"`
22724
+ );
22725
+ dangling = null;
22726
+ } else {
22727
+ const live = new Set(walk.files.map((f) => basename14(f.path, ".jsonl")));
22728
+ dangling = linkedIds.filter((id) => !live.has(id)).length;
22729
+ }
22730
+ } catch (err) {
22731
+ console.error(
22732
+ `${TAG28} op=session-dangling-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
22733
+ );
22734
+ dangling = null;
22735
+ }
22736
+ }
22737
+ if (dangling !== null && dangling > 0) {
22738
+ console.error(
22739
+ `${TAG28} 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"`
22740
+ );
22741
+ }
22498
22742
  const returned = result.records.length;
22499
22743
  if (returned < graphTotal) {
22500
22744
  console.error(
22501
- `${TAG27} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
22745
+ `${TAG28} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
22502
22746
  );
22503
22747
  }
22504
22748
  console.log(
22505
- `${TAG27} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned}`
22749
+ `${TAG28} 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}`
22506
22750
  );
22507
22751
  return { open: open3, completed };
22508
22752
  } catch (err) {
22509
- console.error(`${TAG27} op=list error="${err instanceof Error ? err.message : String(err)}"`);
22753
+ console.error(`${TAG28} op=list error="${err instanceof Error ? err.message : String(err)}"`);
22510
22754
  return null;
22511
22755
  } finally {
22512
22756
  await session.close();
@@ -22516,7 +22760,7 @@ var tasks_list_default = app53;
22516
22760
 
22517
22761
  // server/routes/admin/task-timer-start.ts
22518
22762
  import { randomUUID as randomUUID10 } from "crypto";
22519
- var TAG28 = "[task-timer]";
22763
+ var TAG29 = "[task-timer]";
22520
22764
  var app54 = new Hono();
22521
22765
  app54.post("/", requireAdminSession, async (c) => {
22522
22766
  const cacheKey = c.var.cacheKey;
@@ -22531,7 +22775,7 @@ app54.post("/", requireAdminSession, async (c) => {
22531
22775
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
22532
22776
  if (!taskId) {
22533
22777
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
22534
- console.error(`${TAG28} op=timer-start rejected reason=${reason} account=${accountId}`);
22778
+ console.error(`${TAG29} op=timer-start rejected reason=${reason} account=${accountId}`);
22535
22779
  return c.json({ error: "taskId required" }, 400);
22536
22780
  }
22537
22781
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -22542,7 +22786,7 @@ app54.post("/", requireAdminSession, async (c) => {
22542
22786
  { taskId, accountId }
22543
22787
  );
22544
22788
  if (target.records.length === 0) {
22545
- console.error(`${TAG28} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
22789
+ console.error(`${TAG29} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
22546
22790
  return c.json({ error: "task-not-found" }, 404);
22547
22791
  }
22548
22792
  const open3 = await session.run(
@@ -22554,7 +22798,7 @@ app54.post("/", requireAdminSession, async (c) => {
22554
22798
  const priorEntryId = open3.records[0]?.get("entryId");
22555
22799
  const priorStartedAt = open3.records[0]?.get("startedAt");
22556
22800
  if (priorEntryId) {
22557
- console.log(`${TAG28} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
22801
+ console.log(`${TAG29} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
22558
22802
  invalidate("tasks-list", accountId);
22559
22803
  return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
22560
22804
  }
@@ -22565,11 +22809,11 @@ app54.post("/", requireAdminSession, async (c) => {
22565
22809
  CREATE (te)-[:LOGGED_AGAINST]->(t)`,
22566
22810
  { taskId, accountId, entryId, now }
22567
22811
  );
22568
- console.log(`${TAG28} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
22812
+ console.log(`${TAG29} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
22569
22813
  invalidate("tasks-list", accountId);
22570
22814
  return c.json({ ok: true, running: true, entryId, startedAt: now });
22571
22815
  } catch (err) {
22572
- console.error(`${TAG28} op=start error="${err instanceof Error ? err.message : String(err)}"`);
22816
+ console.error(`${TAG29} op=start error="${err instanceof Error ? err.message : String(err)}"`);
22573
22817
  return c.json({ error: "task-timer-start-failed" }, 500);
22574
22818
  } finally {
22575
22819
  await session.close();
@@ -22579,7 +22823,7 @@ var task_timer_start_default = app54;
22579
22823
 
22580
22824
  // server/routes/admin/task-timer-stop.ts
22581
22825
  import neo4j4 from "neo4j-driver";
22582
- var TAG29 = "[task-timer]";
22826
+ var TAG30 = "[task-timer]";
22583
22827
  var app55 = new Hono();
22584
22828
  app55.post("/", requireAdminSession, async (c) => {
22585
22829
  const cacheKey = c.var.cacheKey;
@@ -22594,7 +22838,7 @@ app55.post("/", requireAdminSession, async (c) => {
22594
22838
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
22595
22839
  if (!taskId) {
22596
22840
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
22597
- console.error(`${TAG29} op=timer-stop rejected reason=${reason} account=${accountId}`);
22841
+ console.error(`${TAG30} op=timer-stop rejected reason=${reason} account=${accountId}`);
22598
22842
  return c.json({ error: "taskId required" }, 400);
22599
22843
  }
22600
22844
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -22615,7 +22859,7 @@ app55.post("/", requireAdminSession, async (c) => {
22615
22859
  { taskId, accountId }
22616
22860
  );
22617
22861
  const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
22618
- console.log(`${TAG29} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
22862
+ console.log(`${TAG30} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
22619
22863
  invalidate("tasks-list", accountId);
22620
22864
  return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
22621
22865
  }
@@ -22639,12 +22883,12 @@ app55.post("/", requireAdminSession, async (c) => {
22639
22883
  const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
22640
22884
  const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
22641
22885
  const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
22642
- console.log(`${TAG29} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
22643
- console.log(`${TAG29} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
22886
+ console.log(`${TAG30} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
22887
+ console.log(`${TAG30} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
22644
22888
  invalidate("tasks-list", accountId);
22645
22889
  return c.json({ ok: true, running: false, seconds, secondsLogged });
22646
22890
  } catch (err) {
22647
- console.error(`${TAG29} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
22891
+ console.error(`${TAG30} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
22648
22892
  return c.json({ error: "task-timer-stop-failed" }, 500);
22649
22893
  } finally {
22650
22894
  await session.close();
@@ -22653,7 +22897,7 @@ app55.post("/", requireAdminSession, async (c) => {
22653
22897
  var task_timer_stop_default = app55;
22654
22898
 
22655
22899
  // server/routes/admin/task-complete.ts
22656
- var TAG30 = "[task-timer]";
22900
+ var TAG31 = "[task-timer]";
22657
22901
  var app56 = new Hono();
22658
22902
  app56.post("/", requireAdminSession, async (c) => {
22659
22903
  const cacheKey = c.var.cacheKey;
@@ -22668,7 +22912,7 @@ app56.post("/", requireAdminSession, async (c) => {
22668
22912
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
22669
22913
  if (!taskId) {
22670
22914
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
22671
- console.error(`${TAG30} op=complete rejected reason=${reason} account=${accountId}`);
22915
+ console.error(`${TAG31} op=complete rejected reason=${reason} account=${accountId}`);
22672
22916
  return c.json({ error: "taskId required" }, 400);
22673
22917
  }
22674
22918
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -22684,11 +22928,11 @@ app56.post("/", requireAdminSession, async (c) => {
22684
22928
  return c.json({ error: "task-not-found" }, 404);
22685
22929
  }
22686
22930
  const secondsLogged = toNum(result.records[0].get("secondsLogged"));
22687
- console.log(`${TAG30} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
22931
+ console.log(`${TAG31} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
22688
22932
  invalidate("tasks-list", accountId);
22689
22933
  return c.json({ ok: true, status: "completed", secondsLogged });
22690
22934
  } catch (err) {
22691
- console.error(`${TAG30} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
22935
+ console.error(`${TAG31} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
22692
22936
  return c.json({ error: "task-complete-failed" }, 500);
22693
22937
  } finally {
22694
22938
  await session.close();
@@ -22699,7 +22943,7 @@ var task_complete_default = app56;
22699
22943
  // server/routes/admin/task-time-adjust.ts
22700
22944
  import { randomUUID as randomUUID11 } from "crypto";
22701
22945
  import neo4j5 from "neo4j-driver";
22702
- var TAG31 = "[task-time-adjust]";
22946
+ var TAG32 = "[task-time-adjust]";
22703
22947
  var app57 = new Hono();
22704
22948
  app57.post("/", requireAdminSession, async (c) => {
22705
22949
  const cacheKey = c.var.cacheKey;
@@ -22709,23 +22953,23 @@ app57.post("/", requireAdminSession, async (c) => {
22709
22953
  try {
22710
22954
  body = await c.req.json();
22711
22955
  } catch {
22712
- console.error(`${TAG31} op=reject reason=bad-json`);
22956
+ console.error(`${TAG32} op=reject reason=bad-json`);
22713
22957
  return c.json({ error: "invalid-json" }, 400);
22714
22958
  }
22715
22959
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
22716
22960
  if (!taskId) {
22717
22961
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
22718
- console.error(`${TAG31} op=time-adjust rejected reason=${reason} account=${accountId}`);
22962
+ console.error(`${TAG32} op=time-adjust rejected reason=${reason} account=${accountId}`);
22719
22963
  return c.json({ error: "taskId required" }, 400);
22720
22964
  }
22721
22965
  const newSeconds = body.newSeconds;
22722
22966
  if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
22723
- console.error(`${TAG31} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
22967
+ console.error(`${TAG32} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
22724
22968
  return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
22725
22969
  }
22726
22970
  const adjustmentId = randomUUID11();
22727
22971
  const now = (/* @__PURE__ */ new Date()).toISOString();
22728
- console.log(`${TAG31} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
22972
+ console.log(`${TAG32} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
22729
22973
  const session = getSession();
22730
22974
  try {
22731
22975
  const guard = await session.run(
@@ -22735,12 +22979,12 @@ app57.post("/", requireAdminSession, async (c) => {
22735
22979
  { taskId, accountId }
22736
22980
  );
22737
22981
  if (guard.records.length === 0) {
22738
- console.error(`${TAG31} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
22982
+ console.error(`${TAG32} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
22739
22983
  return c.json({ error: "task-not-found" }, 404);
22740
22984
  }
22741
22985
  const openCount = toNum(guard.records[0].get("openCount"));
22742
22986
  if (openCount > 0) {
22743
- console.error(`${TAG31} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
22987
+ console.error(`${TAG32} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
22744
22988
  return c.json({ error: "task-timer-running" }, 409);
22745
22989
  }
22746
22990
  const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
@@ -22766,11 +23010,11 @@ app57.post("/", requireAdminSession, async (c) => {
22766
23010
  }
22767
23011
  );
22768
23012
  const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
22769
- console.log(`${TAG31} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
23013
+ console.log(`${TAG32} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
22770
23014
  invalidate("tasks-list", accountId);
22771
23015
  return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
22772
23016
  } catch (err) {
22773
- console.error(`${TAG31} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
23017
+ console.error(`${TAG32} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
22774
23018
  return c.json({ error: "task-time-adjust-failed" }, 500);
22775
23019
  } finally {
22776
23020
  await session.close();
@@ -22863,7 +23107,7 @@ async function resolveAssignableAdmins(accountId, accountsDir = ACCOUNTS_DIR) {
22863
23107
  }
22864
23108
 
22865
23109
  // server/routes/admin/task-assign.ts
22866
- var TAG32 = "[task-assign]";
23110
+ var TAG33 = "[task-assign]";
22867
23111
  var app58 = new Hono();
22868
23112
  app58.post("/", requireAdminSession, async (c) => {
22869
23113
  const cacheKey = c.var.cacheKey;
@@ -22878,7 +23122,7 @@ app58.post("/", requireAdminSession, async (c) => {
22878
23122
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
22879
23123
  if (!taskId) {
22880
23124
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
22881
- console.error(`${TAG32} op=assign rejected reason=${reason} account=${accountId}`);
23125
+ console.error(`${TAG33} op=assign rejected reason=${reason} account=${accountId}`);
22882
23126
  return c.json({ error: "taskId required" }, 400);
22883
23127
  }
22884
23128
  const rawAssignee = body.assigneeUserId;
@@ -22890,7 +23134,7 @@ app58.post("/", requireAdminSession, async (c) => {
22890
23134
  const { ids } = await resolveAllowedAssigneeIds(accountId);
22891
23135
  if (!ids.has(assigneeUserId)) {
22892
23136
  console.error(
22893
- `${TAG32} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
23137
+ `${TAG33} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
22894
23138
  );
22895
23139
  return c.json({ error: "assignee-not-in-roster" }, 403);
22896
23140
  }
@@ -22912,7 +23156,7 @@ app58.post("/", requireAdminSession, async (c) => {
22912
23156
  `MATCH (t:Task {taskId: $taskId, accountId: $accountId}) SET t.updatedAt = $now`,
22913
23157
  { taskId, accountId, now }
22914
23158
  );
22915
- console.log(`${TAG32} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
23159
+ console.log(`${TAG33} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
22916
23160
  invalidate("tasks-list", accountId);
22917
23161
  return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
22918
23162
  }
@@ -22928,7 +23172,7 @@ app58.post("/", requireAdminSession, async (c) => {
22928
23172
  );
22929
23173
  if (set.records.length === 0) {
22930
23174
  console.error(
22931
- `${TAG32} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
23175
+ `${TAG33} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
22932
23176
  );
22933
23177
  return c.json({ error: "assignee-no-admin-node" }, 409);
22934
23178
  }
@@ -22936,12 +23180,12 @@ app58.post("/", requireAdminSession, async (c) => {
22936
23180
  const family = set.records[0].get("familyName") ?? null;
22937
23181
  const assigneeName = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
22938
23182
  console.log(
22939
- `${TAG32} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
23183
+ `${TAG33} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
22940
23184
  );
22941
23185
  invalidate("tasks-list", accountId);
22942
23186
  return c.json({ ok: true, assigneeUserId, assigneeName });
22943
23187
  } catch (err) {
22944
- console.error(`${TAG32} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
23188
+ console.error(`${TAG33} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
22945
23189
  return c.json({ error: "task-assign-failed" }, 500);
22946
23190
  } finally {
22947
23191
  await session.close();
@@ -22949,31 +23193,179 @@ app58.post("/", requireAdminSession, async (c) => {
22949
23193
  });
22950
23194
  var task_assign_default = app58;
22951
23195
 
22952
- // server/routes/admin/admin-users-list.ts
22953
- var TAG33 = "[admin-users]";
23196
+ // server/routes/admin/task-session-open.ts
23197
+ var TAG34 = "[task-session]";
22954
23198
  var app59 = new Hono();
22955
- app59.get("/", requireAdminSession, async (c) => {
23199
+ app59.post("/", requireAdminSession, async (c) => {
22956
23200
  const cacheKey = c.var.cacheKey;
22957
23201
  const accountId = getAccountIdForSession(cacheKey);
22958
23202
  if (!accountId) {
22959
- console.error(`${TAG33} op=list auth-rejected reason="no account for session"`);
23203
+ console.error(`${TAG34} op=request auth-rejected reason="no account for session"`);
23204
+ return c.json({ error: "Account not found for session" }, 401);
23205
+ }
23206
+ let body;
23207
+ try {
23208
+ body = await c.req.json();
23209
+ } catch {
23210
+ return c.json({ error: "invalid-json" }, 400);
23211
+ }
23212
+ const taskId = typeof body.taskId === "string" ? body.taskId : "";
23213
+ if (!taskId) {
23214
+ const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
23215
+ console.error(`${TAG34} op=request rejected reason=${reason} account=${accountId}`);
23216
+ return c.json({ error: "taskId required" }, 400);
23217
+ }
23218
+ const session = getSession();
23219
+ try {
23220
+ const found = await session.run(
23221
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
23222
+ OPTIONAL MATCH (t)-[:WORKED_ON_IN]->(conv:Conversation)
23223
+ WITH t, head(collect(conv)) AS linked
23224
+ RETURN t.name AS name, linked.sessionId AS sessionId LIMIT 1`,
23225
+ { taskId, accountId }
23226
+ );
23227
+ if (found.records.length === 0) {
23228
+ console.error(`${TAG34} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
23229
+ return c.json({ error: "task-not-found" }, 404);
23230
+ }
23231
+ const title = found.records[0].get("name") ?? "";
23232
+ const sessionId = found.records[0].get("sessionId") ?? null;
23233
+ console.log(`${TAG34} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
23234
+ if (sessionId !== null) return c.json({ sessionId, title, accountId });
23235
+ const now = (/* @__PURE__ */ new Date()).toISOString();
23236
+ const stamped = await session.run(
23237
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
23238
+ SET t.sessionSpawnRequestedAt = $now
23239
+ RETURN t.sessionSpawnRequestedAt AS at`,
23240
+ { taskId, accountId, now }
23241
+ );
23242
+ const at = stamped.records[0]?.get("at") ?? void 0;
23243
+ console.log(`${TAG34} op=marker taskId=${taskId} stamped=${at !== void 0}`);
23244
+ return c.json({ sessionId: null, title, accountId });
23245
+ } catch (err) {
23246
+ console.error(`${TAG34} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
23247
+ return c.json({ error: "task-session-open-failed" }, 500);
23248
+ } finally {
23249
+ await session.close();
23250
+ }
23251
+ });
23252
+ var task_session_open_default = app59;
23253
+
23254
+ // server/routes/admin/task-session-link.ts
23255
+ var TAG35 = "[task-session]";
23256
+ var app60 = new Hono();
23257
+ app60.post("/", requireAdminSession, async (c) => {
23258
+ const cacheKey = c.var.cacheKey;
23259
+ const accountId = getAccountIdForSession(cacheKey);
23260
+ if (!accountId) {
23261
+ console.error(`${TAG35} op=link auth-rejected reason="no account for session"`);
23262
+ return c.json({ error: "Account not found for session" }, 401);
23263
+ }
23264
+ let body;
23265
+ try {
23266
+ body = await c.req.json();
23267
+ } catch {
23268
+ return c.json({ error: "invalid-json" }, 400);
23269
+ }
23270
+ const taskId = typeof body.taskId === "string" ? body.taskId : "";
23271
+ if (!taskId) {
23272
+ const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
23273
+ console.error(`${TAG35} op=link rejected reason=${reason} account=${accountId}`);
23274
+ return c.json({ error: "taskId required" }, 400);
23275
+ }
23276
+ const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : "";
23277
+ if (!sessionId) {
23278
+ console.error(`${TAG35} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
23279
+ return c.json({ error: "sessionId required" }, 400);
23280
+ }
23281
+ const session = getSession();
23282
+ try {
23283
+ const state = await session.run(
23284
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
23285
+ OPTIONAL MATCH (target:Conversation {sessionId: $sessionId, accountId: $accountId})
23286
+ OPTIONAL MATCH (t)-[:WORKED_ON_IN]->(prev:Conversation)
23287
+ RETURN target IS NOT NULL AS conversationExists,
23288
+ collect(DISTINCT prev.sessionId) AS priorSessionIds`,
23289
+ { taskId, accountId, sessionId }
23290
+ );
23291
+ if (state.records.length === 0) {
23292
+ console.error(`${TAG35} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
23293
+ return c.json({ error: "task-not-found" }, 404);
23294
+ }
23295
+ const conversationExists = state.records[0].get("conversationExists") === true;
23296
+ const priorSessionIds = (state.records[0].get("priorSessionIds") ?? []).filter((s) => typeof s === "string");
23297
+ if (!conversationExists) {
23298
+ console.error(`${TAG35} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
23299
+ return c.json({ linked: false, created: false, repointedFrom: null });
23300
+ }
23301
+ const stale = priorSessionIds.filter((s) => s !== sessionId);
23302
+ await session.run(
23303
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
23304
+ MATCH (target:Conversation {sessionId: $sessionId, accountId: $accountId})
23305
+ OPTIONAL MATCH (t)-[r:WORKED_ON_IN]->(prev:Conversation)
23306
+ WHERE prev.sessionId <> $sessionId
23307
+ DELETE r
23308
+ WITH DISTINCT t, target
23309
+ MERGE (t)-[:WORKED_ON_IN]->(target)
23310
+ REMOVE t.sessionSpawnRequestedAt`,
23311
+ { taskId, accountId, sessionId }
23312
+ );
23313
+ const verify = await session.run(
23314
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})-[:WORKED_ON_IN]->(c:Conversation)
23315
+ RETURN c.sessionId AS sessionId LIMIT 1`,
23316
+ { taskId, accountId }
23317
+ );
23318
+ const linkedTo = verify.records[0]?.get("sessionId") ?? null;
23319
+ const linked = linkedTo === sessionId;
23320
+ const created = linked && !priorSessionIds.includes(sessionId);
23321
+ const repointedFrom = stale.length > 0 ? stale[0] : null;
23322
+ if (!linked) {
23323
+ console.error(
23324
+ `${TAG35} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
23325
+ );
23326
+ return c.json({ linked: false, created: false, repointedFrom });
23327
+ }
23328
+ console.log(
23329
+ `${TAG35} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
23330
+ );
23331
+ invalidate("tasks-list", accountId);
23332
+ return c.json({ linked: true, created, repointedFrom });
23333
+ } catch (err) {
23334
+ console.error(
23335
+ `${TAG35} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
23336
+ );
23337
+ return c.json({ error: "task-session-link-failed" }, 500);
23338
+ } finally {
23339
+ await session.close();
23340
+ }
23341
+ });
23342
+ var task_session_link_default = app60;
23343
+
23344
+ // server/routes/admin/admin-users-list.ts
23345
+ var TAG36 = "[admin-users]";
23346
+ var app61 = new Hono();
23347
+ app61.get("/", requireAdminSession, async (c) => {
23348
+ const cacheKey = c.var.cacheKey;
23349
+ const accountId = getAccountIdForSession(cacheKey);
23350
+ if (!accountId) {
23351
+ console.error(`${TAG36} op=list auth-rejected reason="no account for session"`);
22960
23352
  return c.json({ error: "Account not found for session" }, 401);
22961
23353
  }
22962
23354
  try {
22963
23355
  const users = await resolveAssignableAdmins(accountId);
22964
- console.log(`${TAG33} op=list account=${accountId} count=${users.length}`);
23356
+ console.log(`${TAG36} op=list account=${accountId} count=${users.length}`);
22965
23357
  return c.json({ ok: true, users });
22966
23358
  } catch (err) {
22967
- console.error(`${TAG33} op=list error="${err instanceof Error ? err.message : String(err)}"`);
23359
+ console.error(`${TAG36} op=list error="${err instanceof Error ? err.message : String(err)}"`);
22968
23360
  return c.json({ error: "admin-users-list-failed" }, 500);
22969
23361
  }
22970
23362
  });
22971
- var admin_users_list_default = app59;
23363
+ var admin_users_list_default = app61;
22972
23364
 
22973
23365
  // server/routes/admin/activity.ts
22974
23366
  import { readdirSync as readdirSync26 } from "fs";
22975
- var app60 = new Hono();
22976
- var TAG34 = "[activity]";
23367
+ var app62 = new Hono();
23368
+ var TAG37 = "[activity]";
22977
23369
  function resolveHouseAccountId(accounts) {
22978
23370
  const houses = accounts.filter((a) => a.config.role === "house");
22979
23371
  if (houses.length === 1) return { accountId: houses[0].accountId, reason: "house" };
@@ -22994,7 +23386,7 @@ function countAccountDirsOnDisk() {
22994
23386
  return null;
22995
23387
  }
22996
23388
  }
22997
- app60.get("/", requireAdminSession, async (c) => {
23389
+ app62.get("/", requireAdminSession, async (c) => {
22998
23390
  const req = requestToken();
22999
23391
  const cacheKey = c.var.cacheKey;
23000
23392
  const caller2 = getAccountIdForSession(cacheKey) ?? null;
@@ -23002,19 +23394,19 @@ app60.get("/", requireAdminSession, async (c) => {
23002
23394
  const house = resolveHouseAccountId(valid);
23003
23395
  const isHouse = caller2 !== null && house.accountId !== null && caller2 === house.accountId;
23004
23396
  console.log(
23005
- `${TAG34} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
23397
+ `${TAG37} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
23006
23398
  );
23007
23399
  if (!isHouse) {
23008
23400
  const reason = house.accountId === null ? house.reason : "not-house";
23009
23401
  console.error(
23010
- `${TAG34} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
23402
+ `${TAG37} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
23011
23403
  );
23012
23404
  return c.json({ error: "house-only" }, 403);
23013
23405
  }
23014
- console.log(`${TAG34} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
23406
+ console.log(`${TAG37} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
23015
23407
  const onDisk = countAccountDirsOnDisk();
23016
23408
  console.log(
23017
- `${TAG34} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
23409
+ `${TAG37} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
23018
23410
  );
23019
23411
  const start = Date.now();
23020
23412
  let res;
@@ -23030,17 +23422,17 @@ app60.get("/", requireAdminSession, async (c) => {
23030
23422
  });
23031
23423
  } catch (err) {
23032
23424
  console.error(
23033
- `${TAG34} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
23425
+ `${TAG37} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
23034
23426
  );
23035
23427
  return c.json({ error: "manager-unreachable" }, 502);
23036
23428
  }
23037
23429
  if (res.status !== 200) {
23038
- console.error(`${TAG34} op=manager-fail req=${req} reason=status status=${res.status}`);
23430
+ console.error(`${TAG37} op=manager-fail req=${req} reason=status status=${res.status}`);
23039
23431
  return c.json({ error: `manager-status-${res.status}` }, 502);
23040
23432
  }
23041
23433
  const body = await res.json().catch(() => null);
23042
23434
  if (!body || !Array.isArray(body.rows)) {
23043
- console.error(`${TAG34} op=manager-fail req=${req} reason=bad-json`);
23435
+ console.error(`${TAG37} op=manager-fail req=${req} reason=bad-json`);
23044
23436
  return c.json({ error: "manager-bad-json" }, 502);
23045
23437
  }
23046
23438
  const rows = body.rows;
@@ -23051,10 +23443,10 @@ app60.get("/", requireAdminSession, async (c) => {
23051
23443
  const ageNull = rows.filter((r) => r.ageMs === null).length;
23052
23444
  const sidecarNull = rows.filter((r) => r.sidecarMissing).length;
23053
23445
  console.log(
23054
- `${TAG34} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
23446
+ `${TAG37} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
23055
23447
  );
23056
23448
  console.log(
23057
- `${TAG34} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
23449
+ `${TAG37} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
23058
23450
  );
23059
23451
  const names = {};
23060
23452
  await Promise.all(
@@ -23073,7 +23465,7 @@ app60.get("/", requireAdminSession, async (c) => {
23073
23465
  return acc;
23074
23466
  }, {});
23075
23467
  console.log(
23076
- `${TAG34} 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(" ")
23468
+ `${TAG37} 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(" ")
23077
23469
  );
23078
23470
  return c.json({
23079
23471
  rows,
@@ -23103,66 +23495,68 @@ app60.get("/", requireAdminSession, async (c) => {
23103
23495
  }
23104
23496
  });
23105
23497
  });
23106
- var activity_default = app60;
23498
+ var activity_default = app62;
23107
23499
 
23108
23500
  // server/routes/admin/index.ts
23109
- var app61 = new Hono();
23110
- app61.route("/session", session_default);
23111
- app61.route("/accounts", accounts_default);
23112
- app61.route("/logs", logs_default);
23113
- app61.route("/claude-info", claude_info_default);
23114
- app61.route("/attachment", attachment_default);
23115
- app61.route("/session-upload", session_upload_default);
23116
- app61.route("/agents", agents_default);
23117
- app61.route("/sessions", sessions_default);
23118
- app61.route("/claude-sessions", claude_sessions_default);
23119
- app61.route("/log-ingest", log_ingest_default);
23120
- app61.route("/events", events_default);
23121
- app61.route("/files", files_default);
23122
- app61.route("/graph-search", graph_search_default);
23123
- app61.route("/graph-subgraph", graph_subgraph_default);
23124
- app61.route("/graph-delete", graph_delete_default);
23125
- app61.route("/graph-restore", graph_restore_default);
23126
- app61.route("/graph-labels-in-graph", graph_labels_in_graph_default);
23127
- app61.route("/graph-default-view", graph_default_view_default);
23128
- app61.route("/sidebar-artefacts", sidebar_artefacts_default);
23129
- app61.route("/sidebar-sessions", sidebar_sessions_default);
23130
- app61.route("/session-delete", session_delete_default);
23131
- app61.route("/session-stop", session_stop_default);
23132
- app61.route("/session-archive", session_archive_default);
23133
- app61.route("/session-rename", session_rename_default);
23134
- app61.route("/session-usage", session_usage_default);
23135
- app61.route("/browser", browser_default);
23136
- app61.route("/session-rc-spawn", session_rc_spawn_default);
23137
- app61.route("/session-reseat", session_reseat_default);
23138
- app61.route("/system-stats", system_stats_default);
23139
- app61.route("/health-brand", health_default2);
23140
- app61.route("/linkedin-ingest", linkedin_ingest_default);
23141
- app61.route("/post-turn-context", post_turn_context_default);
23142
- app61.route("/public-session-context", public_session_context_default);
23143
- app61.route("/public-session-exit", public_session_exit_default);
23144
- app61.route("/access-session-evict", access_session_evict_default);
23145
- app61.route("/enrol-person", enrol_person_default);
23146
- app61.route("/calendar", calendar_default);
23147
- app61.route("/data-portal", data_portal_default);
23148
- app61.route("/routines", routines_default);
23149
- app61.route("/skills", skills_default);
23150
- app61.route("/tasks-list", tasks_list_default);
23151
- app61.route("/task-timer-start", task_timer_start_default);
23152
- app61.route("/task-timer-stop", task_timer_stop_default);
23153
- app61.route("/task-complete", task_complete_default);
23154
- app61.route("/task-time-adjust", task_time_adjust_default);
23155
- app61.route("/task-assign", task_assign_default);
23156
- app61.route("/admin-users-list", admin_users_list_default);
23157
- app61.route("/activity", activity_default);
23158
- var admin_default = app61;
23501
+ var app63 = new Hono();
23502
+ app63.route("/session", session_default);
23503
+ app63.route("/accounts", accounts_default);
23504
+ app63.route("/logs", logs_default);
23505
+ app63.route("/claude-info", claude_info_default);
23506
+ app63.route("/attachment", attachment_default);
23507
+ app63.route("/session-upload", session_upload_default);
23508
+ app63.route("/agents", agents_default);
23509
+ app63.route("/sessions", sessions_default);
23510
+ app63.route("/claude-sessions", claude_sessions_default);
23511
+ app63.route("/log-ingest", log_ingest_default);
23512
+ app63.route("/events", events_default);
23513
+ app63.route("/files", files_default);
23514
+ app63.route("/graph-search", graph_search_default);
23515
+ app63.route("/graph-subgraph", graph_subgraph_default);
23516
+ app63.route("/graph-delete", graph_delete_default);
23517
+ app63.route("/graph-restore", graph_restore_default);
23518
+ app63.route("/graph-labels-in-graph", graph_labels_in_graph_default);
23519
+ app63.route("/graph-default-view", graph_default_view_default);
23520
+ app63.route("/sidebar-artefacts", sidebar_artefacts_default);
23521
+ app63.route("/sidebar-sessions", sidebar_sessions_default);
23522
+ app63.route("/session-delete", session_delete_default);
23523
+ app63.route("/session-stop", session_stop_default);
23524
+ app63.route("/session-archive", session_archive_default);
23525
+ app63.route("/session-rename", session_rename_default);
23526
+ app63.route("/session-usage", session_usage_default);
23527
+ app63.route("/browser", browser_default);
23528
+ app63.route("/session-rc-spawn", session_rc_spawn_default);
23529
+ app63.route("/session-reseat", session_reseat_default);
23530
+ app63.route("/system-stats", system_stats_default);
23531
+ app63.route("/health-brand", health_default2);
23532
+ app63.route("/linkedin-ingest", linkedin_ingest_default);
23533
+ app63.route("/post-turn-context", post_turn_context_default);
23534
+ app63.route("/public-session-context", public_session_context_default);
23535
+ app63.route("/public-session-exit", public_session_exit_default);
23536
+ app63.route("/access-session-evict", access_session_evict_default);
23537
+ app63.route("/enrol-person", enrol_person_default);
23538
+ app63.route("/calendar", calendar_default);
23539
+ app63.route("/data-portal", data_portal_default);
23540
+ app63.route("/routines", routines_default);
23541
+ app63.route("/skills", skills_default);
23542
+ app63.route("/tasks-list", tasks_list_default);
23543
+ app63.route("/task-timer-start", task_timer_start_default);
23544
+ app63.route("/task-timer-stop", task_timer_stop_default);
23545
+ app63.route("/task-complete", task_complete_default);
23546
+ app63.route("/task-time-adjust", task_time_adjust_default);
23547
+ app63.route("/task-assign", task_assign_default);
23548
+ app63.route("/task-session-open", task_session_open_default);
23549
+ app63.route("/task-session-link", task_session_link_default);
23550
+ app63.route("/admin-users-list", admin_users_list_default);
23551
+ app63.route("/activity", activity_default);
23552
+ var admin_default = app63;
23159
23553
 
23160
23554
  // server/routes/access/verify-token.ts
23161
- var TAG35 = "[access-verify]";
23555
+ var TAG38 = "[access-verify]";
23162
23556
  var MINT_TAG = "[access-session-mint]";
23163
23557
  var COOKIE_NAME = "__access_session";
23164
- var app62 = new Hono();
23165
- app62.post("/", async (c) => {
23558
+ var app64 = new Hono();
23559
+ app64.post("/", async (c) => {
23166
23560
  const ip = c.var.clientIp || "unknown";
23167
23561
  let body;
23168
23562
  try {
@@ -23177,39 +23571,39 @@ app62.post("/", async (c) => {
23177
23571
  }
23178
23572
  const rateMsg = checkAccessRateLimit(ip, agentSlug);
23179
23573
  if (rateMsg) {
23180
- console.error(`${TAG35} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
23574
+ console.error(`${TAG38} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
23181
23575
  return c.json({ error: rateMsg }, 429);
23182
23576
  }
23183
23577
  const grant = await findGrantByMagicToken(token);
23184
23578
  if (!grant) {
23185
23579
  recordAccessFailedAttempt(ip, agentSlug);
23186
- console.error(`${TAG35} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
23580
+ console.error(`${TAG38} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
23187
23581
  return c.json({ error: "invalid-or-expired-link" }, 401);
23188
23582
  }
23189
23583
  if (grant.agentSlug !== agentSlug) {
23190
23584
  recordAccessFailedAttempt(ip, agentSlug);
23191
23585
  console.error(
23192
- `${TAG35} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
23586
+ `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
23193
23587
  );
23194
23588
  return c.json({ error: "invalid-or-expired-link" }, 401);
23195
23589
  }
23196
23590
  if (grant.status === "expired" || grant.status === "revoked") {
23197
23591
  recordAccessFailedAttempt(ip, agentSlug);
23198
23592
  console.error(
23199
- `${TAG35} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
23593
+ `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
23200
23594
  );
23201
23595
  return c.json({ error: "access-no-longer-valid" }, 401);
23202
23596
  }
23203
23597
  if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
23204
23598
  recordAccessFailedAttempt(ip, agentSlug);
23205
23599
  console.error(
23206
- `${TAG35} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
23600
+ `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
23207
23601
  );
23208
23602
  return c.json({ error: "access-no-longer-valid" }, 401);
23209
23603
  }
23210
23604
  if (!grant.sliceToken) {
23211
23605
  console.error(
23212
- `${TAG35} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
23606
+ `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
23213
23607
  );
23214
23608
  return c.json({ error: "grant-misconfigured" }, 500);
23215
23609
  }
@@ -23225,12 +23619,12 @@ app62.post("/", async (c) => {
23225
23619
  await consumeMagicTokenAndActivate(grant.grantId);
23226
23620
  } catch (err) {
23227
23621
  console.error(
23228
- `${TAG35} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
23622
+ `${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
23229
23623
  );
23230
23624
  return c.json({ error: "verification-failed" }, 500);
23231
23625
  }
23232
23626
  clearAccessRateLimit(ip, agentSlug);
23233
- console.log(`${TAG35} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
23627
+ console.log(`${TAG38} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
23234
23628
  console.log(
23235
23629
  `${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
23236
23630
  );
@@ -23244,7 +23638,7 @@ app62.post("/", async (c) => {
23244
23638
  displayName: grant.displayName
23245
23639
  });
23246
23640
  });
23247
- var verify_token_default = app62;
23641
+ var verify_token_default = app64;
23248
23642
 
23249
23643
  // app/lib/access-email.ts
23250
23644
  import { spawn as spawn2 } from "child_process";
@@ -23306,10 +23700,10 @@ async function sendMagicLinkEmail(payload) {
23306
23700
  }
23307
23701
 
23308
23702
  // server/routes/access/request-magic-link.ts
23309
- var TAG36 = "[access-request-link]";
23310
- var app63 = new Hono();
23703
+ var TAG39 = "[access-request-link]";
23704
+ var app65 = new Hono();
23311
23705
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
23312
- app63.post("/", async (c) => {
23706
+ app65.post("/", async (c) => {
23313
23707
  let body;
23314
23708
  try {
23315
23709
  body = await c.req.json();
@@ -23323,18 +23717,18 @@ app63.post("/", async (c) => {
23323
23717
  }
23324
23718
  const rateMsg = checkRequestLinkRateLimit(contactValue);
23325
23719
  if (rateMsg) {
23326
- console.error(`${TAG36} contactValue=${maskContact(contactValue)} result=rate-limited`);
23720
+ console.error(`${TAG39} contactValue=${maskContact(contactValue)} result=rate-limited`);
23327
23721
  return c.json({ error: rateMsg }, 429);
23328
23722
  }
23329
23723
  recordRequestLinkAttempt(contactValue);
23330
23724
  const accountId = process.env.ACCOUNT_ID ?? "";
23331
23725
  if (!accountId) {
23332
- console.error(`${TAG36} contactValue=${maskContact(contactValue)} result=no-account-id`);
23726
+ console.error(`${TAG39} contactValue=${maskContact(contactValue)} result=no-account-id`);
23333
23727
  return c.json({ message: VISITOR_MESSAGE }, 200);
23334
23728
  }
23335
23729
  const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
23336
23730
  if (!grant) {
23337
- console.log(`${TAG36} contactValue=${maskContact(contactValue)} result=notfound`);
23731
+ console.log(`${TAG39} contactValue=${maskContact(contactValue)} result=notfound`);
23338
23732
  return c.json({ message: VISITOR_MESSAGE }, 200);
23339
23733
  }
23340
23734
  let token;
@@ -23342,7 +23736,7 @@ app63.post("/", async (c) => {
23342
23736
  token = await generateNewMagicToken(grant.grantId);
23343
23737
  } catch (err) {
23344
23738
  console.error(
23345
- `${TAG36} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
23739
+ `${TAG39} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
23346
23740
  );
23347
23741
  return c.json({ message: VISITOR_MESSAGE }, 200);
23348
23742
  }
@@ -23374,22 +23768,22 @@ app63.post("/", async (c) => {
23374
23768
  });
23375
23769
  if (!sendResult.ok) {
23376
23770
  console.error(
23377
- `${TAG36} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
23771
+ `${TAG39} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
23378
23772
  );
23379
23773
  return c.json({ message: VISITOR_MESSAGE }, 200);
23380
23774
  }
23381
23775
  console.log(
23382
- `${TAG36} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
23776
+ `${TAG39} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
23383
23777
  );
23384
23778
  return c.json({ message: VISITOR_MESSAGE }, 200);
23385
23779
  });
23386
- var request_magic_link_default = app63;
23780
+ var request_magic_link_default = app65;
23387
23781
 
23388
23782
  // server/routes/access/index.ts
23389
- var app64 = new Hono();
23390
- app64.route("/verify-token", verify_token_default);
23391
- app64.route("/request-magic-link", request_magic_link_default);
23392
- var access_default = app64;
23783
+ var app66 = new Hono();
23784
+ app66.route("/verify-token", verify_token_default);
23785
+ app66.route("/request-magic-link", request_magic_link_default);
23786
+ var access_default = app66;
23393
23787
 
23394
23788
  // server/routes/sites.ts
23395
23789
  import { existsSync as existsSync41, readFileSync as readFileSync38, realpathSync as realpathSync8, statSync as statSync21 } from "fs";
@@ -23424,8 +23818,8 @@ function getExt(p) {
23424
23818
  if (idx < p.lastIndexOf("/")) return "";
23425
23819
  return p.slice(idx).toLowerCase();
23426
23820
  }
23427
- var app65 = new Hono();
23428
- app65.get("/:rel{.*}", (c) => {
23821
+ var app67 = new Hono();
23822
+ app67.get("/:rel{.*}", (c) => {
23429
23823
  const reqPath = c.req.path;
23430
23824
  const rawRel = c.req.param("rel") ?? "";
23431
23825
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -23528,7 +23922,7 @@ app65.get("/:rel{.*}", (c) => {
23528
23922
  "X-Content-Type-Options": "nosniff"
23529
23923
  });
23530
23924
  });
23531
- var sites_default = app65;
23925
+ var sites_default = app67;
23532
23926
 
23533
23927
  // app/lib/visitor-token.ts
23534
23928
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
@@ -23609,7 +24003,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
23609
24003
 
23610
24004
  // app/lib/brand-config.ts
23611
24005
  import { existsSync as existsSync42, readFileSync as readFileSync40 } from "fs";
23612
- import { join as join45 } from "path";
24006
+ import { join as join46 } from "path";
23613
24007
  var cached2 = null;
23614
24008
  var cachedAttempted = false;
23615
24009
  function readBrandConfig() {
@@ -23617,7 +24011,7 @@ function readBrandConfig() {
23617
24011
  cachedAttempted = true;
23618
24012
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
23619
24013
  if (!platformRoot5) return null;
23620
- const brandPath = join45(platformRoot5, "config", "brand.json");
24014
+ const brandPath = join46(platformRoot5, "config", "brand.json");
23621
24015
  if (!existsSync42(brandPath)) return null;
23622
24016
  try {
23623
24017
  cached2 = JSON.parse(readFileSync40(brandPath, "utf-8"));
@@ -23628,7 +24022,7 @@ function readBrandConfig() {
23628
24022
  }
23629
24023
 
23630
24024
  // server/routes/visitor-consent.ts
23631
- var app66 = new Hono();
24025
+ var app68 = new Hono();
23632
24026
  var CONSENT_COOKIE_NAME = "mxy_consent";
23633
24027
  var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
23634
24028
  var DEFAULT_CONSENT_COPY = {
@@ -23673,17 +24067,17 @@ function siteSlugFromReferer(referer) {
23673
24067
  return "";
23674
24068
  }
23675
24069
  }
23676
- app66.options("/consent", (c) => {
24070
+ app68.options("/consent", (c) => {
23677
24071
  const origin = getOrigin(c);
23678
24072
  setCorsHeaders(c, origin);
23679
24073
  return c.body(null, 204);
23680
24074
  });
23681
- app66.options("/brand-config", (c) => {
24075
+ app68.options("/brand-config", (c) => {
23682
24076
  const origin = getOrigin(c);
23683
24077
  setCorsHeaders(c, origin);
23684
24078
  return c.body(null, 204);
23685
24079
  });
23686
- app66.post("/consent", async (c) => {
24080
+ app68.post("/consent", async (c) => {
23687
24081
  const origin = getOrigin(c);
23688
24082
  setCorsHeaders(c, origin);
23689
24083
  let raw;
@@ -23723,7 +24117,7 @@ app66.post("/consent", async (c) => {
23723
24117
  console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
23724
24118
  return c.body(null, 204);
23725
24119
  });
23726
- app66.get("/brand-config", (c) => {
24120
+ app68.get("/brand-config", (c) => {
23727
24121
  const origin = getOrigin(c);
23728
24122
  setCorsHeaders(c, origin);
23729
24123
  const brand = readBrandConfig();
@@ -23733,7 +24127,7 @@ app66.get("/brand-config", (c) => {
23733
24127
  c.header("Cache-Control", "public, max-age=300");
23734
24128
  return c.json({ consent: { copy, palette } });
23735
24129
  });
23736
- var visitor_consent_default = app66;
24130
+ var visitor_consent_default = app68;
23737
24131
 
23738
24132
  // server/routes/listings.ts
23739
24133
  function getCookie(headerValue, name) {
@@ -23760,8 +24154,8 @@ function appendConsentParams(pageUrl, token) {
23760
24154
  }
23761
24155
  var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
23762
24156
  var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
23763
- var app67 = new Hono();
23764
- app67.get("/:slug/click", async (c) => {
24157
+ var app69 = new Hono();
24158
+ app69.get("/:slug/click", async (c) => {
23765
24159
  const slug = c.req.param("slug") ?? "";
23766
24160
  const rawSession = c.req.query("session") ?? "";
23767
24161
  const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
@@ -23825,10 +24219,10 @@ app67.get("/:slug/click", async (c) => {
23825
24219
  console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
23826
24220
  return c.redirect(redirectUrl, 302);
23827
24221
  });
23828
- var listings_default = app67;
24222
+ var listings_default = app69;
23829
24223
 
23830
24224
  // server/routes/visitor-event.ts
23831
- var app68 = new Hono();
24225
+ var app70 = new Hono();
23832
24226
  var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
23833
24227
  var buckets = /* @__PURE__ */ new Map();
23834
24228
  var RATE_LIMIT = 60;
@@ -23904,12 +24298,12 @@ function originAllowed(origin, allowlist) {
23904
24298
  return false;
23905
24299
  }
23906
24300
  }
23907
- app68.options("/event", (c) => {
24301
+ app70.options("/event", (c) => {
23908
24302
  const origin = getOrigin2(c);
23909
24303
  setCorsHeaders2(c, origin);
23910
24304
  return c.body(null, 204);
23911
24305
  });
23912
- app68.post("/event", async (c) => {
24306
+ app70.post("/event", async (c) => {
23913
24307
  const origin = getOrigin2(c);
23914
24308
  setCorsHeaders2(c, origin);
23915
24309
  const ua = c.req.header("user-agent") ?? "";
@@ -24114,7 +24508,7 @@ async function writeEvent(opts) {
24114
24508
  );
24115
24509
  }
24116
24510
  }
24117
- var visitor_event_default = app68;
24511
+ var visitor_event_default = app70;
24118
24512
 
24119
24513
  // server/routes/session.ts
24120
24514
  import { resolve as resolve34 } from "path";
@@ -24160,8 +24554,8 @@ function withVisitorCookie(response, visitorId) {
24160
24554
  headers
24161
24555
  });
24162
24556
  }
24163
- var app69 = new Hono();
24164
- app69.post("/", async (c) => {
24557
+ var app71 = new Hono();
24558
+ app71.post("/", async (c) => {
24165
24559
  let body;
24166
24560
  try {
24167
24561
  body = await c.req.json();
@@ -24308,7 +24702,7 @@ app69.post("/", async (c) => {
24308
24702
  newVisitorId
24309
24703
  );
24310
24704
  });
24311
- var session_default2 = app69;
24705
+ var session_default2 = app71;
24312
24706
 
24313
24707
  // server/lib/calendar-slots.ts
24314
24708
  var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
@@ -24391,17 +24785,17 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
24391
24785
  }
24392
24786
 
24393
24787
  // server/routes/calendar-public.ts
24394
- var app70 = new Hono();
24788
+ var app72 = new Hono();
24395
24789
  function setCors(c) {
24396
24790
  c.header("Access-Control-Allow-Origin", "*");
24397
24791
  c.header("Access-Control-Allow-Methods", "GET, OPTIONS");
24398
24792
  c.header("Access-Control-Allow-Headers", "content-type");
24399
24793
  }
24400
- app70.options("/free-busy", (c) => {
24794
+ app72.options("/free-busy", (c) => {
24401
24795
  setCors(c);
24402
24796
  return c.body(null, 204);
24403
24797
  });
24404
- app70.get("/free-busy", async (c) => {
24798
+ app72.get("/free-busy", async (c) => {
24405
24799
  setCors(c);
24406
24800
  const from = c.req.query("from");
24407
24801
  const to = c.req.query("to");
@@ -24457,15 +24851,15 @@ app70.get("/free-busy", async (c) => {
24457
24851
  await session.close();
24458
24852
  }
24459
24853
  });
24460
- var calendar_public_default = app70;
24854
+ var calendar_public_default = app72;
24461
24855
 
24462
24856
  // server/routes/portal-fetch.ts
24463
24857
  import { createReadStream as createReadStream3 } from "fs";
24464
24858
  import { stat as stat8, readFile as readFile11, realpath } from "fs/promises";
24465
- import { join as join46, resolve as resolve35, sep as sep11 } from "path";
24859
+ import { join as join47, resolve as resolve35, sep as sep11 } from "path";
24466
24860
  import { Readable as Readable3 } from "stream";
24467
- var app71 = new Hono();
24468
- var TAG37 = "[portal-fetch]";
24861
+ var app73 = new Hono();
24862
+ var TAG40 = "[portal-fetch]";
24469
24863
  async function verifySignature(secret, accountId, relPath, expiresAtMs, signature, nowMs) {
24470
24864
  if (!secret || !signature) return false;
24471
24865
  if (!Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return false;
@@ -24520,14 +24914,14 @@ async function readAccountSecret(accountId) {
24520
24914
  try {
24521
24915
  text = await readFile11(path, "utf8");
24522
24916
  } catch {
24523
- console.error(`${TAG37} op=no-secret account="${accountId}" path="${path}"`);
24917
+ console.error(`${TAG40} op=no-secret account="${accountId}" path="${path}"`);
24524
24918
  return "";
24525
24919
  }
24526
24920
  for (const line of text.split("\n")) {
24527
24921
  const m = line.match(/^PORTAL_FETCH_SECRET=(.*)$/);
24528
24922
  if (m) return m[1].trim();
24529
24923
  }
24530
- console.error(`${TAG37} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
24924
+ console.error(`${TAG40} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
24531
24925
  return "";
24532
24926
  }
24533
24927
  function isValidAccountId2(value) {
@@ -24535,7 +24929,7 @@ function isValidAccountId2(value) {
24535
24929
  }
24536
24930
  async function readExposeFolders2(accountDir) {
24537
24931
  try {
24538
- const cfg = JSON.parse(await readFile11(join46(accountDir, "data-portal.json"), "utf8"));
24932
+ const cfg = JSON.parse(await readFile11(join47(accountDir, "data-portal.json"), "utf8"));
24539
24933
  return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
24540
24934
  } catch {
24541
24935
  return [];
@@ -24544,7 +24938,7 @@ async function readExposeFolders2(accountDir) {
24544
24938
  async function resolveFetchTarget(accountDir, relPath, ownerId) {
24545
24939
  let schemaText = null;
24546
24940
  try {
24547
- schemaText = await readFile11(join46(accountDir, "SCHEMA.md"), "utf8");
24941
+ schemaText = await readFile11(join47(accountDir, "SCHEMA.md"), "utf8");
24548
24942
  } catch {
24549
24943
  schemaText = null;
24550
24944
  }
@@ -24587,16 +24981,16 @@ async function handle(c, headOnly) {
24587
24981
  const sig = c.req.query("sig") ?? "";
24588
24982
  const owner = c.req.query("owner") ?? "";
24589
24983
  console.log(
24590
- `${TAG37} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
24984
+ `${TAG40} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
24591
24985
  );
24592
24986
  if (!isValidAccountId2(accountId)) {
24593
- console.error(`${TAG37} op=denied account=${q(accountId)} reason=account-id`);
24987
+ console.error(`${TAG40} op=denied account=${q(accountId)} reason=account-id`);
24594
24988
  return c.json({ ok: false, error: "denied" }, 401);
24595
24989
  }
24596
24990
  const secret = await readAccountSecret(accountId);
24597
24991
  const verified = owner ? await verifyOwnUploadSignature(secret, accountId, owner, relPath, exp, sig, Date.now()) : await verifySignature(secret, accountId, relPath, exp, sig, Date.now());
24598
24992
  if (!verified) {
24599
- console.error(`${TAG37} op=denied account=${q(accountId)} reason=secret`);
24993
+ console.error(`${TAG40} op=denied account=${q(accountId)} reason=secret`);
24600
24994
  return c.json({ ok: false, error: "denied" }, 401);
24601
24995
  }
24602
24996
  const target = await resolveFetchTarget(
@@ -24606,14 +25000,14 @@ async function handle(c, headOnly) {
24606
25000
  );
24607
25001
  if (!target.ok) {
24608
25002
  const op = target.reason === "enoent" ? "miss" : "denied";
24609
- console.error(`${TAG37} op=${op} account=${accountId} reason=${target.reason}`);
25003
+ console.error(`${TAG40} op=${op} account=${accountId} reason=${target.reason}`);
24610
25004
  return c.json({ ok: false, error: "not found" }, 404);
24611
25005
  }
24612
25006
  if (headOnly) {
24613
- console.log(`${TAG37} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
25007
+ console.log(`${TAG40} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
24614
25008
  return c.body(null, 200);
24615
25009
  }
24616
- console.log(`${TAG37} op=served account=${accountId} bytes=${target.sizeBytes}`);
25010
+ console.log(`${TAG40} op=served account=${accountId} bytes=${target.sizeBytes}`);
24617
25011
  return new Response(Readable3.toWeb(createReadStream3(target.absolute)), {
24618
25012
  status: 200,
24619
25013
  headers: {
@@ -24627,12 +25021,12 @@ async function handle(c, headOnly) {
24627
25021
  }
24628
25022
  });
24629
25023
  }
24630
- app71.get("/fetch", (c) => handle(c, false));
24631
- app71.on("HEAD", "/fetch", (c) => handle(c, true));
24632
- var portal_fetch_default = app71;
25024
+ app73.get("/fetch", (c) => handle(c, false));
25025
+ app73.on("HEAD", "/fetch", (c) => handle(c, true));
25026
+ var portal_fetch_default = app73;
24633
25027
 
24634
25028
  // app/lib/timeentry-census.ts
24635
- var TAG38 = "[timeentry-census]";
25029
+ var TAG41 = "[timeentry-census]";
24636
25030
  function reconcileTimeEntries(rows, now, horizonMs) {
24637
25031
  const openEntries = rows.openEntries.length;
24638
25032
  let oldestOpenAgeMs = 0;
@@ -24672,12 +25066,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
24672
25066
  sumAdjustments: toNum(r.get("sumAdjustments"))
24673
25067
  }));
24674
25068
  const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
24675
- const line = `${TAG38} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
25069
+ const line = `${TAG41} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
24676
25070
  if (finding.alarm) console.error(`${line} alarm=true`);
24677
25071
  else console.log(line);
24678
25072
  return finding;
24679
25073
  } catch (err) {
24680
- console.error(`${TAG38} error="${err instanceof Error ? err.message : String(err)}"`);
25074
+ console.error(`${TAG41} error="${err instanceof Error ? err.message : String(err)}"`);
24681
25075
  return null;
24682
25076
  }
24683
25077
  }
@@ -24691,13 +25085,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
24691
25085
  try {
24692
25086
  session = openSession();
24693
25087
  } catch (err) {
24694
- console.error(`${TAG38} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
25088
+ console.error(`${TAG41} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
24695
25089
  return;
24696
25090
  }
24697
25091
  try {
24698
25092
  await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
24699
25093
  } catch (err) {
24700
- console.error(`${TAG38} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
25094
+ console.error(`${TAG41} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
24701
25095
  } finally {
24702
25096
  try {
24703
25097
  await session.close();
@@ -24715,7 +25109,7 @@ function startTimeEntryCensus(openSession, opts = {}) {
24715
25109
 
24716
25110
  // app/lib/ledger-census.ts
24717
25111
  import { readdirSync as readdirSync27, readFileSync as readFileSync41, statSync as statSync22 } from "fs";
24718
- import { join as join47 } from "path";
25112
+ import { join as join48 } from "path";
24719
25113
 
24720
25114
  // ../lib/ledger-core/dist/reconcile.js
24721
25115
  var LEDGER_INDEX_NAMES = [
@@ -24758,7 +25152,7 @@ function formatCensusLine(f) {
24758
25152
  }
24759
25153
 
24760
25154
  // app/lib/ledger-census.ts
24761
- var TAG39 = "[ledger-census]";
25155
+ var TAG42 = "[ledger-census]";
24762
25156
  var DAY_MS = 864e5;
24763
25157
  function countWriteRejects24h(logDir, now) {
24764
25158
  let entries2;
@@ -24769,7 +25163,7 @@ function countWriteRejects24h(logDir, now) {
24769
25163
  }
24770
25164
  let total = 0;
24771
25165
  for (const name of entries2) {
24772
- const path = join47(logDir, name);
25166
+ const path = join48(logDir, name);
24773
25167
  try {
24774
25168
  if (now - statSync22(path).mtimeMs > DAY_MS) continue;
24775
25169
  for (const line of readFileSync41(path, "utf8").split("\n")) {
@@ -24834,7 +25228,7 @@ async function runLedgerCensusOnce(session, now) {
24834
25228
  else console.log(line);
24835
25229
  return finding;
24836
25230
  } catch (err) {
24837
- console.error(`${TAG39} error="${err instanceof Error ? err.message : String(err)}"`);
25231
+ console.error(`${TAG42} error="${err instanceof Error ? err.message : String(err)}"`);
24838
25232
  return null;
24839
25233
  }
24840
25234
  }
@@ -24847,7 +25241,7 @@ function startLedgerCensus(openSession, opts = {}) {
24847
25241
  session = openSession();
24848
25242
  } catch (err) {
24849
25243
  console.error(
24850
- `${TAG39} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
25244
+ `${TAG42} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
24851
25245
  );
24852
25246
  return;
24853
25247
  }
@@ -24855,7 +25249,7 @@ function startLedgerCensus(openSession, opts = {}) {
24855
25249
  await runLedgerCensusOnce(session, Date.now());
24856
25250
  } catch (err) {
24857
25251
  console.error(
24858
- `${TAG39} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
25252
+ `${TAG42} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
24859
25253
  );
24860
25254
  } finally {
24861
25255
  try {
@@ -24873,7 +25267,7 @@ function startLedgerCensus(openSession, opts = {}) {
24873
25267
  }
24874
25268
 
24875
25269
  // app/lib/conversation-audit.ts
24876
- var TAG40 = "[conversation-audit]";
25270
+ var TAG43 = "[conversation-audit]";
24877
25271
  async function runConversationAudit() {
24878
25272
  const session = getSession();
24879
25273
  try {
@@ -24910,12 +25304,12 @@ async function runConversationAudit() {
24910
25304
  multiAnchored: Number(multiRec?.get("multiAnchored") ?? 0)
24911
25305
  };
24912
25306
  console.error(
24913
- `${TAG40} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
25307
+ `${TAG43} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
24914
25308
  );
24915
25309
  return result;
24916
25310
  } catch (err) {
24917
25311
  const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
24918
- console.error(`${TAG40} op=failed reason=${reason}`);
25312
+ console.error(`${TAG43} op=failed reason=${reason}`);
24919
25313
  return null;
24920
25314
  } finally {
24921
25315
  await session.close();
@@ -25268,7 +25662,7 @@ async function migrateUploads(opts = {}) {
25268
25662
  // app/lib/migrate-admin-webchat-sidecars.ts
25269
25663
  import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as writeFile4, unlink as unlink4 } from "fs/promises";
25270
25664
  import { existsSync as existsSync44 } from "fs";
25271
- import { join as join48 } from "path";
25665
+ import { join as join49 } from "path";
25272
25666
  var ADMIN_ROLE2 = "admin";
25273
25667
  var WEBCHAT_CHANNEL2 = "webchat";
25274
25668
  var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
@@ -25313,7 +25707,7 @@ async function collectLiveSidecars(projectsRoot) {
25313
25707
  }
25314
25708
  for (const slug of slugs) {
25315
25709
  if (!slug.isDirectory()) continue;
25316
- const slugDir = join48(projectsRoot, slug.name);
25710
+ const slugDir = join49(projectsRoot, slug.name);
25317
25711
  let entries2;
25318
25712
  try {
25319
25713
  entries2 = await readdir7(slugDir, { withFileTypes: true });
@@ -25322,9 +25716,9 @@ async function collectLiveSidecars(projectsRoot) {
25322
25716
  }
25323
25717
  for (const entry of entries2) {
25324
25718
  if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
25325
- out.push(join48(slugDir, entry.name));
25719
+ out.push(join49(slugDir, entry.name));
25326
25720
  } else if (entry.isDirectory() && entry.name === "subagents") {
25327
- const subDir = join48(slugDir, entry.name);
25721
+ const subDir = join49(slugDir, entry.name);
25328
25722
  let subs;
25329
25723
  try {
25330
25724
  subs = await readdir7(subDir, { withFileTypes: true });
@@ -25332,7 +25726,7 @@ async function collectLiveSidecars(projectsRoot) {
25332
25726
  continue;
25333
25727
  }
25334
25728
  for (const s of subs) {
25335
- if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join48(subDir, s.name));
25729
+ if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join49(subDir, s.name));
25336
25730
  }
25337
25731
  }
25338
25732
  }
@@ -25344,7 +25738,7 @@ function shortId(path) {
25344
25738
  return base.slice(0, 8);
25345
25739
  }
25346
25740
  async function migrateAdminWebchatSidecars(opts = {}) {
25347
- const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join48(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
25741
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join49(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
25348
25742
  const usersFile = opts.usersFile ?? USERS_FILE;
25349
25743
  const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
25350
25744
  const resolveName = opts.resolveName ?? defaultResolveName;
@@ -25421,7 +25815,7 @@ async function migrateAdminWebchatSidecars(opts = {}) {
25421
25815
  // app/lib/migrate-sidecar-account-ids.ts
25422
25816
  import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as writeFile5, unlink as unlink5 } from "fs/promises";
25423
25817
  import { existsSync as existsSync45 } from "fs";
25424
- import { join as join49 } from "path";
25818
+ import { join as join50 } from "path";
25425
25819
  var SESSION_META_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
25426
25820
  function projectSlugForCwd(cwd) {
25427
25821
  return cwd.replace(/\//g, "-");
@@ -25467,7 +25861,7 @@ async function collectSidecars(projectsRoot) {
25467
25861
  }
25468
25862
  for (const slug of slugs) {
25469
25863
  if (!slug.isDirectory()) continue;
25470
- const slugDir = join49(projectsRoot, slug.name);
25864
+ const slugDir = join50(projectsRoot, slug.name);
25471
25865
  let entries2;
25472
25866
  try {
25473
25867
  entries2 = await readdir8(slugDir, { withFileTypes: true });
@@ -25476,9 +25870,9 @@ async function collectSidecars(projectsRoot) {
25476
25870
  }
25477
25871
  for (const entry of entries2) {
25478
25872
  if (entry.isFile() && SESSION_META_RE2.test(entry.name)) {
25479
- out.push({ path: join49(slugDir, entry.name), slug: slug.name });
25873
+ out.push({ path: join50(slugDir, entry.name), slug: slug.name });
25480
25874
  } else if (entry.isDirectory() && (entry.name === "subagents" || entry.name === "archive")) {
25481
- const subDir = join49(slugDir, entry.name);
25875
+ const subDir = join50(slugDir, entry.name);
25482
25876
  let subs;
25483
25877
  try {
25484
25878
  subs = await readdir8(subDir, { withFileTypes: true });
@@ -25487,7 +25881,7 @@ async function collectSidecars(projectsRoot) {
25487
25881
  }
25488
25882
  for (const s of subs) {
25489
25883
  if (s.isFile() && SESSION_META_RE2.test(s.name)) {
25490
- out.push({ path: join49(subDir, s.name), slug: slug.name });
25884
+ out.push({ path: join50(subDir, s.name), slug: slug.name });
25491
25885
  }
25492
25886
  }
25493
25887
  }
@@ -25496,7 +25890,7 @@ async function collectSidecars(projectsRoot) {
25496
25890
  return out;
25497
25891
  }
25498
25892
  async function migrateSidecarAccountIds(opts = {}) {
25499
- const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join49(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
25893
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join50(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
25500
25894
  const accounts = opts.accounts ?? listValidAccounts();
25501
25895
  const result = {
25502
25896
  scanned: 0,
@@ -25809,8 +26203,8 @@ var streamSSE = (c, cb, onError) => {
25809
26203
 
25810
26204
  // app/lib/whatsapp/gateway/routes.ts
25811
26205
  function createWaChannelRoutes(deps) {
25812
- const app73 = new Hono();
25813
- app73.get("/wa-channel/inbound", (c) => {
26206
+ const app75 = new Hono();
26207
+ app75.get("/wa-channel/inbound", (c) => {
25814
26208
  const senderId = c.req.query("senderId");
25815
26209
  if (!senderId) return c.json({ error: "senderId required" }, 400);
25816
26210
  return streamSSE(c, async (stream2) => {
@@ -25828,7 +26222,7 @@ function createWaChannelRoutes(deps) {
25828
26222
  }
25829
26223
  });
25830
26224
  });
25831
- app73.post("/wa-channel/reply", async (c) => {
26225
+ app75.post("/wa-channel/reply", async (c) => {
25832
26226
  const body = await c.req.json().catch(() => null);
25833
26227
  const senderId = body?.senderId;
25834
26228
  const text = body?.text;
@@ -25850,7 +26244,7 @@ function createWaChannelRoutes(deps) {
25850
26244
  deps.onReplyDispatch?.(senderId, Date.now());
25851
26245
  return c.json({ ok: true });
25852
26246
  });
25853
- app73.post("/wa-channel/reply-document", async (c) => {
26247
+ app75.post("/wa-channel/reply-document", async (c) => {
25854
26248
  const body = await c.req.json().catch(() => null);
25855
26249
  const senderId = body?.senderId;
25856
26250
  const files = body?.files;
@@ -25889,7 +26283,7 @@ function createWaChannelRoutes(deps) {
25889
26283
  }
25890
26284
  return c.json({ ok: true, results });
25891
26285
  });
25892
- app73.post("/wa-channel/ready", async (c) => {
26286
+ app75.post("/wa-channel/ready", async (c) => {
25893
26287
  const body = await c.req.json().catch(() => null);
25894
26288
  const senderId = body?.senderId;
25895
26289
  if (typeof senderId !== "string") {
@@ -25898,7 +26292,7 @@ function createWaChannelRoutes(deps) {
25898
26292
  deps.onReady?.(senderId);
25899
26293
  return c.json({ ok: true });
25900
26294
  });
25901
- app73.post("/wa-channel/received", async (c) => {
26295
+ app75.post("/wa-channel/received", async (c) => {
25902
26296
  const body = await c.req.json().catch(() => null);
25903
26297
  const senderId = body?.senderId;
25904
26298
  const waMessageId = body?.waMessageId;
@@ -25908,7 +26302,7 @@ function createWaChannelRoutes(deps) {
25908
26302
  deps.onReceived?.(senderId, waMessageId);
25909
26303
  return c.json({ ok: true });
25910
26304
  });
25911
- app73.post("/wa-channel/turn-end", async (c) => {
26305
+ app75.post("/wa-channel/turn-end", async (c) => {
25912
26306
  const body = await c.req.json().catch(() => null);
25913
26307
  const senderId = body?.senderId;
25914
26308
  const sessionId = body?.sessionId;
@@ -25954,7 +26348,7 @@ function createWaChannelRoutes(deps) {
25954
26348
  console.error(`[whatsapp-native] op=turn-end ${decision} delivered=none`);
25955
26349
  return c.json({ ok: true, delivered: "none" });
25956
26350
  });
25957
- return app73;
26351
+ return app75;
25958
26352
  }
25959
26353
 
25960
26354
  // app/lib/whatsapp/gateway/wa-gateway.ts
@@ -26463,8 +26857,8 @@ var InboundHub2 = class {
26463
26857
 
26464
26858
  // app/lib/webchat/gateway/routes.ts
26465
26859
  function createWebchatChannelRoutes(deps) {
26466
- const app73 = new Hono();
26467
- app73.get("/webchat-channel/inbound", (c) => {
26860
+ const app75 = new Hono();
26861
+ app75.get("/webchat-channel/inbound", (c) => {
26468
26862
  const key = c.req.query("key");
26469
26863
  if (!key) return c.json({ error: "key required" }, 400);
26470
26864
  const role = c.req.query("role");
@@ -26489,7 +26883,7 @@ function createWebchatChannelRoutes(deps) {
26489
26883
  }
26490
26884
  });
26491
26885
  });
26492
- app73.post("/webchat-channel/reply", async (c) => {
26886
+ app75.post("/webchat-channel/reply", async (c) => {
26493
26887
  const body = await c.req.json().catch(() => null);
26494
26888
  const key = body?.key;
26495
26889
  const text = body?.text;
@@ -26499,7 +26893,7 @@ function createWebchatChannelRoutes(deps) {
26499
26893
  deps.onReply?.(key, text);
26500
26894
  return c.json({ ok: true });
26501
26895
  });
26502
- app73.post("/webchat-channel/connector-auth", async (c) => {
26896
+ app75.post("/webchat-channel/connector-auth", async (c) => {
26503
26897
  const body = await c.req.json().catch(() => null);
26504
26898
  const key = body?.key;
26505
26899
  const sessionId = body?.sessionId;
@@ -26512,7 +26906,7 @@ function createWebchatChannelRoutes(deps) {
26512
26906
  const result = await deps.onConnectorAuth({ key, sessionId, name, completed });
26513
26907
  return c.json(result);
26514
26908
  });
26515
- app73.post("/webchat-channel/ready", async (c) => {
26909
+ app75.post("/webchat-channel/ready", async (c) => {
26516
26910
  const body = await c.req.json().catch(() => null);
26517
26911
  const key = body?.key;
26518
26912
  if (typeof key !== "string") {
@@ -26521,7 +26915,7 @@ function createWebchatChannelRoutes(deps) {
26521
26915
  deps.onReady?.(key);
26522
26916
  return c.json({ ok: true });
26523
26917
  });
26524
- app73.post("/webchat-channel/permission-request", async (c) => {
26918
+ app75.post("/webchat-channel/permission-request", async (c) => {
26525
26919
  const body = await c.req.json().catch(() => null);
26526
26920
  const key = body?.key;
26527
26921
  const requestId = body?.request_id;
@@ -26535,7 +26929,7 @@ function createWebchatChannelRoutes(deps) {
26535
26929
  const verdict = await deps.awaitPermissionVerdict({ key, requestId, toolName, description, inputPreview });
26536
26930
  return c.json(verdict);
26537
26931
  });
26538
- app73.post("/webchat-channel/received", async (c) => {
26932
+ app75.post("/webchat-channel/received", async (c) => {
26539
26933
  const body = await c.req.json().catch(() => null);
26540
26934
  const key = body?.key;
26541
26935
  const messageId = body?.messageId;
@@ -26545,7 +26939,7 @@ function createWebchatChannelRoutes(deps) {
26545
26939
  deps.onReceived?.(key, messageId);
26546
26940
  return c.json({ ok: true });
26547
26941
  });
26548
- app73.post("/webchat-channel/turn-end", async (c) => {
26942
+ app75.post("/webchat-channel/turn-end", async (c) => {
26549
26943
  const body = await c.req.json().catch(() => null);
26550
26944
  const key = body?.key;
26551
26945
  const sessionId = body?.sessionId;
@@ -26565,7 +26959,7 @@ function createWebchatChannelRoutes(deps) {
26565
26959
  deps.onTurnEnd?.(key, role);
26566
26960
  return c.json({ ok: true });
26567
26961
  });
26568
- return app73;
26962
+ return app75;
26569
26963
  }
26570
26964
 
26571
26965
  // app/lib/webchat/gateway/webchat-gateway.ts
@@ -27324,14 +27718,14 @@ function makeFileDelivery(opts) {
27324
27718
  }
27325
27719
 
27326
27720
  // app/lib/webchat/file-delivery.ts
27327
- var TAG41 = "[webchat-adaptor]";
27721
+ var TAG44 = "[webchat-adaptor]";
27328
27722
  function platformRoot2() {
27329
27723
  return process.env.MAXY_PLATFORM_ROOT || "";
27330
27724
  }
27331
27725
  function makeWebchatSendFile(entry) {
27332
27726
  return async (filePath) => {
27333
27727
  if (!entry.accountId) {
27334
- console.error(`${TAG41} file-delivery reject reason=no-account sender=${entry.senderId}`);
27728
+ console.error(`${TAG44} file-delivery reject reason=no-account sender=${entry.senderId}`);
27335
27729
  return { ok: false, error: "no-account" };
27336
27730
  }
27337
27731
  const accountDir = resolve38(platformRoot2(), "..", "data/accounts", entry.accountId);
@@ -27339,14 +27733,14 @@ function makeWebchatSendFile(entry) {
27339
27733
  const resolved = realpathSync9(filePath);
27340
27734
  const accountResolved = realpathSync9(accountDir);
27341
27735
  if (!resolved.startsWith(accountResolved + "/")) {
27342
- console.error(`${TAG41} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
27736
+ console.error(`${TAG44} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
27343
27737
  return { ok: false, error: "outside-account" };
27344
27738
  }
27345
27739
  return { ok: true };
27346
27740
  } catch (err) {
27347
27741
  const code = err.code;
27348
27742
  console.error(
27349
- `${TAG41} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
27743
+ `${TAG44} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
27350
27744
  );
27351
27745
  return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
27352
27746
  }
@@ -27355,7 +27749,7 @@ function makeWebchatSendFile(entry) {
27355
27749
  function makeWebchatFileDelivery(entry) {
27356
27750
  return makeFileDelivery({
27357
27751
  entry,
27358
- tag: TAG41,
27752
+ tag: TAG44,
27359
27753
  channel: "webchat",
27360
27754
  sendFile: makeWebchatSendFile(entry),
27361
27755
  deferUntilVerdict: true
@@ -27417,7 +27811,7 @@ function buildPublicWebchatSpawnRequest(input) {
27417
27811
  }
27418
27812
 
27419
27813
  // app/lib/whatsapp/inbound/file-delivery-bridge.ts
27420
- var TAG42 = "[whatsapp-adaptor]";
27814
+ var TAG45 = "[whatsapp-adaptor]";
27421
27815
  var SEND_USER_FILE2 = "SendUserFile";
27422
27816
  var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
27423
27817
  function platformRoot3() {
@@ -27435,7 +27829,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
27435
27829
  });
27436
27830
  if (result.ok) return { ok: true };
27437
27831
  console.error(
27438
- `${TAG42} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
27832
+ `${TAG45} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
27439
27833
  );
27440
27834
  return { ok: false, error: result.error };
27441
27835
  };
@@ -27443,7 +27837,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
27443
27837
  function makeWhatsAppFileDelivery(entry, maxyAccountId) {
27444
27838
  const shared = makeFileDelivery({
27445
27839
  entry,
27446
- tag: TAG42,
27840
+ tag: TAG45,
27447
27841
  channel: "whatsapp",
27448
27842
  sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
27449
27843
  });
@@ -27478,7 +27872,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
27478
27872
  if (!delivered) {
27479
27873
  const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
27480
27874
  console.error(
27481
- `${TAG42} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
27875
+ `${TAG45} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
27482
27876
  );
27483
27877
  }
27484
27878
  }
@@ -27661,8 +28055,8 @@ var InboundHub3 = class {
27661
28055
 
27662
28056
  // app/lib/telegram/gateway/routes.ts
27663
28057
  function createTelegramChannelRoutes(deps) {
27664
- const app73 = new Hono();
27665
- app73.get("/tg-channel/inbound", (c) => {
28058
+ const app75 = new Hono();
28059
+ app75.get("/tg-channel/inbound", (c) => {
27666
28060
  const key = c.req.query("key");
27667
28061
  if (!key) return c.json({ error: "key required" }, 400);
27668
28062
  return streamSSE(c, async (stream2) => {
@@ -27680,7 +28074,7 @@ function createTelegramChannelRoutes(deps) {
27680
28074
  }
27681
28075
  });
27682
28076
  });
27683
- app73.post("/tg-channel/reply", async (c) => {
28077
+ app75.post("/tg-channel/reply", async (c) => {
27684
28078
  const body = await c.req.json().catch(() => null);
27685
28079
  const key = body?.key;
27686
28080
  const text = body?.text;
@@ -27696,7 +28090,7 @@ function createTelegramChannelRoutes(deps) {
27696
28090
  console.error(`[telegram-native] op=reply key=${key} bytes=${Buffer.byteLength(text, "utf8")}`);
27697
28091
  return c.json({ ok: true });
27698
28092
  });
27699
- app73.post("/tg-channel/ready", async (c) => {
28093
+ app75.post("/tg-channel/ready", async (c) => {
27700
28094
  const body = await c.req.json().catch(() => null);
27701
28095
  const key = body?.key;
27702
28096
  if (typeof key !== "string") {
@@ -27705,7 +28099,7 @@ function createTelegramChannelRoutes(deps) {
27705
28099
  deps.onReady?.(key);
27706
28100
  return c.json({ ok: true });
27707
28101
  });
27708
- app73.post("/tg-channel/received", async (c) => {
28102
+ app75.post("/tg-channel/received", async (c) => {
27709
28103
  const body = await c.req.json().catch(() => null);
27710
28104
  const key = body?.key;
27711
28105
  const messageId = body?.messageId;
@@ -27715,7 +28109,7 @@ function createTelegramChannelRoutes(deps) {
27715
28109
  deps.onReceived?.(key, messageId);
27716
28110
  return c.json({ ok: true });
27717
28111
  });
27718
- app73.post("/tg-channel/turn-end", async (c) => {
28112
+ app75.post("/tg-channel/turn-end", async (c) => {
27719
28113
  const body = await c.req.json().catch(() => null);
27720
28114
  const key = body?.key;
27721
28115
  const sessionId = body?.sessionId;
@@ -27748,7 +28142,7 @@ function createTelegramChannelRoutes(deps) {
27748
28142
  console.error(`[telegram-native] op=turn-end key=${key} sessionId=${sid} replied=no delivered=none`);
27749
28143
  return c.json({ ok: true, delivered: "none" });
27750
28144
  });
27751
- return app73;
28145
+ return app75;
27752
28146
  }
27753
28147
 
27754
28148
  // app/lib/telegram/gateway/telegram-gateway.ts
@@ -27898,8 +28292,8 @@ function buildTelegramSpawnRequest(input) {
27898
28292
  // app/lib/telegram/outbound/send-document.ts
27899
28293
  import { realpathSync as realpathSync10 } from "fs";
27900
28294
  import { readFile as readFile14, stat as stat10 } from "fs/promises";
27901
- import { resolve as resolve39, basename as basename14 } from "path";
27902
- var TAG43 = "[telegram:outbound]";
28295
+ import { resolve as resolve39, basename as basename15 } from "path";
28296
+ var TAG46 = "[telegram:outbound]";
27903
28297
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
27904
28298
  async function sendTelegramDocument(input) {
27905
28299
  const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
@@ -27916,10 +28310,10 @@ async function sendTelegramDocument(input) {
27916
28310
  } catch (err) {
27917
28311
  const code = err.code;
27918
28312
  if (code === "ENOENT") {
27919
- console.error(`${TAG43} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
28313
+ console.error(`${TAG46} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
27920
28314
  return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
27921
28315
  }
27922
- console.error(`${TAG43} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
28316
+ console.error(`${TAG46} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
27923
28317
  return { ok: false, status: 500, error: String(err) };
27924
28318
  }
27925
28319
  let resolvedPath;
@@ -27928,14 +28322,14 @@ async function sendTelegramDocument(input) {
27928
28322
  } catch (err) {
27929
28323
  const code = err.code;
27930
28324
  if (code === "ENOENT") {
27931
- console.error(`${TAG43} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
28325
+ console.error(`${TAG46} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
27932
28326
  return { ok: false, status: 404, error: `File not found: ${filePath}` };
27933
28327
  }
27934
- console.error(`${TAG43} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
28328
+ console.error(`${TAG46} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
27935
28329
  return { ok: false, status: 500, error: String(err) };
27936
28330
  }
27937
28331
  if (!resolvedPath.startsWith(accountResolved + "/")) {
27938
- console.error(`${TAG43} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
28332
+ console.error(`${TAG46} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
27939
28333
  return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
27940
28334
  }
27941
28335
  const fileStat = await stat10(resolvedPath);
@@ -27946,7 +28340,7 @@ async function sendTelegramDocument(input) {
27946
28340
  error: `File exceeds 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)`
27947
28341
  };
27948
28342
  }
27949
- const filename = basename14(resolvedPath);
28343
+ const filename = basename15(resolvedPath);
27950
28344
  const buffer = Buffer.from(await readFile14(resolvedPath));
27951
28345
  const form = new FormData();
27952
28346
  form.append("chat_id", String(chatId));
@@ -27968,13 +28362,13 @@ async function sendTelegramDocument(input) {
27968
28362
  error = e instanceof Error ? e.message : String(e);
27969
28363
  }
27970
28364
  console.error(
27971
- `${TAG43} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
28365
+ `${TAG46} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
27972
28366
  );
27973
28367
  return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
27974
28368
  }
27975
28369
 
27976
28370
  // app/lib/telegram/outbound/file-delivery.ts
27977
- var TAG44 = "[telegram:outbound]";
28371
+ var TAG47 = "[telegram:outbound]";
27978
28372
  function platformRoot4() {
27979
28373
  return process.env.MAXY_PLATFORM_ROOT || "";
27980
28374
  }
@@ -27986,11 +28380,11 @@ function makeTelegramSendFile(entry) {
27986
28380
  botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
27987
28381
  }
27988
28382
  if (!botToken) {
27989
- console.error(`${TAG44} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
28383
+ console.error(`${TAG47} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
27990
28384
  return { ok: false, error: "no-bot-token" };
27991
28385
  }
27992
28386
  if (entry.replyTarget == null) {
27993
- console.error(`${TAG44} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
28387
+ console.error(`${TAG47} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
27994
28388
  return { ok: false, error: "no-reply-target" };
27995
28389
  }
27996
28390
  const result = await sendTelegramDocument({
@@ -28007,7 +28401,7 @@ function makeTelegramSendFile(entry) {
28007
28401
  function makeTelegramFileDelivery(entry) {
28008
28402
  return makeFileDelivery({
28009
28403
  entry,
28010
- tag: TAG44,
28404
+ tag: TAG47,
28011
28405
  channel: "telegram",
28012
28406
  sendFile: makeTelegramSendFile(entry)
28013
28407
  });
@@ -28048,7 +28442,7 @@ function startTelegramNativeFileFollower(input) {
28048
28442
 
28049
28443
  // app/lib/channel-pty-bridge/public-session-end-review.ts
28050
28444
  import { randomUUID as randomUUID12 } from "crypto";
28051
- var TAG45 = "[public-session-review]";
28445
+ var TAG48 = "[public-session-review]";
28052
28446
  var CONSUMED_CAP = 500;
28053
28447
  var consumed = /* @__PURE__ */ new Set();
28054
28448
  function consumeOnce(sessionId) {
@@ -28075,7 +28469,7 @@ async function fetchJsonl(sessionId) {
28075
28469
  return await res.text();
28076
28470
  } catch (err) {
28077
28471
  console.error(
28078
- `${TAG45} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
28472
+ `${TAG48} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
28079
28473
  );
28080
28474
  return null;
28081
28475
  }
@@ -28099,7 +28493,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
28099
28493
  const res = await fetch(url);
28100
28494
  if (!res.ok) {
28101
28495
  console.error(
28102
- `${TAG45} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
28496
+ `${TAG48} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
28103
28497
  );
28104
28498
  return [];
28105
28499
  }
@@ -28107,7 +28501,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
28107
28501
  return Array.isArray(body.writes) ? body.writes : [];
28108
28502
  } catch (err) {
28109
28503
  console.error(
28110
- `${TAG45} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
28504
+ `${TAG48} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
28111
28505
  );
28112
28506
  return [];
28113
28507
  }
@@ -28136,7 +28530,7 @@ function composeInitialMessage(input) {
28136
28530
  }
28137
28531
  async function dispatchReviewer(input, initialMessage) {
28138
28532
  const sessionId = randomUUID12();
28139
- console.log(`${TAG45} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
28533
+ console.log(`${TAG48} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
28140
28534
  const spawned = await managerRcSpawn({
28141
28535
  sessionId,
28142
28536
  initialMessage,
@@ -28156,21 +28550,21 @@ async function firePublicSessionEndReview(input) {
28156
28550
  const dispatchedAt = Date.now();
28157
28551
  if (consumed.has(input.sessionId)) {
28158
28552
  console.log(
28159
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
28553
+ `${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
28160
28554
  );
28161
28555
  return;
28162
28556
  }
28163
28557
  const jsonl = await fetchJsonl(input.sessionId);
28164
28558
  if (!jsonl) {
28165
28559
  console.log(
28166
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
28560
+ `${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
28167
28561
  );
28168
28562
  return;
28169
28563
  }
28170
28564
  const operatorTurns = countOperatorTurns(jsonl);
28171
28565
  if (operatorTurns === 0) {
28172
28566
  console.log(
28173
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
28567
+ `${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
28174
28568
  );
28175
28569
  return;
28176
28570
  }
@@ -28184,19 +28578,19 @@ async function firePublicSessionEndReview(input) {
28184
28578
  });
28185
28579
  if (!consumeOnce(input.sessionId)) {
28186
28580
  console.log(
28187
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
28581
+ `${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
28188
28582
  );
28189
28583
  return;
28190
28584
  }
28191
28585
  const dispatched = await dispatchReviewer(input, initialMessage);
28192
28586
  if (!dispatched.ok) {
28193
28587
  console.error(
28194
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
28588
+ `${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
28195
28589
  );
28196
28590
  return;
28197
28591
  }
28198
28592
  console.log(
28199
- `${TAG45} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
28593
+ `${TAG48} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
28200
28594
  );
28201
28595
  }
28202
28596
 
@@ -28602,7 +28996,7 @@ function clientFrom(c) {
28602
28996
  }
28603
28997
  installMediaDownloadGuard();
28604
28998
  var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
28605
- var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join50(PLATFORM_ROOT6, "config", "brand.json") : "";
28999
+ var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join51(PLATFORM_ROOT6, "config", "brand.json") : "";
28606
29000
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
28607
29001
  if (BRAND_JSON_PATH && !existsSync48(BRAND_JSON_PATH)) {
28608
29002
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
@@ -28641,7 +29035,7 @@ var brandLoginOpts = {
28641
29035
  appleTouchIconPath: brandAppIcon512Path,
28642
29036
  themeColor: BRAND.defaultColors?.primary
28643
29037
  };
28644
- var ALIAS_DOMAINS_PATH = join50(homedir4(), BRAND.configDir, "alias-domains.json");
29038
+ var ALIAS_DOMAINS_PATH = join51(homedir4(), BRAND.configDir, "alias-domains.json");
28645
29039
  function loadAliasDomains() {
28646
29040
  try {
28647
29041
  if (!existsSync48(ALIAS_DOMAINS_PATH)) return null;
@@ -28671,7 +29065,7 @@ startManagerEventsSubscriber();
28671
29065
  function isPublicHost(host) {
28672
29066
  return host.startsWith("public.") || aliasDomains.has(host);
28673
29067
  }
28674
- var app72 = new Hono();
29068
+ var app74 = new Hono();
28675
29069
  function resolveChannelOverride(accountId, channel, senderId) {
28676
29070
  try {
28677
29071
  const dir = listValidAccounts().find((a) => a.accountId === accountId)?.accountDir;
@@ -28720,7 +29114,7 @@ var waGateway = new WaGateway({
28720
29114
  fetchStandingRules: fetchAccountStandingRules,
28721
29115
  resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
28722
29116
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
28723
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve42(process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
29117
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve42(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
28724
29118
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
28725
29119
  // path-validation scope) is the sender's effective SESSION account, resolved
28726
29120
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -28735,7 +29129,7 @@ var waGateway = new WaGateway({
28735
29129
  caption,
28736
29130
  accountId,
28737
29131
  maxyAccountId,
28738
- platformRoot: resolve42(process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, ".."))
29132
+ platformRoot: resolve42(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, ".."))
28739
29133
  });
28740
29134
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
28741
29135
  },
@@ -28848,13 +29242,13 @@ var waGateway = new WaGateway({
28848
29242
  nativeFileFollowers.set(senderId, ac);
28849
29243
  }
28850
29244
  });
28851
- app72.route("/", waGateway.routes());
29245
+ app74.route("/", waGateway.routes());
28852
29246
  waGateway.startSweeper();
28853
29247
  function runDuplicateSenderAudit() {
28854
29248
  try {
28855
29249
  const configDir = process.env.CLAUDE_CONFIG_DIR;
28856
29250
  if (!configDir) return;
28857
- const projectsRoot = join50(configDir, "projects");
29251
+ const projectsRoot = join51(configDir, "projects");
28858
29252
  const records = [];
28859
29253
  for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
28860
29254
  if (isSubagent || archived) continue;
@@ -28978,7 +29372,7 @@ var webchatGateway = new WebchatGateway({
28978
29372
  firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
28979
29373
  });
28980
29374
  setWebchatGateway(webchatGateway);
28981
- app72.route("/", webchatGateway.routes());
29375
+ app74.route("/", webchatGateway.routes());
28982
29376
  webchatGateway.startSweeper();
28983
29377
  webchatGateway.startPublicReaper();
28984
29378
  var telegramFileFollowers = /* @__PURE__ */ new Map();
@@ -29022,7 +29416,7 @@ var telegramGateway = new TelegramGateway({
29022
29416
  }
29023
29417
  });
29024
29418
  setTelegramGateway(telegramGateway);
29025
- app72.route("/", telegramGateway.routes());
29419
+ app74.route("/", telegramGateway.routes());
29026
29420
  telegramGateway.startSweeper();
29027
29421
  var chatRoutes = createChatRoutes({
29028
29422
  handleInbound: (input) => webchatGateway.handleInbound(input),
@@ -29056,19 +29450,19 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
29056
29450
  // and why the real dependencies are bound there rather than assembled here.
29057
29451
  effectiveAccountFor: resolveScheduledEffectiveAccountForInstall
29058
29452
  });
29059
- app72.route("/api/channel/schedule-inject", scheduleInjectRoutes);
29060
- app72.use("*", clientIpMiddleware);
29453
+ app74.route("/api/channel/schedule-inject", scheduleInjectRoutes);
29454
+ app74.use("*", clientIpMiddleware);
29061
29455
  function allowsSameOriginFraming(path) {
29062
29456
  return path === "/vnc-viewer.html" || path.startsWith("/api/admin/attachment/") || path.startsWith("/api/public-reader/attachment/") || path === "/api/admin/files/download" || path === "/api/admin/session-upload";
29063
29457
  }
29064
- app72.use("*", async (c, next) => {
29458
+ app74.use("*", async (c, next) => {
29065
29459
  await next();
29066
29460
  c.header("X-Content-Type-Options", "nosniff");
29067
29461
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
29068
29462
  c.header("X-Frame-Options", allowsSameOriginFraming(c.req.path) ? "SAMEORIGIN" : "DENY");
29069
29463
  });
29070
29464
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
29071
- app72.use("*", async (c, next) => {
29465
+ app74.use("*", async (c, next) => {
29072
29466
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
29073
29467
  await next();
29074
29468
  return;
@@ -29086,7 +29480,7 @@ app72.use("*", async (c, next) => {
29086
29480
  });
29087
29481
  }
29088
29482
  });
29089
- app72.use("*", async (c, next) => {
29483
+ app74.use("*", async (c, next) => {
29090
29484
  const host = (c.req.header("host") ?? "").split(":")[0];
29091
29485
  if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
29092
29486
  await next();
@@ -29124,7 +29518,7 @@ function resolveRemoteAuthOpts(c) {
29124
29518
  return { ...brandLoginOpts, origin };
29125
29519
  }
29126
29520
  var MAX_LOGIN_BODY = 8 * 1024;
29127
- app72.post("/__remote-auth/login", async (c) => {
29521
+ app74.post("/__remote-auth/login", async (c) => {
29128
29522
  const client = clientFrom(c);
29129
29523
  const clientIp = client.ip || "unknown";
29130
29524
  if (!requestIsTlsTerminated(c)) {
@@ -29169,7 +29563,7 @@ app72.post("/__remote-auth/login", async (c) => {
29169
29563
  }
29170
29564
  });
29171
29565
  });
29172
- app72.get("/__remote-auth/logout", (c) => {
29566
+ app74.get("/__remote-auth/logout", (c) => {
29173
29567
  const client = clientFrom(c);
29174
29568
  const clientIp = client.ip || "unknown";
29175
29569
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -29182,7 +29576,7 @@ app72.get("/__remote-auth/logout", (c) => {
29182
29576
  }
29183
29577
  });
29184
29578
  });
29185
- app72.post("/__remote-auth/change-password", async (c) => {
29579
+ app74.post("/__remote-auth/change-password", async (c) => {
29186
29580
  const client = clientFrom(c);
29187
29581
  const clientIp = client.ip || "unknown";
29188
29582
  const rateLimited = checkRateLimit(client);
@@ -29241,13 +29635,13 @@ app72.post("/__remote-auth/change-password", async (c) => {
29241
29635
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "change", changeError: "Failed to save password", redirect }), 200);
29242
29636
  }
29243
29637
  });
29244
- app72.get("/__remote-auth/setup", (c) => {
29638
+ app74.get("/__remote-auth/setup", (c) => {
29245
29639
  if (isRemoteAuthConfigured()) {
29246
29640
  return c.redirect("/");
29247
29641
  }
29248
29642
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup" }), 200);
29249
29643
  });
29250
- app72.post("/__remote-auth/set-initial-password", async (c) => {
29644
+ app74.post("/__remote-auth/set-initial-password", async (c) => {
29251
29645
  if (isRemoteAuthConfigured()) {
29252
29646
  return c.redirect("/");
29253
29647
  }
@@ -29285,10 +29679,10 @@ app72.post("/__remote-auth/set-initial-password", async (c) => {
29285
29679
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
29286
29680
  }
29287
29681
  });
29288
- app72.get("/api/remote-auth/status", (c) => {
29682
+ app74.get("/api/remote-auth/status", (c) => {
29289
29683
  return c.json({ configured: isRemoteAuthConfigured() });
29290
29684
  });
29291
- app72.post("/api/remote-auth/set-password", async (c) => {
29685
+ app74.post("/api/remote-auth/set-password", async (c) => {
29292
29686
  let body;
29293
29687
  try {
29294
29688
  body = await c.req.json();
@@ -29327,10 +29721,10 @@ app72.post("/api/remote-auth/set-password", async (c) => {
29327
29721
  return c.json({ error: "Failed to save password" }, 500);
29328
29722
  }
29329
29723
  });
29330
- app72.route("/api/_client-error", client_error_default);
29724
+ app74.route("/api/_client-error", client_error_default);
29331
29725
  console.log("[client-error-route] mounted");
29332
29726
  var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
29333
- app72.use("*", async (c, next) => {
29727
+ app74.use("*", async (c, next) => {
29334
29728
  const host = (c.req.header("host") ?? "").split(":")[0];
29335
29729
  const path = c.req.path;
29336
29730
  if (path === "/favicon.ico" || path.startsWith("/assets/") || path.startsWith("/brand/") || // Public free/busy is read by the booking page (a separate Cloudflare Pages
@@ -29374,30 +29768,30 @@ app72.use("*", async (c, next) => {
29374
29768
  }
29375
29769
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(c), redirect: path }), 200);
29376
29770
  });
29377
- app72.route("/api/health", health_default);
29378
- app72.route("/api/chat", chatRoutes);
29379
- app72.route("/api/whatsapp", whatsapp_default);
29380
- app72.route("/api/storage", storage_broker_default);
29381
- app72.route("/api/whatsapp-reader", whatsapp_reader_default);
29382
- app72.route("/api/session-reader", session_reader_default);
29383
- app72.route("/api/operator-conversations", operator_conversations_default);
29384
- app72.route("/api/public-reader", public_reader_default);
29385
- app72.route("/api/webchat", createWebchatRoutes({
29771
+ app74.route("/api/health", health_default);
29772
+ app74.route("/api/chat", chatRoutes);
29773
+ app74.route("/api/whatsapp", whatsapp_default);
29774
+ app74.route("/api/storage", storage_broker_default);
29775
+ app74.route("/api/whatsapp-reader", whatsapp_reader_default);
29776
+ app74.route("/api/session-reader", session_reader_default);
29777
+ app74.route("/api/operator-conversations", operator_conversations_default);
29778
+ app74.route("/api/public-reader", public_reader_default);
29779
+ app74.route("/api/webchat", createWebchatRoutes({
29386
29780
  handleInbound: (input) => webchatGateway.handleInbound(input),
29387
29781
  // Task 940 — the permission relay's pointer read + verdict write.
29388
29782
  pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
29389
29783
  deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
29390
29784
  resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
29391
29785
  }));
29392
- app72.route("/api/webchat/greeting", webchat_greeting_default);
29393
- app72.route("/api/telegram", telegram_default);
29394
- app72.route("/api/quickbooks", quickbooks_default);
29395
- app72.route("/api/onboarding", onboarding_default);
29396
- app72.route("/api/admin", admin_default);
29397
- app72.route("/api/access", access_default);
29398
- app72.route("/api/session", session_default2);
29399
- app72.route("/api/calendar", calendar_public_default);
29400
- app72.route("/api/portal", portal_fetch_default);
29786
+ app74.route("/api/webchat/greeting", webchat_greeting_default);
29787
+ app74.route("/api/telegram", telegram_default);
29788
+ app74.route("/api/quickbooks", quickbooks_default);
29789
+ app74.route("/api/onboarding", onboarding_default);
29790
+ app74.route("/api/admin", admin_default);
29791
+ app74.route("/api/access", access_default);
29792
+ app74.route("/api/session", session_default2);
29793
+ app74.route("/api/calendar", calendar_public_default);
29794
+ app74.route("/api/portal", portal_fetch_default);
29401
29795
  var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
29402
29796
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
29403
29797
  var IMAGE_MIME = {
@@ -29409,7 +29803,7 @@ var IMAGE_MIME = {
29409
29803
  ".svg": "image/svg+xml",
29410
29804
  ".ico": "image/x-icon"
29411
29805
  };
29412
- app72.get("/agent-assets/:slug/:filename", (c) => {
29806
+ app74.get("/agent-assets/:slug/:filename", (c) => {
29413
29807
  const slug = c.req.param("slug");
29414
29808
  const filename = c.req.param("filename");
29415
29809
  if (!SAFE_SLUG_RE2.test(slug)) {
@@ -29444,7 +29838,7 @@ app72.get("/agent-assets/:slug/:filename", (c) => {
29444
29838
  "Cache-Control": "public, max-age=3600"
29445
29839
  });
29446
29840
  });
29447
- app72.get("/generated/:filename", (c) => {
29841
+ app74.get("/generated/:filename", (c) => {
29448
29842
  const filename = c.req.param("filename");
29449
29843
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
29450
29844
  console.error(`[generated] serve file=${filename} status=403`);
@@ -29474,10 +29868,10 @@ app72.get("/generated/:filename", (c) => {
29474
29868
  "Cache-Control": "public, max-age=86400"
29475
29869
  });
29476
29870
  });
29477
- app72.route("/sites", sites_default);
29478
- app72.route("/listings", listings_default);
29479
- app72.route("/v", visitor_event_default);
29480
- app72.route("/v", visitor_consent_default);
29871
+ app74.route("/sites", sites_default);
29872
+ app74.route("/listings", listings_default);
29873
+ app74.route("/v", visitor_event_default);
29874
+ app74.route("/v", visitor_consent_default);
29481
29875
  var htmlCache = /* @__PURE__ */ new Map();
29482
29876
  var brandLogoPath = "/brand/maxy-monochrome.png";
29483
29877
  var brandIconPath = "/brand/maxy-monochrome.png";
@@ -29522,7 +29916,7 @@ var SW_SOURCE = (() => {
29522
29916
  function readInstalledVersion() {
29523
29917
  try {
29524
29918
  if (!PLATFORM_ROOT6) return "unknown";
29525
- const versionFile = join50(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
29919
+ const versionFile = join51(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
29526
29920
  if (!existsSync48(versionFile)) return "unknown";
29527
29921
  const content = readFileSync44(versionFile, "utf-8").trim();
29528
29922
  return content || "unknown";
@@ -29552,11 +29946,11 @@ ${clientErrorReporterScript}
29552
29946
  return html;
29553
29947
  }
29554
29948
  function loadBrandingCache(agentSlug) {
29555
- const configDir = join50(homedir4(), BRAND.configDir);
29949
+ const configDir = join51(homedir4(), BRAND.configDir);
29556
29950
  try {
29557
29951
  const accountId = getDefaultAccountId();
29558
29952
  if (!accountId) return null;
29559
- const cachePath = join50(configDir, "branding-cache", accountId, `${agentSlug}.json`);
29953
+ const cachePath = join51(configDir, "branding-cache", accountId, `${agentSlug}.json`);
29560
29954
  if (!existsSync48(cachePath)) return null;
29561
29955
  return JSON.parse(readFileSync44(cachePath, "utf-8"));
29562
29956
  } catch {
@@ -29602,7 +29996,7 @@ function brandedPublicHtml(agentSlug) {
29602
29996
  function agentUnavailableHtml() {
29603
29997
  return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
29604
29998
  }
29605
- app72.get("/", (c) => {
29999
+ app74.get("/", (c) => {
29606
30000
  const host = (c.req.header("host") ?? "").split(":")[0];
29607
30001
  const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
29608
30002
  if (klass === "operator") {
@@ -29624,12 +30018,12 @@ app72.get("/", (c) => {
29624
30018
  console.log(`[host-class] host=${host} class=admin served=index.html`);
29625
30019
  return c.html(cachedHtml("index.html"));
29626
30020
  });
29627
- app72.get("/public", (c) => {
30021
+ app74.get("/public", (c) => {
29628
30022
  const host = (c.req.header("host") ?? "").split(":")[0];
29629
30023
  if (isPublicHost(host)) return c.text("Not found", 404);
29630
30024
  return c.html(cachedHtml("public.html"));
29631
30025
  });
29632
- app72.get("/public-chat", (c) => {
30026
+ app74.get("/public-chat", (c) => {
29633
30027
  const host = (c.req.header("host") ?? "").split(":")[0];
29634
30028
  if (isPublicHost(host)) return c.text("Not found", 404);
29635
30029
  return c.html(cachedHtml("public.html"));
@@ -29648,9 +30042,9 @@ async function logViewerFetch(c, next) {
29648
30042
  duration_ms: Date.now() - start
29649
30043
  });
29650
30044
  }
29651
- app72.use("/vnc-viewer.html", logViewerFetch);
29652
- app72.use("/vnc-popout.html", logViewerFetch);
29653
- app72.get("/vnc-popout.html", (c) => {
30045
+ app74.use("/vnc-viewer.html", logViewerFetch);
30046
+ app74.use("/vnc-popout.html", logViewerFetch);
30047
+ app74.get("/vnc-popout.html", (c) => {
29654
30048
  let html = htmlCache.get("vnc-popout.html");
29655
30049
  if (!html) {
29656
30050
  html = readFileSync44(resolve42(process.cwd(), "public", "vnc-popout.html"), "utf-8");
@@ -29663,7 +30057,7 @@ app72.get("/vnc-popout.html", (c) => {
29663
30057
  }
29664
30058
  return c.html(html);
29665
30059
  });
29666
- app72.post("/api/vnc/client-event", async (c) => {
30060
+ app74.post("/api/vnc/client-event", async (c) => {
29667
30061
  let body;
29668
30062
  try {
29669
30063
  body = await c.req.json();
@@ -29684,11 +30078,11 @@ app72.post("/api/vnc/client-event", async (c) => {
29684
30078
  });
29685
30079
  return c.json({ ok: true });
29686
30080
  });
29687
- app72.get("/g/:slug", (c) => {
30081
+ app74.get("/g/:slug", (c) => {
29688
30082
  return c.html(brandedPublicHtml(resolveDefaultSlug() ?? void 0));
29689
30083
  });
29690
30084
  for (const pwa of PWA_SURFACES) {
29691
- app72.get(pwa.manifestPath, (c) => {
30085
+ app74.get(pwa.manifestPath, (c) => {
29692
30086
  const manifest = buildManifest(pwa, {
29693
30087
  productName: BRAND.productName,
29694
30088
  appIcon192: brandAppIcon192Path,
@@ -29704,7 +30098,7 @@ for (const pwa of PWA_SURFACES) {
29704
30098
  return c.body(JSON.stringify(manifest));
29705
30099
  });
29706
30100
  }
29707
- app72.get("/sw.js", (c) => {
30101
+ app74.get("/sw.js", (c) => {
29708
30102
  if (SW_SOURCE == null) {
29709
30103
  console.error("[pwa] op=sw status=500 reason=sw-source-missing");
29710
30104
  return c.text("Service worker unavailable", 500);
@@ -29713,12 +30107,12 @@ app72.get("/sw.js", (c) => {
29713
30107
  console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
29714
30108
  return c.body(SW_SOURCE);
29715
30109
  });
29716
- app72.get("/graph", (c) => {
30110
+ app74.get("/graph", (c) => {
29717
30111
  const host = (c.req.header("host") ?? "").split(":")[0];
29718
30112
  if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
29719
30113
  return c.html(cachedHtml("graph.html"));
29720
30114
  });
29721
- app72.get("/chat", (c) => {
30115
+ app74.get("/chat", (c) => {
29722
30116
  const host = (c.req.header("host") ?? "").split(":")[0];
29723
30117
  if (isOperatorHost(host, getOperatorDomains())) {
29724
30118
  console.log(`[host-class] host=${host} class=operator served=operator.html`);
@@ -29727,47 +30121,47 @@ app72.get("/chat", (c) => {
29727
30121
  if (isPublicHost(host)) return c.text("Not found", 404);
29728
30122
  return c.html(cachedHtml("chat.html"));
29729
30123
  });
29730
- app72.get("/data", (c) => {
30124
+ app74.get("/data", (c) => {
29731
30125
  const host = (c.req.header("host") ?? "").split(":")[0];
29732
30126
  if (isPublicHost(host)) return c.text("Not found", 404);
29733
30127
  return c.html(cachedHtml("data.html"));
29734
30128
  });
29735
- app72.get("/tasks", (c) => {
30129
+ app74.get("/tasks", (c) => {
29736
30130
  const host = (c.req.header("host") ?? "").split(":")[0];
29737
30131
  if (isPublicHost(host)) return c.text("Not found", 404);
29738
30132
  return c.html(cachedHtml("tasks.html"));
29739
30133
  });
29740
- app72.get("/activity", (c) => {
30134
+ app74.get("/activity", (c) => {
29741
30135
  const host = (c.req.header("host") ?? "").split(":")[0];
29742
30136
  if (isPublicHost(host)) return c.text("Not found", 404);
29743
30137
  return c.html(cachedHtml("activity.html"));
29744
30138
  });
29745
- app72.get("/calendar", (c) => {
30139
+ app74.get("/calendar", (c) => {
29746
30140
  const host = (c.req.header("host") ?? "").split(":")[0];
29747
30141
  if (isPublicHost(host)) return c.text("Not found", 404);
29748
30142
  return c.html(cachedHtml("calendar.html"));
29749
30143
  });
29750
- app72.get("/routines", (c) => {
30144
+ app74.get("/routines", (c) => {
29751
30145
  const host = (c.req.header("host") ?? "").split(":")[0];
29752
30146
  if (isPublicHost(host)) return c.text("Not found", 404);
29753
30147
  return c.html(cachedHtml("routines.html"));
29754
30148
  });
29755
- app72.get("/skills", (c) => {
30149
+ app74.get("/skills", (c) => {
29756
30150
  const host = (c.req.header("host") ?? "").split(":")[0];
29757
30151
  if (isPublicHost(host)) return c.text("Not found", 404);
29758
30152
  return c.html(cachedHtml("skills.html"));
29759
30153
  });
29760
- app72.get("/agents", (c) => {
30154
+ app74.get("/agents", (c) => {
29761
30155
  const host = (c.req.header("host") ?? "").split(":")[0];
29762
30156
  if (isPublicHost(host)) return c.text("Not found", 404);
29763
30157
  return c.html(cachedHtml("agents.html"));
29764
30158
  });
29765
- app72.get("/browser", (c) => {
30159
+ app74.get("/browser", (c) => {
29766
30160
  const host = (c.req.header("host") ?? "").split(":")[0];
29767
30161
  if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
29768
30162
  return c.html(cachedHtml("browser.html"));
29769
30163
  });
29770
- app72.get("/:slug", async (c, next) => {
30164
+ app74.get("/:slug", async (c, next) => {
29771
30165
  const slug = c.req.param("slug");
29772
30166
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
29773
30167
  const account = resolveAccount();
@@ -29782,13 +30176,13 @@ app72.get("/:slug", async (c, next) => {
29782
30176
  await next();
29783
30177
  });
29784
30178
  if (brandFaviconPath !== "/favicon.ico") {
29785
- app72.get("/favicon.ico", (c) => {
30179
+ app74.get("/favicon.ico", (c) => {
29786
30180
  c.header("Cache-Control", "public, max-age=300");
29787
30181
  return c.redirect(brandFaviconPath, 302);
29788
30182
  });
29789
30183
  }
29790
- mountStaticFiles(app72, "./public");
29791
- app72.all("*", (c) => {
30184
+ mountStaticFiles(app74, "./public");
30185
+ app74.all("*", (c) => {
29792
30186
  const host = (c.req.header("host") ?? "").split(":")[0];
29793
30187
  const path = c.req.path;
29794
30188
  if (isPublicHost(host)) {
@@ -29802,10 +30196,10 @@ app72.all("*", (c) => {
29802
30196
  });
29803
30197
  var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
29804
30198
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
29805
- var httpServer = serve({ fetch: app72.fetch, port, hostname });
30199
+ var httpServer = serve({ fetch: app74.fetch, port, hostname });
29806
30200
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29807
30201
  {
29808
- const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..");
30202
+ const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
29809
30203
  const reconcileScript = resolve42(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
29810
30204
  const runReconcile = (ctx) => {
29811
30205
  if (!existsSync48(reconcileScript)) return;
@@ -29828,7 +30222,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29828
30222
  detached: true,
29829
30223
  run: runReconcile
29830
30224
  });
29831
- const reconcileStatePath = join50(MAXY_DIR, "booking-reconcile-state.json");
30225
+ const reconcileStatePath = join51(MAXY_DIR, "booking-reconcile-state.json");
29832
30226
  registerLoop({
29833
30227
  name: "calendar-reconcile-liveness",
29834
30228
  intervalMs: 6e5,
@@ -29846,7 +30240,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29846
30240
  }
29847
30241
  {
29848
30242
  const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
29849
- const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..");
30243
+ const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
29850
30244
  const dreamSweepScript = resolve42(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
29851
30245
  registerLoop({
29852
30246
  name: "dream-cycle-sweep",
@@ -29870,7 +30264,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29870
30264
  });
29871
30265
  }
29872
30266
  {
29873
- const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..");
30267
+ const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
29874
30268
  const outlookScript = resolve42(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
29875
30269
  const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
29876
30270
  const runOutlookComplete = (ctx) => {
@@ -29896,7 +30290,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29896
30290
  });
29897
30291
  }
29898
30292
  {
29899
- const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..");
30293
+ const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
29900
30294
  const strandedAccountsDir = resolve42(auditRoot, "..", "data/accounts");
29901
30295
  const STRANDED_AUDIT_INTERVAL_MS = 3e5;
29902
30296
  const STRANDED_AGE_MS = 16 * 6e4;
@@ -29926,7 +30320,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29926
30320
  });
29927
30321
  }
29928
30322
  {
29929
- const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..");
30323
+ const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
29930
30324
  const googleAccountsDir = resolve42(googleRoot, "..", "data/accounts");
29931
30325
  const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
29932
30326
  const runGooglePendingAuditSafe = () => {
@@ -29970,7 +30364,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
29970
30364
  });
29971
30365
  }
29972
30366
  {
29973
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..");
30367
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
29974
30368
  const STORAGE_AUDIT_INTERVAL_MS = 3e5;
29975
30369
  const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
29976
30370
  console.error(`[storage-audit] error="${err.message}"`);
@@ -30029,9 +30423,15 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
30029
30423
  firstRunDelayMs: 15e4,
30030
30424
  run: auditGroupOutboundNote
30031
30425
  });
30426
+ registerLoop({
30427
+ name: "wa-chatmeta-sweep",
30428
+ intervalMs: WA_STANDING_CHECK_INTERVAL_MS,
30429
+ firstRunDelayMs: 18e4,
30430
+ run: sweepChatMetadata
30431
+ });
30032
30432
  }
30033
30433
  {
30034
- const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..");
30434
+ const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
30035
30435
  const publishScript = resolve42(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
30036
30436
  const PUBLISH_INTERVAL_MS = 3e5;
30037
30437
  const bookingAccounts = () => {
@@ -30108,7 +30508,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
30108
30508
  startTimeEntryCensus(() => getSession());
30109
30509
  startLedgerCensus(() => getSession());
30110
30510
  {
30111
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..");
30511
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
30112
30512
  const auditScript = resolve42(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
30113
30513
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
30114
30514
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
@@ -30193,7 +30593,7 @@ for (const m of SUBAPP_MANIFEST) {
30193
30593
  }
30194
30594
  try {
30195
30595
  const registered = [];
30196
- for (const r of app72.routes ?? []) {
30596
+ for (const r of app74.routes ?? []) {
30197
30597
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
30198
30598
  if (AGENT_SLUG_PATTERN.test(r.path)) {
30199
30599
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -30359,7 +30759,7 @@ try {
30359
30759
  } catch (err) {
30360
30760
  console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
30361
30761
  }
30362
- var configDirForWhatsApp = basename15(MAXY_DIR) || ".maxy";
30762
+ var configDirForWhatsApp = basename16(MAXY_DIR) || ".maxy";
30363
30763
  var bootAccount = resolveAccount();
30364
30764
  if (bootAccount) {
30365
30765
  migrateRemovedConfigKeys(bootAccount.accountDir);
@@ -30424,7 +30824,7 @@ if (bootAccountConfig?.whatsapp) {
30424
30824
  }
30425
30825
  init({
30426
30826
  configDir: configDirForWhatsApp,
30427
- platformRoot: resolve42(process.env.MAXY_PLATFORM_ROOT ?? join50(__dirname, "..")),
30827
+ platformRoot: resolve42(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..")),
30428
30828
  accountConfig: bootAccountConfig,
30429
30829
  // Task 2074 — enrich with the sub-account name and fan out to every open
30430
30830
  // admin SSE stream. Fire-and-forget: the manager's persist path must not