@rubytech/create-realagent-code 0.1.602 → 0.1.604

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 (275) hide show
  1. package/dist/__tests__/email-sampler-unit.test.js +22 -0
  2. package/dist/index.js +3 -0
  3. package/dist/port-resolution.js +9 -1
  4. package/package.json +1 -1
  5. package/payload/platform/lib/routine-templates/dist/roster.d.ts +17 -1
  6. package/payload/platform/lib/routine-templates/dist/roster.d.ts.map +1 -1
  7. package/payload/platform/lib/routine-templates/dist/roster.js +8 -0
  8. package/payload/platform/lib/routine-templates/dist/roster.js.map +1 -1
  9. package/payload/platform/lib/routine-templates/src/__tests__/seed.test.ts +26 -1
  10. package/payload/platform/lib/routine-templates/src/roster.ts +26 -1
  11. package/payload/platform/lib/telegram-store-read/dist/index.d.ts +59 -0
  12. package/payload/platform/lib/telegram-store-read/dist/index.d.ts.map +1 -0
  13. package/payload/platform/lib/telegram-store-read/dist/index.js +219 -0
  14. package/payload/platform/lib/telegram-store-read/dist/index.js.map +1 -0
  15. package/payload/platform/lib/telegram-store-read/src/__tests__/fold.test.ts +124 -0
  16. package/payload/platform/lib/telegram-store-read/src/index.ts +262 -0
  17. package/payload/platform/lib/telegram-store-read/tsconfig.json +9 -0
  18. package/payload/platform/lib/telegram-store-read/vitest.config.ts +9 -0
  19. package/payload/platform/neo4j/schema.cypher +7 -0
  20. package/payload/platform/package.json +2 -2
  21. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +51 -4
  22. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
  23. package/payload/platform/plugins/docs/references/outlook-guide.md +21 -2
  24. package/payload/platform/plugins/docs/references/telegram-guide.md +29 -1
  25. package/payload/platform/plugins/email/PLUGIN.md +10 -1
  26. package/payload/platform/plugins/email/mcp/dist/sampler/__tests__/sample-mailbox.test.js +30 -0
  27. package/payload/platform/plugins/email/mcp/dist/sampler/__tests__/sample-mailbox.test.js.map +1 -1
  28. package/payload/platform/plugins/email/mcp/dist/sampler/main.js +49 -3
  29. package/payload/platform/plugins/email/mcp/dist/sampler/main.js.map +1 -1
  30. package/payload/platform/plugins/email/mcp/dist/sampler/sample-mailbox.d.ts +5 -0
  31. package/payload/platform/plugins/email/mcp/dist/sampler/sample-mailbox.d.ts.map +1 -1
  32. package/payload/platform/plugins/email/mcp/dist/sampler/sample-mailbox.js +10 -5
  33. package/payload/platform/plugins/email/mcp/dist/sampler/sample-mailbox.js.map +1 -1
  34. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.js +11 -0
  35. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.js.map +1 -1
  36. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
  37. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +8 -0
  38. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
  39. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sample-outlook-mailbox.test.d.ts +2 -0
  40. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sample-outlook-mailbox.test.d.ts.map +1 -0
  41. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sample-outlook-mailbox.test.js +324 -0
  42. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sample-outlook-mailbox.test.js.map +1 -0
  43. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sampler-cursor.test.d.ts +2 -0
  44. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sampler-cursor.test.d.ts.map +1 -0
  45. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sampler-cursor.test.js +102 -0
  46. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sampler-cursor.test.js.map +1 -0
  47. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sampler-enumerate.test.d.ts +2 -0
  48. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sampler-enumerate.test.d.ts.map +1 -0
  49. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sampler-enumerate.test.js +125 -0
  50. package/payload/platform/plugins/outlook/mcp/dist/__tests__/sampler-enumerate.test.js.map +1 -0
  51. package/payload/platform/plugins/outlook/mcp/dist/sampler/arm.d.ts +2 -0
  52. package/payload/platform/plugins/outlook/mcp/dist/sampler/arm.d.ts.map +1 -0
  53. package/payload/platform/plugins/outlook/mcp/dist/sampler/arm.js +109 -0
  54. package/payload/platform/plugins/outlook/mcp/dist/sampler/arm.js.map +1 -0
  55. package/payload/platform/plugins/outlook/mcp/dist/sampler/cursor.d.ts +25 -0
  56. package/payload/platform/plugins/outlook/mcp/dist/sampler/cursor.d.ts.map +1 -0
  57. package/payload/platform/plugins/outlook/mcp/dist/sampler/cursor.js +94 -0
  58. package/payload/platform/plugins/outlook/mcp/dist/sampler/cursor.js.map +1 -0
  59. package/payload/platform/plugins/outlook/mcp/dist/sampler/enumerate.d.ts +41 -0
  60. package/payload/platform/plugins/outlook/mcp/dist/sampler/enumerate.d.ts.map +1 -0
  61. package/payload/platform/plugins/outlook/mcp/dist/sampler/enumerate.js +122 -0
  62. package/payload/platform/plugins/outlook/mcp/dist/sampler/enumerate.js.map +1 -0
  63. package/payload/platform/plugins/outlook/mcp/dist/sampler/sample-outlook-mailbox.d.ts +73 -0
  64. package/payload/platform/plugins/outlook/mcp/dist/sampler/sample-outlook-mailbox.d.ts.map +1 -0
  65. package/payload/platform/plugins/outlook/mcp/dist/sampler/sample-outlook-mailbox.js +162 -0
  66. package/payload/platform/plugins/outlook/mcp/dist/sampler/sample-outlook-mailbox.js.map +1 -0
  67. package/payload/platform/plugins/scheduling/mcp/dist/index.js +1 -1
  68. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  69. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-flag.test.d.ts +2 -0
  70. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-flag.test.d.ts.map +1 -0
  71. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-flag.test.js +90 -0
  72. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-flag.test.js.map +1 -0
  73. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +26 -4
  74. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -1
  75. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate-flag.d.ts +78 -0
  76. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate-flag.d.ts.map +1 -0
  77. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate-flag.js +76 -0
  78. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate-flag.js.map +1 -0
  79. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +8 -0
  80. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
  81. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +9 -1
  82. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
  83. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js +15 -0
  84. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js.map +1 -1
  85. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +12 -1
  86. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  87. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +34 -1
  88. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  89. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +9 -1
  90. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  91. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +116 -4
  92. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
  93. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +60 -2
  94. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
  95. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +101 -4
  96. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
  97. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -1
  98. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  99. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  100. package/payload/server/public/activity.html +6 -6
  101. package/payload/server/public/agents.html +5 -5
  102. package/payload/server/public/assets/{AdminLoginScreens-CaQqLuxZ.js → AdminLoginScreens-DI5bNlX8.js} +1 -1
  103. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.br +0 -0
  104. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.gz +0 -0
  105. package/payload/server/public/assets/{AdminShell-D8WTrqem.js → AdminShell-B-iX9ahJ.js} +1 -1
  106. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.br +0 -0
  107. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.gz +0 -0
  108. package/payload/server/public/assets/{activity-B3fiJrC2.js → activity-CqgFwANo.js} +1 -1
  109. package/payload/server/public/assets/activity-CqgFwANo.js.br +0 -0
  110. package/payload/server/public/assets/activity-CqgFwANo.js.gz +0 -0
  111. package/payload/server/public/assets/{admin-ouF-DflP.js → admin-K63n6ybW.js} +1 -1
  112. package/payload/server/public/assets/admin-K63n6ybW.js.br +0 -0
  113. package/payload/server/public/assets/admin-K63n6ybW.js.gz +0 -0
  114. package/payload/server/public/assets/{agents-C8RSXHdh.js → agents-cue5Zf8X.js} +1 -1
  115. package/payload/server/public/assets/agents-cue5Zf8X.js.br +0 -0
  116. package/payload/server/public/assets/agents-cue5Zf8X.js.gz +0 -0
  117. package/payload/server/public/assets/{browser-Dbv6-Rag.js → browser-CqDBcKwU.js} +1 -1
  118. package/payload/server/public/assets/browser-CqDBcKwU.js.br +0 -0
  119. package/payload/server/public/assets/browser-CqDBcKwU.js.gz +0 -0
  120. package/payload/server/public/assets/{calendar-vJjtsH9n.js → calendar-BgzuW5Rt.js} +1 -1
  121. package/payload/server/public/assets/calendar-BgzuW5Rt.js.br +0 -0
  122. package/payload/server/public/assets/calendar-BgzuW5Rt.js.gz +0 -0
  123. package/payload/server/public/assets/chat-HYZViu2u.js +1 -0
  124. package/payload/server/public/assets/chat-HYZViu2u.js.br +3 -0
  125. package/payload/server/public/assets/chat-HYZViu2u.js.gz +0 -0
  126. package/payload/server/public/assets/chevron-left-C5FXH9r_.js +1 -0
  127. package/payload/server/public/assets/chevron-left-C5FXH9r_.js.br +0 -0
  128. package/payload/server/public/assets/clock-DxPtyejC.js +1 -0
  129. package/payload/server/public/assets/clock-DxPtyejC.js.br +0 -0
  130. package/payload/server/public/assets/clock-DxPtyejC.js.gz +0 -0
  131. package/payload/server/public/assets/{copy-DyG7sC5o.js → copy-BNhZ0flH.js} +1 -1
  132. package/payload/server/public/assets/copy-BNhZ0flH.js.br +0 -0
  133. package/payload/server/public/assets/copy-BNhZ0flH.js.gz +0 -0
  134. package/payload/server/public/assets/data-kCBB8Z4Z.js +1 -0
  135. package/payload/server/public/assets/data-kCBB8Z4Z.js.br +0 -0
  136. package/payload/server/public/assets/data-kCBB8Z4Z.js.gz +0 -0
  137. package/payload/server/public/assets/{field-Bx6pM-vq.js → field-X4OVA3vx.js} +1 -1
  138. package/payload/server/public/assets/field-X4OVA3vx.js.br +0 -0
  139. package/payload/server/public/assets/field-X4OVA3vx.js.gz +0 -0
  140. package/payload/server/public/assets/{file-text-CpHWsMGe.js → file-text-BddO_2EI.js} +1 -1
  141. package/payload/server/public/assets/file-text-BddO_2EI.js.br +0 -0
  142. package/payload/server/public/assets/file-text-BddO_2EI.js.gz +0 -0
  143. package/payload/server/public/assets/{graph-DjOywuv_.js → graph-l7tzHqvm.js} +1 -1
  144. package/payload/server/public/assets/graph-l7tzHqvm.js.br +0 -0
  145. package/payload/server/public/assets/graph-l7tzHqvm.js.gz +0 -0
  146. package/payload/server/public/assets/{graph-labels-CGWtqa-m.js → graph-labels-CtFFq5W2.js} +1 -1
  147. package/payload/server/public/assets/graph-labels-CtFFq5W2.js.br +0 -0
  148. package/payload/server/public/assets/graph-labels-CtFFq5W2.js.gz +0 -0
  149. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css +1 -0
  150. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.br +0 -0
  151. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.gz +0 -0
  152. package/payload/server/public/assets/{operator-_DN0RF1R.js → operator-Dg-dwf7a.js} +1 -1
  153. package/payload/server/public/assets/operator-Dg-dwf7a.js.br +7 -0
  154. package/payload/server/public/assets/operator-Dg-dwf7a.js.gz +0 -0
  155. package/payload/server/public/assets/{page-DI4qQIK0.js → page-Ci1bfIbs.js} +1 -1
  156. package/payload/server/public/assets/page-Ci1bfIbs.js.br +0 -0
  157. package/payload/server/public/assets/page-Ci1bfIbs.js.gz +0 -0
  158. package/payload/server/public/assets/{page-zCwgrs8m.js → page-Y9JmFq0Q.js} +1 -1
  159. package/payload/server/public/assets/page-Y9JmFq0Q.js.br +0 -0
  160. package/payload/server/public/assets/page-Y9JmFq0Q.js.gz +0 -0
  161. package/payload/server/public/assets/play-BSZVGpQT.js +1 -0
  162. package/payload/server/public/assets/play-BSZVGpQT.js.br +0 -0
  163. package/payload/server/public/assets/play-BSZVGpQT.js.gz +0 -0
  164. package/payload/server/public/assets/{public-DDVWBNSH.js → public-m66FAza_.js} +1 -1
  165. package/payload/server/public/assets/public-m66FAza_.js.br +0 -0
  166. package/payload/server/public/assets/public-m66FAza_.js.gz +0 -0
  167. package/payload/server/public/assets/{rotate-ccw-xTwkf-m7.js → rotate-ccw-DTOJmOxB.js} +1 -1
  168. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.br +0 -0
  169. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.gz +0 -0
  170. package/payload/server/public/assets/{routines-Bu5MdNmG.js → routines-6fxZNacQ.js} +1 -1
  171. package/payload/server/public/assets/routines-6fxZNacQ.js.br +0 -0
  172. package/payload/server/public/assets/routines-6fxZNacQ.js.gz +0 -0
  173. package/payload/server/public/assets/{skills-DRunh5vy.js → skills-51mqx-s5.js} +1 -1
  174. package/payload/server/public/assets/skills-51mqx-s5.js.br +0 -0
  175. package/payload/server/public/assets/skills-51mqx-s5.js.gz +0 -0
  176. package/payload/server/public/assets/{tasks-DI2fznvd.js → tasks-D4y-Cwa3.js} +1 -1
  177. package/payload/server/public/assets/tasks-D4y-Cwa3.js.br +0 -0
  178. package/payload/server/public/assets/tasks-D4y-Cwa3.js.gz +0 -0
  179. package/payload/server/public/assets/{triangle-alert-B6CHZeUf.js → triangle-alert-BzCjDFts.js} +1 -1
  180. package/payload/server/public/assets/triangle-alert-BzCjDFts.js.br +0 -0
  181. package/payload/server/public/assets/triangle-alert-BzCjDFts.js.gz +0 -0
  182. package/payload/server/public/assets/{useCopyFeedback-6rU2IEPk.js → useCopyFeedback-BG7h37Rx.js} +1 -1
  183. package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.br +2 -0
  184. package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.gz +0 -0
  185. package/payload/server/public/assets/{useMediaQuery-D7A5Bzs3.js → useMediaQuery-CqwktQr_.js} +1 -1
  186. package/payload/server/public/assets/useMediaQuery-CqwktQr_.js.br +0 -0
  187. package/payload/server/public/assets/{useMediaQuery-D7A5Bzs3.js.gz → useMediaQuery-CqwktQr_.js.gz} +0 -0
  188. package/payload/server/public/assets/{useVoiceRecorder-CptrerVA.js → useVoiceRecorder-CAZcUc1s.js} +1 -1
  189. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.br +0 -0
  190. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.gz +0 -0
  191. package/payload/server/public/assets/{wrench-DyX4C8aY.js → wrench-B2WKLLQG.js} +1 -1
  192. package/payload/server/public/assets/wrench-B2WKLLQG.js.br +0 -0
  193. package/payload/server/public/assets/wrench-B2WKLLQG.js.gz +0 -0
  194. package/payload/server/public/browser.html +5 -5
  195. package/payload/server/public/calendar.html +8 -8
  196. package/payload/server/public/chat.html +14 -14
  197. package/payload/server/public/data.html +12 -12
  198. package/payload/server/public/field.html +3 -3
  199. package/payload/server/public/graph.html +10 -10
  200. package/payload/server/public/index.html +14 -14
  201. package/payload/server/public/operator.html +15 -15
  202. package/payload/server/public/public.html +14 -14
  203. package/payload/server/public/routines.html +8 -8
  204. package/payload/server/public/skills.html +6 -6
  205. package/payload/server/public/tasks.html +7 -7
  206. package/payload/server/server.js +500 -325
  207. package/payload/server/public/assets/AdminLoginScreens-CaQqLuxZ.js.br +0 -0
  208. package/payload/server/public/assets/AdminLoginScreens-CaQqLuxZ.js.gz +0 -0
  209. package/payload/server/public/assets/AdminShell-D8WTrqem.js.br +0 -0
  210. package/payload/server/public/assets/AdminShell-D8WTrqem.js.gz +0 -0
  211. package/payload/server/public/assets/activity-B3fiJrC2.js.br +0 -0
  212. package/payload/server/public/assets/activity-B3fiJrC2.js.gz +0 -0
  213. package/payload/server/public/assets/admin-ouF-DflP.js.br +0 -0
  214. package/payload/server/public/assets/admin-ouF-DflP.js.gz +0 -0
  215. package/payload/server/public/assets/agents-C8RSXHdh.js.br +0 -0
  216. package/payload/server/public/assets/agents-C8RSXHdh.js.gz +0 -0
  217. package/payload/server/public/assets/browser-Dbv6-Rag.js.br +0 -0
  218. package/payload/server/public/assets/browser-Dbv6-Rag.js.gz +0 -0
  219. package/payload/server/public/assets/calendar-vJjtsH9n.js.br +0 -0
  220. package/payload/server/public/assets/calendar-vJjtsH9n.js.gz +0 -0
  221. package/payload/server/public/assets/chat-cqL4qPUy.js +0 -1
  222. package/payload/server/public/assets/chat-cqL4qPUy.js.br +0 -1
  223. package/payload/server/public/assets/chat-cqL4qPUy.js.gz +0 -0
  224. package/payload/server/public/assets/chevron-left-DB98DSG3.js +0 -1
  225. package/payload/server/public/assets/chevron-left-DB98DSG3.js.br +0 -0
  226. package/payload/server/public/assets/clock-4YwsYe4L.js +0 -1
  227. package/payload/server/public/assets/clock-4YwsYe4L.js.br +0 -0
  228. package/payload/server/public/assets/clock-4YwsYe4L.js.gz +0 -0
  229. package/payload/server/public/assets/copy-DyG7sC5o.js.br +0 -0
  230. package/payload/server/public/assets/copy-DyG7sC5o.js.gz +0 -0
  231. package/payload/server/public/assets/data-BAzLtx9C.js +0 -1
  232. package/payload/server/public/assets/data-BAzLtx9C.js.br +0 -0
  233. package/payload/server/public/assets/data-BAzLtx9C.js.gz +0 -0
  234. package/payload/server/public/assets/field-Bx6pM-vq.js.br +0 -0
  235. package/payload/server/public/assets/field-Bx6pM-vq.js.gz +0 -0
  236. package/payload/server/public/assets/file-text-CpHWsMGe.js.br +0 -0
  237. package/payload/server/public/assets/file-text-CpHWsMGe.js.gz +0 -0
  238. package/payload/server/public/assets/graph-DjOywuv_.js.br +0 -0
  239. package/payload/server/public/assets/graph-DjOywuv_.js.gz +0 -0
  240. package/payload/server/public/assets/graph-labels-CGWtqa-m.js.br +0 -0
  241. package/payload/server/public/assets/graph-labels-CGWtqa-m.js.gz +0 -0
  242. package/payload/server/public/assets/jsx-runtime-D75_aR1J.css +0 -1
  243. package/payload/server/public/assets/jsx-runtime-D75_aR1J.css.br +0 -0
  244. package/payload/server/public/assets/jsx-runtime-D75_aR1J.css.gz +0 -0
  245. package/payload/server/public/assets/operator-_DN0RF1R.js.br +0 -0
  246. package/payload/server/public/assets/operator-_DN0RF1R.js.gz +0 -0
  247. package/payload/server/public/assets/page-DI4qQIK0.js.br +0 -0
  248. package/payload/server/public/assets/page-DI4qQIK0.js.gz +0 -0
  249. package/payload/server/public/assets/page-zCwgrs8m.js.br +0 -0
  250. package/payload/server/public/assets/page-zCwgrs8m.js.gz +0 -0
  251. package/payload/server/public/assets/play-CHQ5a9yh.js +0 -1
  252. package/payload/server/public/assets/play-CHQ5a9yh.js.br +0 -0
  253. package/payload/server/public/assets/play-CHQ5a9yh.js.gz +0 -0
  254. package/payload/server/public/assets/public-DDVWBNSH.js.br +0 -0
  255. package/payload/server/public/assets/public-DDVWBNSH.js.gz +0 -0
  256. package/payload/server/public/assets/rotate-ccw-xTwkf-m7.js.br +0 -0
  257. package/payload/server/public/assets/rotate-ccw-xTwkf-m7.js.gz +0 -0
  258. package/payload/server/public/assets/routines-Bu5MdNmG.js.br +0 -0
  259. package/payload/server/public/assets/routines-Bu5MdNmG.js.gz +0 -0
  260. package/payload/server/public/assets/skills-DRunh5vy.js.br +0 -0
  261. package/payload/server/public/assets/skills-DRunh5vy.js.gz +0 -0
  262. package/payload/server/public/assets/tasks-DI2fznvd.js.br +0 -0
  263. package/payload/server/public/assets/tasks-DI2fznvd.js.gz +0 -0
  264. package/payload/server/public/assets/triangle-alert-B6CHZeUf.js.br +0 -0
  265. package/payload/server/public/assets/triangle-alert-B6CHZeUf.js.gz +0 -0
  266. package/payload/server/public/assets/useCopyFeedback-6rU2IEPk.js.br +0 -2
  267. package/payload/server/public/assets/useCopyFeedback-6rU2IEPk.js.gz +0 -0
  268. package/payload/server/public/assets/useMediaQuery-D7A5Bzs3.js.br +0 -0
  269. package/payload/server/public/assets/useVoiceRecorder-CptrerVA.js.br +0 -0
  270. package/payload/server/public/assets/useVoiceRecorder-CptrerVA.js.gz +0 -0
  271. package/payload/server/public/assets/wrench-DyX4C8aY.js.br +0 -0
  272. package/payload/server/public/assets/wrench-DyX4C8aY.js.gz +0 -0
  273. /package/payload/server/public/assets/{jsx-runtime-B2Q1UOSJ.js → jsx-runtime-UK6hgBWO.js} +0 -0
  274. /package/payload/server/public/assets/{jsx-runtime-B2Q1UOSJ.js.br → jsx-runtime-UK6hgBWO.js.br} +0 -0
  275. /package/payload/server/public/assets/{jsx-runtime-B2Q1UOSJ.js.gz → jsx-runtime-UK6hgBWO.js.gz} +0 -0
@@ -612,8 +612,289 @@ var require_dist4 = __commonJS({
612
612
  }
613
613
  });
614
614
 
615
- // ../lib/telegram-button-labels/dist/index.js
615
+ // ../lib/graph-trash/dist/index.js
616
616
  var require_dist5 = __commonJS({
617
+ "../lib/graph-trash/dist/index.js"(exports) {
618
+ "use strict";
619
+ Object.defineProperty(exports, "__esModule", { value: true });
620
+ exports.TRASH_METADATA_PROPS = void 0;
621
+ exports.trashNode = trashNode2;
622
+ exports.restoreNode = restoreNode2;
623
+ exports.emptyTrash = emptyTrash;
624
+ exports.notTrashed = notTrashed4;
625
+ exports.uniqueKeysForLabels = uniqueKeysForLabels;
626
+ var UNIQUE_KEYS_BY_LABEL2 = {
627
+ Person: ["email", "telephone"],
628
+ Service: ["serviceId"],
629
+ LocalBusiness: ["accountId"],
630
+ Task: ["taskId"],
631
+ Event: ["eventId"],
632
+ // :KnowledgeDocument is keyed on `attachmentId` (document writer path —
633
+ // file/URL/obsidian/contract attachment + legacy Gmail-thread shape under
634
+ // `source:'email'`). Task 397 split the conversation transcripts off into
635
+ // `:ConversationArchive`, which carries `conversationIdentity`.
636
+ KnowledgeDocument: ["attachmentId"],
637
+ ConversationArchive: ["conversationIdentity"],
638
+ DigitalDocument: ["attachmentId"],
639
+ Conversation: ["sessionId"],
640
+ Message: ["messageId"],
641
+ Workflow: ["workflowId"],
642
+ WorkflowStep: ["stepId"],
643
+ WorkflowRun: ["runId"],
644
+ Preference: ["preferenceId"],
645
+ Email: ["emailId", "messageId"],
646
+ AdminUser: ["userId"],
647
+ ToolCall: ["callId"],
648
+ // Composite component nulls — frees the composite constraint:
649
+ AccessGrant: ["contactValue"],
650
+ // composite (contactValue, agentSlug, accountId)
651
+ UserProfile: ["userId"]
652
+ // composite (accountId, userId)
653
+ };
654
+ var TRASH_PROP_NAMES = [
655
+ "trashedAt",
656
+ "trashedBy",
657
+ "trashReason",
658
+ "_trashedKeys"
659
+ ];
660
+ async function trashNode2(params) {
661
+ const { session, accountId, elementId, by, reason } = params;
662
+ const lookup = await session.run(`MATCH (n) WHERE elementId(n) = $eid AND n.accountId = $accountId
663
+ RETURN labels(n) AS labels, properties(n) AS props`, { eid: elementId, accountId });
664
+ if (lookup.records.length === 0) {
665
+ throw new Error(`trashNode: node not found (elementId=${elementId} accountId=${accountId.slice(0, 8)}\u2026)`);
666
+ }
667
+ const allLabels = lookup.records[0].get("labels");
668
+ const props = lookup.records[0].get("props");
669
+ const baseLabels = allLabels.filter((l) => l !== "Trashed");
670
+ if (allLabels.includes("Trashed")) {
671
+ return {
672
+ trashed: false,
673
+ alreadyTrashed: true,
674
+ nodeId: elementId,
675
+ labels: baseLabels,
676
+ trashedAt: String(props.trashedAt ?? ""),
677
+ originalKeys: {}
678
+ };
679
+ }
680
+ const uniqueKeys = /* @__PURE__ */ new Set();
681
+ for (const label of baseLabels) {
682
+ for (const key2 of UNIQUE_KEYS_BY_LABEL2[label] ?? [])
683
+ uniqueKeys.add(key2);
684
+ }
685
+ const originalKeys = {};
686
+ for (const k of uniqueKeys) {
687
+ if (props[k] !== void 0 && props[k] !== null)
688
+ originalKeys[k] = props[k];
689
+ }
690
+ const setNullClauses = Object.keys(originalKeys).map((k) => `n.\`${k}\` = null`).join(", ");
691
+ const setNullSuffix = setNullClauses ? `, ${setNullClauses}` : "";
692
+ const trashedAt = (/* @__PURE__ */ new Date()).toISOString();
693
+ const isConversation = baseLabels.includes("Conversation");
694
+ const messageUniqueKeys = UNIQUE_KEYS_BY_LABEL2["Message"] ?? [];
695
+ let cascadedMessageCount = 0;
696
+ await session.executeWrite(async (tx) => {
697
+ await tx.run(`MATCH (n) WHERE elementId(n) = $eid
698
+ SET n:Trashed,
699
+ n.trashedAt = datetime($trashedAt),
700
+ n.trashedBy = $by,
701
+ n.trashReason = $reason,
702
+ n._trashedKeys = $trashedKeysJson${setNullSuffix}`, {
703
+ eid: elementId,
704
+ trashedAt,
705
+ by,
706
+ reason: reason ?? null,
707
+ trashedKeysJson: JSON.stringify(originalKeys)
708
+ });
709
+ if (isConversation) {
710
+ const collectKeys = messageUniqueKeys.length > 0 ? messageUniqueKeys.map((k) => `\`${k}\`: m.\`${k}\``).join(", ") : "";
711
+ const collectMsgProps = collectKeys ? `, {${collectKeys}}` : ", {}";
712
+ const collected = await tx.run(`MATCH (c) WHERE elementId(c) = $eid
713
+ MATCH (m:Message)-[:PART_OF]->(c)
714
+ WHERE NOT m:Trashed
715
+ RETURN elementId(m) AS meid${collectMsgProps} AS keys`, { eid: elementId });
716
+ for (const rec of collected.records) {
717
+ const meid = rec.get("meid");
718
+ const keys = rec.get("keys");
719
+ const liveKeys = {};
720
+ for (const k of messageUniqueKeys) {
721
+ if (keys[k] !== void 0 && keys[k] !== null)
722
+ liveKeys[k] = keys[k];
723
+ }
724
+ const msgSetNulls = Object.keys(liveKeys).length > 0 ? ", " + Object.keys(liveKeys).map((k) => `m.\`${k}\` = null`).join(", ") : "";
725
+ await tx.run(`MATCH (m) WHERE elementId(m) = $meid
726
+ SET m:Trashed,
727
+ m.trashedAt = datetime($trashedAt),
728
+ m.trashedBy = $by,
729
+ m.trashReason = $reason,
730
+ m._trashedKeys = $trashedKeysJson${msgSetNulls}`, {
731
+ meid,
732
+ trashedAt,
733
+ by: `${by}:cascade-from-conversation`,
734
+ reason: reason ?? `cascade from Conversation ${elementId}`,
735
+ trashedKeysJson: JSON.stringify(liveKeys)
736
+ });
737
+ }
738
+ cascadedMessageCount = collected.records.length;
739
+ }
740
+ });
741
+ process.stderr.write(`[trash:marked] accountId=${accountId} elementId=${elementId} labels=${baseLabels.join(",")} by=${by} reason=${reason ?? "null"}
742
+ `);
743
+ if (isConversation) {
744
+ process.stderr.write(`[trash:cascaded] accountId=${accountId} conversationElementId=${elementId} messageCount=${cascadedMessageCount} by=${by}
745
+ `);
746
+ }
747
+ return {
748
+ trashed: true,
749
+ alreadyTrashed: false,
750
+ nodeId: elementId,
751
+ labels: baseLabels,
752
+ trashedAt,
753
+ originalKeys
754
+ };
755
+ }
756
+ async function restoreNode2(params) {
757
+ const { session, accountId, elementId } = params;
758
+ const lookup = await session.run(`MATCH (n:Trashed) WHERE elementId(n) = $eid
759
+ RETURN labels(n) AS labels, n._trashedKeys AS keysJson`, { eid: elementId });
760
+ if (lookup.records.length === 0) {
761
+ throw new Error(`restoreNode: trashed node not found (elementId=${elementId})`);
762
+ }
763
+ const allLabels = lookup.records[0].get("labels");
764
+ const baseLabels = allLabels.filter((l) => l !== "Trashed");
765
+ const keysJson = lookup.records[0].get("keysJson");
766
+ const originalKeys = keysJson ? JSON.parse(keysJson) : {};
767
+ for (const label of baseLabels) {
768
+ const uniqueKeys = UNIQUE_KEYS_BY_LABEL2[label] ?? [];
769
+ for (const k of uniqueKeys) {
770
+ const v = originalKeys[k];
771
+ if (v === void 0 || v === null)
772
+ continue;
773
+ const conflict = await session.run(`MATCH (other:\`${label}\`)
774
+ WHERE elementId(other) <> $eid
775
+ AND NOT other:Trashed
776
+ AND other.\`${k}\` = $val
777
+ RETURN elementId(other) AS otherId LIMIT 1`, { eid: elementId, val: v });
778
+ if (conflict.records.length > 0) {
779
+ const otherId = conflict.records[0].get("otherId");
780
+ throw new Error(`restoreNode: cannot restore ${label} elementId=${elementId} \u2014 active node elementId=${otherId} already holds ${k}=${JSON.stringify(v)}`);
781
+ }
782
+ }
783
+ }
784
+ const setClauses = Object.keys(originalKeys).map((k) => `n.\`${k}\` = $val_${k}`).join(", ");
785
+ const setSuffix = setClauses ? `, ${setClauses}` : "";
786
+ const setParams = { eid: elementId };
787
+ for (const [k, v] of Object.entries(originalKeys))
788
+ setParams[`val_${k}`] = v;
789
+ const isConversation = baseLabels.includes("Conversation");
790
+ let cascadedMessageCount = 0;
791
+ await session.executeWrite(async (tx) => {
792
+ await tx.run(`MATCH (n:Trashed) WHERE elementId(n) = $eid
793
+ REMOVE n:Trashed, n.trashedAt, n.trashedBy, n.trashReason, n._trashedKeys
794
+ SET n.restoredAt = datetime()${setSuffix}`, setParams);
795
+ if (isConversation) {
796
+ const collected = await tx.run(`MATCH (c) WHERE elementId(c) = $eid
797
+ MATCH (m:Trashed:Message)-[:PART_OF]->(c)
798
+ WHERE m.trashedBy ENDS WITH ':cascade-from-conversation'
799
+ RETURN elementId(m) AS meid, m._trashedKeys AS keysJson`, { eid: elementId });
800
+ for (const rec of collected.records) {
801
+ const meid = rec.get("meid");
802
+ const keysJson2 = rec.get("keysJson");
803
+ const keys = keysJson2 ? JSON.parse(keysJson2) : {};
804
+ const setClause = Object.keys(keys).length > 0 ? ", " + Object.keys(keys).map((k) => `m.\`${k}\` = $val_${k}`).join(", ") : "";
805
+ const msgParams = { meid };
806
+ for (const [k, v] of Object.entries(keys))
807
+ msgParams[`val_${k}`] = v;
808
+ await tx.run(`MATCH (m) WHERE elementId(m) = $meid
809
+ REMOVE m:Trashed, m.trashedAt, m.trashedBy, m.trashReason, m._trashedKeys
810
+ SET m.restoredAt = datetime()${setClause}`, msgParams);
811
+ }
812
+ cascadedMessageCount = collected.records.length;
813
+ }
814
+ });
815
+ process.stderr.write(`[trash:restored] accountId=${accountId} elementId=${elementId} labels=${baseLabels.join(",")}
816
+ `);
817
+ if (isConversation) {
818
+ process.stderr.write(`[trash:cascade-restored] accountId=${accountId} conversationElementId=${elementId} messageCount=${cascadedMessageCount}
819
+ `);
820
+ }
821
+ return {
822
+ restored: true,
823
+ nodeId: elementId,
824
+ labels: baseLabels,
825
+ restoredKeys: originalKeys
826
+ };
827
+ }
828
+ async function emptyTrash(params) {
829
+ const t0 = Date.now();
830
+ const { session, accountId, graceDays = 30, dryRun = false, labels: labelFilter, onEmpty } = params;
831
+ const cutoff = new Date(Date.now() - graceDays * 24 * 60 * 60 * 1e3).toISOString();
832
+ const labelClause = labelFilter && labelFilter.length > 0 ? `AND ANY(l IN labels(n) WHERE l IN $labelFilter)` : "";
833
+ const candidatesResult = await session.run(`MATCH (n:Trashed)
834
+ WHERE n.trashedAt < datetime($cutoff)
835
+ ${labelClause}
836
+ RETURN elementId(n) AS eid,
837
+ labels(n) AS labels,
838
+ toString(n.trashedAt) AS trashedAt,
839
+ n.trashedBy AS trashedBy,
840
+ n._trashedKeys AS keysJson
841
+ ORDER BY n.trashedAt ASC`, { cutoff, ...labelFilter ? { labelFilter } : {} });
842
+ const candidates = candidatesResult.records.map((r) => {
843
+ const keysJson = r.get("keysJson");
844
+ return {
845
+ elementId: r.get("eid"),
846
+ labels: r.get("labels").filter((l) => l !== "Trashed"),
847
+ trashedAt: String(r.get("trashedAt")),
848
+ trashedBy: r.get("trashedBy") ?? null,
849
+ trashedKeys: keysJson ? JSON.parse(keysJson) : {}
850
+ };
851
+ });
852
+ process.stderr.write(`[trash:empty-run] accountId=${accountId} graceDays=${graceDays} dryRun=${dryRun} candidates=${candidates.length}
853
+ `);
854
+ if (dryRun || candidates.length === 0) {
855
+ process.stderr.write(`[graph:trash:summary] accountId=${accountId} trashedNow=0 emptiedThisRun=0 graceDays=${graceDays} dryRun=${dryRun} elapsedMs=${Date.now() - t0}
856
+ `);
857
+ return { graceDays, dryRun, candidates, emptied: 0 };
858
+ }
859
+ let emptied = 0;
860
+ for (const c of candidates) {
861
+ if (onEmpty) {
862
+ try {
863
+ await onEmpty(c);
864
+ } catch (err) {
865
+ const id83 = c.elementId.slice(0, 8);
866
+ const message = err instanceof Error ? err.message : String(err);
867
+ process.stderr.write(`[trash:empty-run] reason=onEmpty-failed elementId=${id83} labels=${c.labels.join(",")} message=${message}
868
+ `);
869
+ continue;
870
+ }
871
+ }
872
+ await session.run(`MATCH (n) WHERE elementId(n) = $eid DETACH DELETE n`, { eid: c.elementId });
873
+ const ageDays = Math.floor((Date.now() - new Date(c.trashedAt).getTime()) / (24 * 60 * 60 * 1e3));
874
+ process.stderr.write(`[trash:emptied] accountId=${accountId} elementId=${c.elementId} labels=${c.labels.join(",")} trashedAt=${c.trashedAt} ageDays=${ageDays}
875
+ `);
876
+ emptied++;
877
+ }
878
+ process.stderr.write(`[graph:trash:summary] accountId=${accountId} trashedNow=0 emptiedThisRun=${emptied} graceDays=${graceDays} dryRun=${dryRun} elapsedMs=${Date.now() - t0}
879
+ `);
880
+ return { graceDays, dryRun, candidates, emptied };
881
+ }
882
+ function notTrashed4(alias) {
883
+ return `(NOT \`${alias}\`:Trashed AND \`${alias}\`.deletedAt IS NULL)`;
884
+ }
885
+ function uniqueKeysForLabels(labels) {
886
+ const out = /* @__PURE__ */ new Set();
887
+ for (const l of labels)
888
+ for (const k of UNIQUE_KEYS_BY_LABEL2[l] ?? [])
889
+ out.add(k);
890
+ return [...out];
891
+ }
892
+ exports.TRASH_METADATA_PROPS = TRASH_PROP_NAMES;
893
+ }
894
+ });
895
+
896
+ // ../lib/telegram-button-labels/dist/index.js
897
+ var require_dist6 = __commonJS({
617
898
  "../lib/telegram-button-labels/dist/index.js"(exports) {
618
899
  "use strict";
619
900
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1583,7 +1864,7 @@ var require_geo = __commonJS({
1583
1864
  });
1584
1865
 
1585
1866
  // ../lib/dispatch-read/dist/index.js
1586
- var require_dist6 = __commonJS({
1867
+ var require_dist7 = __commonJS({
1587
1868
  "../lib/dispatch-read/dist/index.js"(exports) {
1588
1869
  "use strict";
1589
1870
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1742,7 +2023,7 @@ var require_dist6 = __commonJS({
1742
2023
  });
1743
2024
 
1744
2025
  // ../lib/account-schema-regions/dist/index.js
1745
- var require_dist7 = __commonJS({
2026
+ var require_dist8 = __commonJS({
1746
2027
  "../lib/account-schema-regions/dist/index.js"(exports) {
1747
2028
  "use strict";
1748
2029
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1811,287 +2092,6 @@ var require_dist7 = __commonJS({
1811
2092
  }
1812
2093
  });
1813
2094
 
1814
- // ../lib/graph-trash/dist/index.js
1815
- var require_dist8 = __commonJS({
1816
- "../lib/graph-trash/dist/index.js"(exports) {
1817
- "use strict";
1818
- Object.defineProperty(exports, "__esModule", { value: true });
1819
- exports.TRASH_METADATA_PROPS = void 0;
1820
- exports.trashNode = trashNode2;
1821
- exports.restoreNode = restoreNode2;
1822
- exports.emptyTrash = emptyTrash;
1823
- exports.notTrashed = notTrashed2;
1824
- exports.uniqueKeysForLabels = uniqueKeysForLabels;
1825
- var UNIQUE_KEYS_BY_LABEL2 = {
1826
- Person: ["email", "telephone"],
1827
- Service: ["serviceId"],
1828
- LocalBusiness: ["accountId"],
1829
- Task: ["taskId"],
1830
- Event: ["eventId"],
1831
- // :KnowledgeDocument is keyed on `attachmentId` (document writer path —
1832
- // file/URL/obsidian/contract attachment + legacy Gmail-thread shape under
1833
- // `source:'email'`). Task 397 split the conversation transcripts off into
1834
- // `:ConversationArchive`, which carries `conversationIdentity`.
1835
- KnowledgeDocument: ["attachmentId"],
1836
- ConversationArchive: ["conversationIdentity"],
1837
- DigitalDocument: ["attachmentId"],
1838
- Conversation: ["sessionId"],
1839
- Message: ["messageId"],
1840
- Workflow: ["workflowId"],
1841
- WorkflowStep: ["stepId"],
1842
- WorkflowRun: ["runId"],
1843
- Preference: ["preferenceId"],
1844
- Email: ["emailId", "messageId"],
1845
- AdminUser: ["userId"],
1846
- ToolCall: ["callId"],
1847
- // Composite component nulls — frees the composite constraint:
1848
- AccessGrant: ["contactValue"],
1849
- // composite (contactValue, agentSlug, accountId)
1850
- UserProfile: ["userId"]
1851
- // composite (accountId, userId)
1852
- };
1853
- var TRASH_PROP_NAMES = [
1854
- "trashedAt",
1855
- "trashedBy",
1856
- "trashReason",
1857
- "_trashedKeys"
1858
- ];
1859
- async function trashNode2(params) {
1860
- const { session, accountId, elementId, by, reason } = params;
1861
- const lookup = await session.run(`MATCH (n) WHERE elementId(n) = $eid AND n.accountId = $accountId
1862
- RETURN labels(n) AS labels, properties(n) AS props`, { eid: elementId, accountId });
1863
- if (lookup.records.length === 0) {
1864
- throw new Error(`trashNode: node not found (elementId=${elementId} accountId=${accountId.slice(0, 8)}\u2026)`);
1865
- }
1866
- const allLabels = lookup.records[0].get("labels");
1867
- const props = lookup.records[0].get("props");
1868
- const baseLabels = allLabels.filter((l) => l !== "Trashed");
1869
- if (allLabels.includes("Trashed")) {
1870
- return {
1871
- trashed: false,
1872
- alreadyTrashed: true,
1873
- nodeId: elementId,
1874
- labels: baseLabels,
1875
- trashedAt: String(props.trashedAt ?? ""),
1876
- originalKeys: {}
1877
- };
1878
- }
1879
- const uniqueKeys = /* @__PURE__ */ new Set();
1880
- for (const label of baseLabels) {
1881
- for (const key2 of UNIQUE_KEYS_BY_LABEL2[label] ?? [])
1882
- uniqueKeys.add(key2);
1883
- }
1884
- const originalKeys = {};
1885
- for (const k of uniqueKeys) {
1886
- if (props[k] !== void 0 && props[k] !== null)
1887
- originalKeys[k] = props[k];
1888
- }
1889
- const setNullClauses = Object.keys(originalKeys).map((k) => `n.\`${k}\` = null`).join(", ");
1890
- const setNullSuffix = setNullClauses ? `, ${setNullClauses}` : "";
1891
- const trashedAt = (/* @__PURE__ */ new Date()).toISOString();
1892
- const isConversation = baseLabels.includes("Conversation");
1893
- const messageUniqueKeys = UNIQUE_KEYS_BY_LABEL2["Message"] ?? [];
1894
- let cascadedMessageCount = 0;
1895
- await session.executeWrite(async (tx) => {
1896
- await tx.run(`MATCH (n) WHERE elementId(n) = $eid
1897
- SET n:Trashed,
1898
- n.trashedAt = datetime($trashedAt),
1899
- n.trashedBy = $by,
1900
- n.trashReason = $reason,
1901
- n._trashedKeys = $trashedKeysJson${setNullSuffix}`, {
1902
- eid: elementId,
1903
- trashedAt,
1904
- by,
1905
- reason: reason ?? null,
1906
- trashedKeysJson: JSON.stringify(originalKeys)
1907
- });
1908
- if (isConversation) {
1909
- const collectKeys = messageUniqueKeys.length > 0 ? messageUniqueKeys.map((k) => `\`${k}\`: m.\`${k}\``).join(", ") : "";
1910
- const collectMsgProps = collectKeys ? `, {${collectKeys}}` : ", {}";
1911
- const collected = await tx.run(`MATCH (c) WHERE elementId(c) = $eid
1912
- MATCH (m:Message)-[:PART_OF]->(c)
1913
- WHERE NOT m:Trashed
1914
- RETURN elementId(m) AS meid${collectMsgProps} AS keys`, { eid: elementId });
1915
- for (const rec of collected.records) {
1916
- const meid = rec.get("meid");
1917
- const keys = rec.get("keys");
1918
- const liveKeys = {};
1919
- for (const k of messageUniqueKeys) {
1920
- if (keys[k] !== void 0 && keys[k] !== null)
1921
- liveKeys[k] = keys[k];
1922
- }
1923
- const msgSetNulls = Object.keys(liveKeys).length > 0 ? ", " + Object.keys(liveKeys).map((k) => `m.\`${k}\` = null`).join(", ") : "";
1924
- await tx.run(`MATCH (m) WHERE elementId(m) = $meid
1925
- SET m:Trashed,
1926
- m.trashedAt = datetime($trashedAt),
1927
- m.trashedBy = $by,
1928
- m.trashReason = $reason,
1929
- m._trashedKeys = $trashedKeysJson${msgSetNulls}`, {
1930
- meid,
1931
- trashedAt,
1932
- by: `${by}:cascade-from-conversation`,
1933
- reason: reason ?? `cascade from Conversation ${elementId}`,
1934
- trashedKeysJson: JSON.stringify(liveKeys)
1935
- });
1936
- }
1937
- cascadedMessageCount = collected.records.length;
1938
- }
1939
- });
1940
- process.stderr.write(`[trash:marked] accountId=${accountId} elementId=${elementId} labels=${baseLabels.join(",")} by=${by} reason=${reason ?? "null"}
1941
- `);
1942
- if (isConversation) {
1943
- process.stderr.write(`[trash:cascaded] accountId=${accountId} conversationElementId=${elementId} messageCount=${cascadedMessageCount} by=${by}
1944
- `);
1945
- }
1946
- return {
1947
- trashed: true,
1948
- alreadyTrashed: false,
1949
- nodeId: elementId,
1950
- labels: baseLabels,
1951
- trashedAt,
1952
- originalKeys
1953
- };
1954
- }
1955
- async function restoreNode2(params) {
1956
- const { session, accountId, elementId } = params;
1957
- const lookup = await session.run(`MATCH (n:Trashed) WHERE elementId(n) = $eid
1958
- RETURN labels(n) AS labels, n._trashedKeys AS keysJson`, { eid: elementId });
1959
- if (lookup.records.length === 0) {
1960
- throw new Error(`restoreNode: trashed node not found (elementId=${elementId})`);
1961
- }
1962
- const allLabels = lookup.records[0].get("labels");
1963
- const baseLabels = allLabels.filter((l) => l !== "Trashed");
1964
- const keysJson = lookup.records[0].get("keysJson");
1965
- const originalKeys = keysJson ? JSON.parse(keysJson) : {};
1966
- for (const label of baseLabels) {
1967
- const uniqueKeys = UNIQUE_KEYS_BY_LABEL2[label] ?? [];
1968
- for (const k of uniqueKeys) {
1969
- const v = originalKeys[k];
1970
- if (v === void 0 || v === null)
1971
- continue;
1972
- const conflict = await session.run(`MATCH (other:\`${label}\`)
1973
- WHERE elementId(other) <> $eid
1974
- AND NOT other:Trashed
1975
- AND other.\`${k}\` = $val
1976
- RETURN elementId(other) AS otherId LIMIT 1`, { eid: elementId, val: v });
1977
- if (conflict.records.length > 0) {
1978
- const otherId = conflict.records[0].get("otherId");
1979
- throw new Error(`restoreNode: cannot restore ${label} elementId=${elementId} \u2014 active node elementId=${otherId} already holds ${k}=${JSON.stringify(v)}`);
1980
- }
1981
- }
1982
- }
1983
- const setClauses = Object.keys(originalKeys).map((k) => `n.\`${k}\` = $val_${k}`).join(", ");
1984
- const setSuffix = setClauses ? `, ${setClauses}` : "";
1985
- const setParams = { eid: elementId };
1986
- for (const [k, v] of Object.entries(originalKeys))
1987
- setParams[`val_${k}`] = v;
1988
- const isConversation = baseLabels.includes("Conversation");
1989
- let cascadedMessageCount = 0;
1990
- await session.executeWrite(async (tx) => {
1991
- await tx.run(`MATCH (n:Trashed) WHERE elementId(n) = $eid
1992
- REMOVE n:Trashed, n.trashedAt, n.trashedBy, n.trashReason, n._trashedKeys
1993
- SET n.restoredAt = datetime()${setSuffix}`, setParams);
1994
- if (isConversation) {
1995
- const collected = await tx.run(`MATCH (c) WHERE elementId(c) = $eid
1996
- MATCH (m:Trashed:Message)-[:PART_OF]->(c)
1997
- WHERE m.trashedBy ENDS WITH ':cascade-from-conversation'
1998
- RETURN elementId(m) AS meid, m._trashedKeys AS keysJson`, { eid: elementId });
1999
- for (const rec of collected.records) {
2000
- const meid = rec.get("meid");
2001
- const keysJson2 = rec.get("keysJson");
2002
- const keys = keysJson2 ? JSON.parse(keysJson2) : {};
2003
- const setClause = Object.keys(keys).length > 0 ? ", " + Object.keys(keys).map((k) => `m.\`${k}\` = $val_${k}`).join(", ") : "";
2004
- const msgParams = { meid };
2005
- for (const [k, v] of Object.entries(keys))
2006
- msgParams[`val_${k}`] = v;
2007
- await tx.run(`MATCH (m) WHERE elementId(m) = $meid
2008
- REMOVE m:Trashed, m.trashedAt, m.trashedBy, m.trashReason, m._trashedKeys
2009
- SET m.restoredAt = datetime()${setClause}`, msgParams);
2010
- }
2011
- cascadedMessageCount = collected.records.length;
2012
- }
2013
- });
2014
- process.stderr.write(`[trash:restored] accountId=${accountId} elementId=${elementId} labels=${baseLabels.join(",")}
2015
- `);
2016
- if (isConversation) {
2017
- process.stderr.write(`[trash:cascade-restored] accountId=${accountId} conversationElementId=${elementId} messageCount=${cascadedMessageCount}
2018
- `);
2019
- }
2020
- return {
2021
- restored: true,
2022
- nodeId: elementId,
2023
- labels: baseLabels,
2024
- restoredKeys: originalKeys
2025
- };
2026
- }
2027
- async function emptyTrash(params) {
2028
- const t0 = Date.now();
2029
- const { session, accountId, graceDays = 30, dryRun = false, labels: labelFilter, onEmpty } = params;
2030
- const cutoff = new Date(Date.now() - graceDays * 24 * 60 * 60 * 1e3).toISOString();
2031
- const labelClause = labelFilter && labelFilter.length > 0 ? `AND ANY(l IN labels(n) WHERE l IN $labelFilter)` : "";
2032
- const candidatesResult = await session.run(`MATCH (n:Trashed)
2033
- WHERE n.trashedAt < datetime($cutoff)
2034
- ${labelClause}
2035
- RETURN elementId(n) AS eid,
2036
- labels(n) AS labels,
2037
- toString(n.trashedAt) AS trashedAt,
2038
- n.trashedBy AS trashedBy,
2039
- n._trashedKeys AS keysJson
2040
- ORDER BY n.trashedAt ASC`, { cutoff, ...labelFilter ? { labelFilter } : {} });
2041
- const candidates = candidatesResult.records.map((r) => {
2042
- const keysJson = r.get("keysJson");
2043
- return {
2044
- elementId: r.get("eid"),
2045
- labels: r.get("labels").filter((l) => l !== "Trashed"),
2046
- trashedAt: String(r.get("trashedAt")),
2047
- trashedBy: r.get("trashedBy") ?? null,
2048
- trashedKeys: keysJson ? JSON.parse(keysJson) : {}
2049
- };
2050
- });
2051
- process.stderr.write(`[trash:empty-run] accountId=${accountId} graceDays=${graceDays} dryRun=${dryRun} candidates=${candidates.length}
2052
- `);
2053
- if (dryRun || candidates.length === 0) {
2054
- process.stderr.write(`[graph:trash:summary] accountId=${accountId} trashedNow=0 emptiedThisRun=0 graceDays=${graceDays} dryRun=${dryRun} elapsedMs=${Date.now() - t0}
2055
- `);
2056
- return { graceDays, dryRun, candidates, emptied: 0 };
2057
- }
2058
- let emptied = 0;
2059
- for (const c of candidates) {
2060
- if (onEmpty) {
2061
- try {
2062
- await onEmpty(c);
2063
- } catch (err) {
2064
- const id83 = c.elementId.slice(0, 8);
2065
- const message = err instanceof Error ? err.message : String(err);
2066
- process.stderr.write(`[trash:empty-run] reason=onEmpty-failed elementId=${id83} labels=${c.labels.join(",")} message=${message}
2067
- `);
2068
- continue;
2069
- }
2070
- }
2071
- await session.run(`MATCH (n) WHERE elementId(n) = $eid DETACH DELETE n`, { eid: c.elementId });
2072
- const ageDays = Math.floor((Date.now() - new Date(c.trashedAt).getTime()) / (24 * 60 * 60 * 1e3));
2073
- process.stderr.write(`[trash:emptied] accountId=${accountId} elementId=${c.elementId} labels=${c.labels.join(",")} trashedAt=${c.trashedAt} ageDays=${ageDays}
2074
- `);
2075
- emptied++;
2076
- }
2077
- process.stderr.write(`[graph:trash:summary] accountId=${accountId} trashedNow=0 emptiedThisRun=${emptied} graceDays=${graceDays} dryRun=${dryRun} elapsedMs=${Date.now() - t0}
2078
- `);
2079
- return { graceDays, dryRun, candidates, emptied };
2080
- }
2081
- function notTrashed2(alias) {
2082
- return `(NOT \`${alias}\`:Trashed AND \`${alias}\`.deletedAt IS NULL)`;
2083
- }
2084
- function uniqueKeysForLabels(labels) {
2085
- const out = /* @__PURE__ */ new Set();
2086
- for (const l of labels)
2087
- for (const k of UNIQUE_KEYS_BY_LABEL2[l] ?? [])
2088
- out.add(k);
2089
- return [...out];
2090
- }
2091
- exports.TRASH_METADATA_PROPS = TRASH_PROP_NAMES;
2092
- }
2093
- });
2094
-
2095
2095
  // ../lib/graph-style/dist/index.js
2096
2096
  var require_dist9 = __commonJS({
2097
2097
  "../lib/graph-style/dist/index.js"(exports) {
@@ -7452,7 +7452,7 @@ function createScheduleInjectRoutes(deps) {
7452
7452
  }
7453
7453
 
7454
7454
  // server/index.ts
7455
- var import_dist18 = __toESM(require_dist3(), 1);
7455
+ var import_dist19 = __toESM(require_dist3(), 1);
7456
7456
 
7457
7457
  // app/lib/whatsapp/avatar-store.ts
7458
7458
  import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync4, readdirSync as readdirSync6, statSync as statSync8, rmSync as rmSync3 } from "fs";
@@ -19176,6 +19176,44 @@ async function downloadTelegramMedia(input) {
19176
19176
  return out;
19177
19177
  }
19178
19178
 
19179
+ // app/lib/telegram/resolve-sender-name.ts
19180
+ var import_dist6 = __toESM(require_dist5(), 1);
19181
+ function composeName(row) {
19182
+ return [row.givenName ?? "", row.familyName ?? ""].join(" ").trim().replace(/\s+/g, " ");
19183
+ }
19184
+ function classifySenderName(rows) {
19185
+ if (rows.length > 1) return { kind: "ambiguous", count: rows.length };
19186
+ const first = rows[0];
19187
+ if (!first) return { kind: "none" };
19188
+ const display = composeName(first);
19189
+ return display.length > 0 ? { kind: "resolved", display } : { kind: "none" };
19190
+ }
19191
+ async function resolveTelegramSenderName(params) {
19192
+ if (!/^\d+$/.test(params.senderId)) return { verdict: { kind: "none" } };
19193
+ const telegramUserId = Number(params.senderId);
19194
+ if (!Number.isSafeInteger(telegramUserId)) return { verdict: { kind: "none" } };
19195
+ let session;
19196
+ try {
19197
+ session = getSession();
19198
+ const result = await session.run(
19199
+ `MATCH (p:Person {accountId: $accountId})
19200
+ WHERE p.telegramUserId = $telegramUserId AND ${(0, import_dist6.notTrashed)("p")}
19201
+ RETURN p.givenName AS givenName, p.familyName AS familyName`,
19202
+ { accountId: params.accountId, telegramUserId },
19203
+ { timeout: 2e3 }
19204
+ );
19205
+ const rows = result.records.map((r) => ({
19206
+ givenName: r.get("givenName") ?? null,
19207
+ familyName: r.get("familyName") ?? null
19208
+ }));
19209
+ return { verdict: classifySenderName(rows) };
19210
+ } catch (err) {
19211
+ return { verdict: { kind: "none" }, error: err instanceof Error ? err.message : String(err) };
19212
+ } finally {
19213
+ await session?.close();
19214
+ }
19215
+ }
19216
+
19179
19217
  // app/lib/telegram/inbound/servable.ts
19180
19218
  import { readFile as readFile6 } from "fs/promises";
19181
19219
  import { basename as basename12 } from "path";
@@ -19345,7 +19383,7 @@ function runTelegramNotifyReconcile(now) {
19345
19383
  }
19346
19384
 
19347
19385
  // server/routes/telegram.ts
19348
- var import_dist8 = __toESM(require_dist5(), 1);
19386
+ var import_dist9 = __toESM(require_dist6(), 1);
19349
19387
 
19350
19388
  // app/lib/telegram/outbound/answer-callback.ts
19351
19389
  async function answerTelegramCallback(botToken, callbackQueryId, text) {
@@ -19439,7 +19477,7 @@ function runTelegramNotifyPublishCensus(now) {
19439
19477
  }
19440
19478
 
19441
19479
  // ../lib/dispatch-write/src/lifecycle.ts
19442
- var import_dist6 = __toESM(require_dist6());
19480
+ var import_dist7 = __toESM(require_dist7());
19443
19481
  function checkTransition(kind, from, to, cfg) {
19444
19482
  const edges = kind === "job" ? cfg.statuses.jobTransitions : cfg.statuses.visitTransitions;
19445
19483
  const legal = edges.some(([f, t]) => f === from && t === to);
@@ -19469,7 +19507,7 @@ function firstMissingRequiredField(toStatus, cfg, state) {
19469
19507
  const required = cfg.records.requiredBeforeTerminal[toStatus];
19470
19508
  if (!required) return null;
19471
19509
  for (const field2 of required) {
19472
- if (!import_dist6.RECORDABLE_FIELDS.includes(field2)) continue;
19510
+ if (!import_dist7.RECORDABLE_FIELDS.includes(field2)) continue;
19473
19511
  if (!fieldSatisfied(field2, state)) {
19474
19512
  return field2;
19475
19513
  }
@@ -19481,12 +19519,12 @@ function formatTransitionRefused(p) {
19481
19519
  }
19482
19520
 
19483
19521
  // ../lib/dispatch-write/src/write.ts
19484
- var import_dist7 = __toESM(require_dist6());
19522
+ var import_dist8 = __toESM(require_dist7());
19485
19523
  function refuse(reason, message) {
19486
19524
  return { ok: false, reason, message };
19487
19525
  }
19488
19526
  async function visitRecord(p) {
19489
- const visit = await (0, import_dist7.readVisit)(p.session, p.accountId, p.visitId);
19527
+ const visit = await (0, import_dist8.readVisit)(p.session, p.accountId, p.visitId);
19490
19528
  if (!visit) {
19491
19529
  return refuse(
19492
19530
  "not-found",
@@ -19583,7 +19621,7 @@ async function visitRecord(p) {
19583
19621
  arrivalParams
19584
19622
  );
19585
19623
  }
19586
- const state = await (0, import_dist7.readVisitRecordState)(p.session, p.accountId, p.visitId);
19624
+ const state = await (0, import_dist8.readVisitRecordState)(p.session, p.accountId, p.visitId);
19587
19625
  p.emit(
19588
19626
  `[dispatch] op=visit-record visitId=${p.visitId} notes=${state.notes} media=${state.media} parts=${state.parts} checklist=${state.checklistDone}/${state.checklistTotal} signatures=${state.signatures}`
19589
19627
  );
@@ -19596,7 +19634,7 @@ async function visitRecord(p) {
19596
19634
  `[dispatch] op=arrival-observed visitId=${p.visitId} distanceM=${p.arrivedObservedDistanceM ?? "none"} observedAt=${p.arrivedObservedAt} pressedAt=${pressedAt ?? "none"} deltaS=${deltaS ?? "none"}`
19597
19635
  );
19598
19636
  }
19599
- const after = await (0, import_dist7.readVisit)(p.session, p.accountId, p.visitId);
19637
+ const after = await (0, import_dist8.readVisit)(p.session, p.accountId, p.visitId);
19600
19638
  return {
19601
19639
  ok: true,
19602
19640
  value: {
@@ -19611,7 +19649,7 @@ async function visitRecord(p) {
19611
19649
  };
19612
19650
  }
19613
19651
  async function visitStatusSet(p) {
19614
- const visit = await (0, import_dist7.readVisit)(p.session, p.accountId, p.visitId);
19652
+ const visit = await (0, import_dist8.readVisit)(p.session, p.accountId, p.visitId);
19615
19653
  if (!visit) {
19616
19654
  return refuse(
19617
19655
  "not-found",
@@ -19651,7 +19689,7 @@ async function visitStatusSet(p) {
19651
19689
  `This account allows no move from "${visit.status}" to "${p.to}". From "${visit.status}" it allows: ${legalNext.join(", ") || "nothing"}.`
19652
19690
  );
19653
19691
  }
19654
- const state = await (0, import_dist7.readVisitRecordState)(p.session, p.accountId, p.visitId);
19692
+ const state = await (0, import_dist8.readVisitRecordState)(p.session, p.accountId, p.visitId);
19655
19693
  const missing = firstMissingRequiredField(p.to, p.cfg, state);
19656
19694
  if (missing) {
19657
19695
  p.emit(
@@ -19680,7 +19718,7 @@ async function visitStatusSet(p) {
19680
19718
  );
19681
19719
  let jobClosed = null;
19682
19720
  if (terminal && visit.jobId) {
19683
- const siblings = await (0, import_dist7.readVisitsForJob)(p.session, p.accountId, visit.jobId);
19721
+ const siblings = await (0, import_dist8.readVisitsForJob)(p.session, p.accountId, visit.jobId);
19684
19722
  const allTerminal = siblings.every(
19685
19723
  (v) => v.visitId === p.visitId || isTerminal("visit", v.status, p.cfg)
19686
19724
  );
@@ -20410,6 +20448,18 @@ app11.post("/", async (c) => {
20410
20448
  console.error(`${TAG36} op=ignore botId=${botId} reason=bot-unbound`);
20411
20449
  return c.json({ ok: true }, 200);
20412
20450
  }
20451
+ const decisionSenderId = "senderId" in decision ? decision.senderId : void 0;
20452
+ const decisionSenderDisplay = "senderDisplay" in decision ? decision.senderDisplay : void 0;
20453
+ let provenanceDisplay = decisionSenderDisplay;
20454
+ if (entry3.role === "admin" && typeof decisionSenderId === "string" && decisionSenderId.length > 0) {
20455
+ const startedMs = Date.now();
20456
+ const { verdict, error } = await resolveTelegramSenderName({ accountId, senderId: decisionSenderId });
20457
+ const source = verdict.kind === "resolved" ? "contact" : typeof decisionSenderDisplay === "string" && decisionSenderDisplay.length > 0 ? "profile" : "id";
20458
+ if (verdict.kind === "resolved") provenanceDisplay = verdict.display;
20459
+ console.error(
20460
+ `[telegram:reframe] op=sender-name senderId=${decisionSenderId} accountId=${accountId.slice(0, 8)} source=${source} resolvedMs=${Date.now() - startedMs}` + (verdict.kind === "ambiguous" ? ` reason=ambiguous count=${verdict.count}` : "") + (error ? ` error=${error}` : "")
20461
+ );
20462
+ }
20413
20463
  if (decision.kind === "chat-member") {
20414
20464
  console.error(
20415
20465
  `${TAG36} op=chat-member-group botId=${botId} chatId=${decision.chatId} userId=${decision.userId || "none"} status=${logValue2(decision.status)}`
@@ -20441,7 +20491,7 @@ app11.post("/", async (c) => {
20441
20491
  const cbAt = (/* @__PURE__ */ new Date()).toISOString();
20442
20492
  let cbBody = `[button: ${decision.data ?? "no-data"}]`;
20443
20493
  if (decision.data !== null) {
20444
- const label = (0, import_dist8.readButtonLabel)(accountDir, (0, import_dist8.buttonLabelKey)(botId, decision.chatId, decision.data));
20494
+ const label = (0, import_dist9.readButtonLabel)(accountDir, (0, import_dist9.buttonLabelKey)(botId, decision.chatId, decision.data));
20445
20495
  if (label !== null) {
20446
20496
  cbBody = label;
20447
20497
  } else {
@@ -20522,7 +20572,7 @@ app11.post("/", async (c) => {
20522
20572
  specialist: entry3.role === "specialist" ? entry3.specialist : null,
20523
20573
  active: cbActive,
20524
20574
  senderId: decision.senderId,
20525
- senderDisplay: decision.senderDisplay,
20575
+ senderDisplay: provenanceDisplay,
20526
20576
  chatId: decision.chatId,
20527
20577
  // The same body the store row above carries, so the operator's reader and
20528
20578
  // the agent's turn say the same thing about one press.
@@ -20575,7 +20625,7 @@ app11.post("/", async (c) => {
20575
20625
  specialist: entry3.role === "specialist" ? entry3.specialist : null,
20576
20626
  active: pollActive,
20577
20627
  senderId: decision.senderId,
20578
- senderDisplay: decision.senderDisplay,
20628
+ senderDisplay: provenanceDisplay,
20579
20629
  chatId: decision.chatId,
20580
20630
  text: pollBody,
20581
20631
  channelKey: pollKey,
@@ -20627,7 +20677,7 @@ app11.post("/", async (c) => {
20627
20677
  specialist: entry3.role === "specialist" ? entry3.specialist : null,
20628
20678
  active: rActive,
20629
20679
  senderId: decision.senderId,
20630
- senderDisplay: decision.senderDisplay,
20680
+ senderDisplay: provenanceDisplay,
20631
20681
  chatId: decision.chatId,
20632
20682
  text: rBody,
20633
20683
  channelKey: rKey,
@@ -20692,7 +20742,7 @@ app11.post("/", async (c) => {
20692
20742
  specialist: entry3.role === "specialist" ? entry3.specialist : null,
20693
20743
  active: sActive,
20694
20744
  senderId: decision.senderId,
20695
- senderDisplay: decision.senderDisplay,
20745
+ senderDisplay: provenanceDisplay,
20696
20746
  chatId: decision.chatId,
20697
20747
  text: sBody,
20698
20748
  channelKey: sKey,
@@ -21234,7 +21284,8 @@ app11.post("/", async (c) => {
21234
21284
  agentSlug,
21235
21285
  senderId,
21236
21286
  // Task 2616 — the name beside the id on the turn's provenance line.
21237
- senderDisplay: decision.senderDisplay,
21287
+ // Task 2705 — the account's own contact name when one holds this id.
21288
+ senderDisplay: provenanceDisplay,
21238
21289
  // Task 2616 — a group is ONE conversation. The gateway's hub key, reply
21239
21290
  // map, spawn guard and session id all take this, so five members of one
21240
21291
  // room reach one channel server rather than opening five sessions whose
@@ -25773,18 +25824,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
25773
25824
  ]);
25774
25825
  var app27 = new Hono();
25775
25826
  app27.post("/", async (c) => {
25776
- const TAG77 = "[admin:events]";
25827
+ const TAG79 = "[admin:events]";
25777
25828
  let body;
25778
25829
  try {
25779
25830
  body = await c.req.json();
25780
25831
  } catch (err) {
25781
25832
  const detail = err instanceof Error ? err.message : String(err);
25782
- console.error(`${TAG77} reject reason=body-not-json detail=${detail}`);
25833
+ console.error(`${TAG79} reject reason=body-not-json detail=${detail}`);
25783
25834
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
25784
25835
  }
25785
25836
  const event = typeof body.event === "string" ? body.event : "";
25786
25837
  if (!ALLOWED_EVENTS.has(event)) {
25787
- console.error(`${TAG77} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
25838
+ console.error(`${TAG79} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
25788
25839
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
25789
25840
  }
25790
25841
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -26740,13 +26791,13 @@ function buildZip(entries2) {
26740
26791
  }
26741
26792
 
26742
26793
  // server/lib/account-root-groups.ts
26743
- var import_dist9 = __toESM(require_dist7(), 1);
26794
+ var import_dist10 = __toESM(require_dist8(), 1);
26744
26795
  function classifyAccountRoot(schemaMd, rootEntries) {
26745
- const regions = (0, import_dist9.parseSchemaRegions)(schemaMd);
26796
+ const regions = (0, import_dist10.parseSchemaRegions)(schemaMd);
26746
26797
  if (!regions.parsed) {
26747
26798
  return { home: [], system: [...rootEntries], unknown: [], parsed: false, reason: regions.reason };
26748
26799
  }
26749
- const homeOrder = [...regions.ontologyRoots, ...import_dist9.HOME_FIXED].filter((d, i, a) => a.indexOf(d) === i);
26800
+ const homeOrder = [...regions.ontologyRoots, ...import_dist10.HOME_FIXED].filter((d, i, a) => a.indexOf(d) === i);
26750
26801
  const homeSet = new Set(homeOrder);
26751
26802
  const present = new Set(rootEntries);
26752
26803
  const home = homeOrder.filter((d) => present.has(d));
@@ -27889,7 +27940,7 @@ app28.post("/rename", requireAdminSession, async (c) => {
27889
27940
  var files_default = app28;
27890
27941
 
27891
27942
  // ../lib/graph-search/src/index.ts
27892
- var import_dist10 = __toESM(require_dist8());
27943
+ var import_dist11 = __toESM(require_dist5());
27893
27944
  import { int } from "neo4j-driver";
27894
27945
 
27895
27946
  // ../lib/graph-search/src/rrf-fusion.ts
@@ -28139,7 +28190,7 @@ async function bm25Only(session, params) {
28139
28190
  ${scopeClause}
28140
28191
  ${agentClause}
28141
28192
  ${labelClause}
28142
- AND ${(0, import_dist10.notTrashed)("node")}
28193
+ AND ${(0, import_dist11.notTrashed)("node")}
28143
28194
  ${kwClause}
28144
28195
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
28145
28196
  ORDER BY score DESC
@@ -28301,7 +28352,7 @@ async function hybrid(session, embed2, params) {
28301
28352
  WHERE node.accountId = $accountId
28302
28353
  ${scopeClause}
28303
28354
  ${agentClause}
28304
- AND ${(0, import_dist10.notTrashed)("node")}
28355
+ AND ${(0, import_dist11.notTrashed)("node")}
28305
28356
  ${keywordClause}
28306
28357
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
28307
28358
  ORDER BY score DESC
@@ -28400,7 +28451,7 @@ async function hybrid(session, embed2, params) {
28400
28451
  const propResult = await session.run(
28401
28452
  `MATCH (node)
28402
28453
  WHERE node.accountId = $accountId
28403
- AND ${(0, import_dist10.notTrashed)("node")}
28454
+ AND ${(0, import_dist11.notTrashed)("node")}
28404
28455
  AND node.keywords IS NOT NULL
28405
28456
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
28406
28457
  ${propScope.clause}
@@ -28452,7 +28503,7 @@ async function hybrid(session, embed2, params) {
28452
28503
  const propResult = await session.run(
28453
28504
  `MATCH (node)
28454
28505
  WHERE node.accountId = $accountId
28455
- AND ${(0, import_dist10.notTrashed)("node")}
28506
+ AND ${(0, import_dist11.notTrashed)("node")}
28456
28507
  AND node.keywords IS NOT NULL
28457
28508
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
28458
28509
  ${propScope.clause}
@@ -28559,7 +28610,7 @@ async function hybrid(session, embed2, params) {
28559
28610
  `UNWIND $nodeIds AS nid
28560
28611
  MATCH (n)-[r]-(related)
28561
28612
  WHERE elementId(n) = nid
28562
- AND ${(0, import_dist10.notTrashed)("related")}
28613
+ AND ${(0, import_dist11.notTrashed)("related")}
28563
28614
  ${expandScopeClause}
28564
28615
  ${expandAgentClause}
28565
28616
  WITH nid, n, r, related
@@ -28787,8 +28838,8 @@ var graph_search_default = app29;
28787
28838
  import neo4j2 from "neo4j-driver";
28788
28839
 
28789
28840
  // app/lib/graph-labels.ts
28790
- var import_dist11 = __toESM(require_dist9(), 1);
28791
28841
  var import_dist12 = __toESM(require_dist9(), 1);
28842
+ var import_dist13 = __toESM(require_dist9(), 1);
28792
28843
  var HIDDEN_BY_DEFAULT_LABELS = Object.freeze(
28793
28844
  /* @__PURE__ */ new Set(["Chunk", "GraphPreference"])
28794
28845
  );
@@ -28872,14 +28923,14 @@ var EXCLUDED_EDGE_TYPES = Object.freeze(
28872
28923
  ])
28873
28924
  );
28874
28925
  function isKnownLabel(label) {
28875
- return Object.prototype.hasOwnProperty.call(import_dist12.GRAPH_LABEL_COLOURS, label);
28926
+ return Object.prototype.hasOwnProperty.call(import_dist13.GRAPH_LABEL_COLOURS, label);
28876
28927
  }
28877
28928
  function isHiddenByDefault(label) {
28878
28929
  return HIDDEN_BY_DEFAULT_LABELS.has(label);
28879
28930
  }
28880
28931
 
28881
28932
  // server/lib/top-level-labels.ts
28882
- var import_dist13 = __toESM(require_dist9(), 1);
28933
+ var import_dist14 = __toESM(require_dist9(), 1);
28883
28934
  import { readdirSync as readdirSync26, readFileSync as readFileSync41 } from "fs";
28884
28935
  import { join as join51, resolve as resolve33 } from "path";
28885
28936
  var STATIC_TOP_LEVEL_LABELS = Object.freeze(
@@ -29016,7 +29067,7 @@ function getTopLevelLabelAllowlist(opts = {}) {
29016
29067
  const referencesDir = opts.referencesDir ?? resolveReferencesDir();
29017
29068
  const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
29018
29069
  const excluded = [];
29019
- for (const label of import_dist13.ADDITIONAL_BASE_LABELS) {
29070
+ for (const label of import_dist14.ADDITIONAL_BASE_LABELS) {
29020
29071
  if (derived.delete(label)) excluded.push(label);
29021
29072
  }
29022
29073
  const derivedCount = derived.size;
@@ -37197,7 +37248,7 @@ async function runConversationAudit() {
37197
37248
  }
37198
37249
 
37199
37250
  // app/lib/graph-health.ts
37200
- var import_dist15 = __toESM(require_dist10(), 1);
37251
+ var import_dist16 = __toESM(require_dist10(), 1);
37201
37252
  var HOUR_MS2 = 60 * 60 * 1e3;
37202
37253
  function renderLabelTop(rows) {
37203
37254
  return rows.map((b) => {
@@ -37242,7 +37293,7 @@ async function runGraphHealthTick() {
37242
37293
  console.error(
37243
37294
  `[graph-health] userprofile-multi accounts=${upAccounts} top=${upTop.length > 0 ? upTop.join(",") : "none"}`
37244
37295
  );
37245
- const indexed = [...import_dist15.VECTOR_INDEXED_LABELS];
37296
+ const indexed = [...import_dist16.VECTOR_INDEXED_LABELS];
37246
37297
  const embCount = await session.run(
37247
37298
  `MATCH (n) WHERE n.embedding IS NULL AND any(l IN labels(n) WHERE l IN $indexed)
37248
37299
  RETURN count(n) AS total`,
@@ -37316,7 +37367,7 @@ function startGraphHealthTimer() {
37316
37367
  // app/lib/shared-folder-census.ts
37317
37368
  import { existsSync as existsSync54, statSync as statSync29, readdirSync as readdirSync32 } from "fs";
37318
37369
  import { join as join65 } from "path";
37319
- var import_dist16 = __toESM(require_dist(), 1);
37370
+ var import_dist17 = __toESM(require_dist(), 1);
37320
37371
  var TAG66 = "[shared-census]";
37321
37372
  var WIRED_SURFACES = 3;
37322
37373
  function countFiles(dir) {
@@ -37334,7 +37385,7 @@ function countFiles(dir) {
37334
37385
  return n;
37335
37386
  }
37336
37387
  function runSharedFolderCensus(dataRoot = DATA_ROOT) {
37337
- const root = (0, import_dist16.sharedRoot)(dataRoot);
37388
+ const root = (0, import_dist17.sharedRoot)(dataRoot);
37338
37389
  const exists = existsSync54(root);
37339
37390
  let isDir = false;
37340
37391
  if (exists) {
@@ -42447,11 +42498,11 @@ async function firePublicSessionEndReview(input) {
42447
42498
  }
42448
42499
 
42449
42500
  // app/lib/whatsapp/inbound/resolve-client-graph-owner.ts
42450
- var import_dist17 = __toESM(require_dist3(), 1);
42501
+ var import_dist18 = __toESM(require_dist3(), 1);
42451
42502
  async function resolveClientOwnerUserId(accountId, deps = {}) {
42452
42503
  const listAccounts = deps.listAccounts ?? listValidAccounts;
42453
42504
  const getSession3 = deps.getSession ?? getSession;
42454
- const resolveOwner2 = deps.resolveOwner ?? import_dist17.resolveOwnerUserId;
42505
+ const resolveOwner2 = deps.resolveOwner ?? import_dist18.resolveOwnerUserId;
42455
42506
  const role = listAccounts().find((a) => a.accountId === accountId)?.config.role;
42456
42507
  if (role !== "client") return null;
42457
42508
  const session = getSession3();
@@ -42779,6 +42830,81 @@ async function runTelegramChannelCensus(accounts, deps) {
42779
42830
  return [buildChannelCensusLine(counts)];
42780
42831
  }
42781
42832
 
42833
+ // server/telegram-graph-duplicate-census.ts
42834
+ var TAG77 = "[telegram-audit]";
42835
+ var DUPLICATE_QUERY = `
42836
+ MATCH (m:Message)
42837
+ WHERE m.accountId = $accountId AND m.channel = 'telegram'
42838
+ RETURN count(m) AS messages, collect(DISTINCT m.createdBySession) AS sessions
42839
+ `;
42840
+ function asCount(value) {
42841
+ if (typeof value === "number") return value;
42842
+ if (value && typeof value === "object" && "low" in value) {
42843
+ const { low } = value;
42844
+ if (typeof low === "number") return low;
42845
+ }
42846
+ return 0;
42847
+ }
42848
+ function asSessions(value) {
42849
+ return value.filter((s) => typeof s === "string" && s.length > 0).sort();
42850
+ }
42851
+ async function runTelegramGraphDuplicateCensus(accountIds, deps) {
42852
+ const lines = [];
42853
+ for (const accountId of accountIds) {
42854
+ try {
42855
+ const rows = await deps.read(DUPLICATE_QUERY, { accountId });
42856
+ const row = rows[0] ?? { messages: 0, sessions: [] };
42857
+ const messages = asCount(row.messages);
42858
+ const sessions4 = asSessions(Array.isArray(row.sessions) ? row.sessions : []);
42859
+ const named = sessions4.length > 0 ? ` ids=${sessions4.join(",")}` : "";
42860
+ lines.push(
42861
+ `${TAG77} op=graph-duplicate accountId=${accountId} messages=${messages} sessions=${sessions4.length}${named}`
42862
+ );
42863
+ } catch (err) {
42864
+ const reason = err instanceof Error ? err.message : String(err);
42865
+ lines.push(
42866
+ `${TAG77} FAIL op=graph-duplicate accountId=${accountId} reason=${reason.slice(0, 100)}`
42867
+ );
42868
+ }
42869
+ }
42870
+ return lines;
42871
+ }
42872
+
42873
+ // server/telegram-identity-census.ts
42874
+ var TAG78 = "[telegram-audit]";
42875
+ function buildIdentityCensusLine(c) {
42876
+ return `${TAG78} op=identity-census bots=${c.bots} ids=${c.ids} bound=${c.bound} unbound=${c.unbound} ambiguous=${c.ambiguous}`;
42877
+ }
42878
+ async function runTelegramIdentityCensus(accounts, deps) {
42879
+ const counts = { bots: 0, ids: 0, bound: 0, unbound: 0, ambiguous: 0 };
42880
+ for (const account of accounts) {
42881
+ const adminEntries = listBotEntries(account.telegram).filter((e) => e.role === "admin");
42882
+ if (adminEntries.length === 0) continue;
42883
+ counts.bots += adminEntries.length;
42884
+ const ids = adminEntries.flatMap((e) => e.adminUsers ?? []);
42885
+ counts.ids += ids.length;
42886
+ if (ids.length === 0) continue;
42887
+ let found;
42888
+ try {
42889
+ found = await deps.boundIds(account.accountId, [...new Set(ids)]);
42890
+ } catch {
42891
+ counts.unbound += ids.length;
42892
+ continue;
42893
+ }
42894
+ for (const id of ids) {
42895
+ const n = found.get(id) ?? 0;
42896
+ if (n === 1) counts.bound += 1;
42897
+ else if (n > 1) counts.ambiguous += 1;
42898
+ else counts.unbound += 1;
42899
+ }
42900
+ }
42901
+ if (counts.bots === 0) return [];
42902
+ return [buildIdentityCensusLine(counts)];
42903
+ }
42904
+
42905
+ // server/index.ts
42906
+ var import_dist20 = __toESM(require_dist5(), 1);
42907
+
42782
42908
  // app/lib/telegram/gateway/origin-target.ts
42783
42909
  function answeringOriginTarget(send, key2, noteAnswered3) {
42784
42910
  if (!send) return null;
@@ -43452,8 +43578,8 @@ var webchatFileFollowers = /* @__PURE__ */ new Map();
43452
43578
  async function fetchAccountStandingRules(accountId) {
43453
43579
  const session = getSession();
43454
43580
  try {
43455
- const res = await (0, import_dist18.resolveActiveRules)(session, accountId);
43456
- return { block: (0, import_dist18.formatStandingRulesBlock)(res.rules), ownerUserId: res.ownerUserId, source: res.source };
43581
+ const res = await (0, import_dist19.resolveActiveRules)(session, accountId);
43582
+ return { block: (0, import_dist19.formatStandingRulesBlock)(res.rules), ownerUserId: res.ownerUserId, source: res.source };
43457
43583
  } catch (err) {
43458
43584
  console.error(
43459
43585
  `[preference-inject] op=fetch-failed accountId=${accountId} error=${err instanceof Error ? err.message : String(err)}`
@@ -45082,6 +45208,31 @@ registerLoop({
45082
45208
  `[telegram-native] op=telegram-spawn-census-rejected detail=${err instanceof Error ? err.message : String(err)}`
45083
45209
  );
45084
45210
  }
45211
+ try {
45212
+ for (const line of await runTelegramIdentityCensus(accounts, {
45213
+ boundIds: async (accountId, ids) => {
45214
+ const session = getSession();
45215
+ try {
45216
+ const result = await session.run(
45217
+ `MATCH (p:Person {accountId: $accountId})
45218
+ WHERE p.telegramUserId IN $ids AND ${(0, import_dist20.notTrashed)("p")}
45219
+ RETURN p.telegramUserId AS id, count(*) AS n`,
45220
+ { accountId, ids },
45221
+ { timeout: 5e3 }
45222
+ );
45223
+ return new Map(result.records.map((r) => [Number(r.get("id")), Number(r.get("n"))]));
45224
+ } finally {
45225
+ await session.close();
45226
+ }
45227
+ }
45228
+ })) {
45229
+ console.error(line);
45230
+ }
45231
+ } catch (err) {
45232
+ console.error(
45233
+ `[telegram-native] op=identity-census-rejected detail=${err instanceof Error ? err.message : String(err)}`
45234
+ );
45235
+ }
45085
45236
  };
45086
45237
  registerLoop({
45087
45238
  name: "telegram-audit",
@@ -45229,6 +45380,30 @@ registerLoop({
45229
45380
  }
45230
45381
  }
45231
45382
  });
45383
+ registerLoop({
45384
+ name: "telegram-graph-duplicate-census",
45385
+ intervalMs: 36e5,
45386
+ firstRunDelayMs: 245e3,
45387
+ run: async () => {
45388
+ const accountIds = listValidAccounts().map((a) => a.accountId);
45389
+ for (const line of await runTelegramGraphDuplicateCensus(accountIds, {
45390
+ read: async (query, params) => {
45391
+ const session = getSession();
45392
+ try {
45393
+ const result = await session.run(query, params);
45394
+ return result.records.map((r) => ({
45395
+ messages: r.get("messages"),
45396
+ sessions: r.get("sessions")
45397
+ }));
45398
+ } finally {
45399
+ await session.close();
45400
+ }
45401
+ }
45402
+ })) {
45403
+ console.error(line);
45404
+ }
45405
+ }
45406
+ });
45232
45407
  registerLoop({
45233
45408
  name: "telegram-business-connection-census",
45234
45409
  intervalMs: 36e5,