@rubytech/create-realagent-code 0.1.582 → 0.1.584

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 (311) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/routine-templates/dist/index.d.ts +1 -1
  3. package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/routine-templates/dist/index.js +5 -1
  5. package/payload/platform/lib/routine-templates/dist/index.js.map +1 -1
  6. package/payload/platform/lib/routine-templates/src/index.ts +4 -0
  7. package/payload/platform/lib/telegram-managed-bot/dist/index.d.ts +269 -0
  8. package/payload/platform/lib/telegram-managed-bot/dist/index.d.ts.map +1 -0
  9. package/payload/platform/lib/telegram-managed-bot/dist/index.js +351 -0
  10. package/payload/platform/lib/telegram-managed-bot/dist/index.js.map +1 -0
  11. package/payload/platform/lib/telegram-managed-bot/src/__tests__/managed-bot.test.ts +251 -0
  12. package/payload/platform/lib/telegram-managed-bot/src/index.ts +529 -0
  13. package/payload/platform/lib/telegram-managed-bot/tsconfig.json +9 -0
  14. package/payload/platform/lib/telegram-managed-bot/vitest.config.ts +9 -0
  15. package/payload/platform/lib/telegram-reach/dist/index.d.ts +86 -0
  16. package/payload/platform/lib/telegram-reach/dist/index.d.ts.map +1 -0
  17. package/payload/platform/lib/telegram-reach/dist/index.js +246 -0
  18. package/payload/platform/lib/telegram-reach/dist/index.js.map +1 -0
  19. package/payload/platform/lib/telegram-reach/src/__tests__/telegram-reach.test.ts +268 -0
  20. package/payload/platform/lib/telegram-reach/src/index.ts +296 -0
  21. package/payload/platform/lib/telegram-reach/tsconfig.json +9 -0
  22. package/payload/platform/lib/telegram-reach/vitest.config.ts +9 -0
  23. package/payload/platform/package.json +2 -2
  24. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  25. package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +9 -0
  26. package/payload/platform/plugins/admin/hooks/__tests__/preference-consult-directive.test.sh +26 -0
  27. package/payload/platform/plugins/admin/hooks/fs-schema-guard.sh +20 -3
  28. package/payload/platform/plugins/admin/hooks/preference-consult-directive.sh +50 -5
  29. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +146 -8
  30. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +16 -0
  31. package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.d.ts +2 -0
  32. package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.d.ts.map +1 -0
  33. package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.js +100 -0
  34. package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.js.map +1 -0
  35. package/payload/platform/plugins/contacts/mcp/dist/index.js +11 -5
  36. package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
  37. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +5 -0
  38. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -1
  39. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +21 -4
  40. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
  41. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +5 -0
  42. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -1
  43. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +29 -1
  44. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -1
  45. package/payload/platform/plugins/contacts/mcp/vitest.config.ts +14 -0
  46. package/payload/platform/plugins/docs/references/admin-ui.md +17 -3
  47. package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +15 -0
  48. package/payload/platform/plugins/docs/references/telegram-guide.md +113 -4
  49. package/payload/platform/plugins/filesystem/PLUGIN.md +2 -2
  50. package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.d.ts +2 -0
  51. package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.d.ts.map +1 -0
  52. package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.js +108 -0
  53. package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.js.map +1 -0
  54. package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.d.ts +17 -0
  55. package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.d.ts.map +1 -0
  56. package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.js +162 -0
  57. package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.js.map +1 -0
  58. package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.d.ts +2 -0
  59. package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.d.ts.map +1 -0
  60. package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.js +116 -0
  61. package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.js.map +1 -0
  62. package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.d.ts.map +1 -1
  63. package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js +9 -0
  64. package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js.map +1 -1
  65. package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.d.ts.map +1 -1
  66. package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js +10 -0
  67. package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js.map +1 -1
  68. package/payload/platform/plugins/scheduling/PLUGIN.md +8 -2
  69. package/payload/platform/plugins/scheduling/mcp/dist/index.js +7 -2
  70. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  71. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +53 -6
  72. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js.map +1 -1
  73. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +38 -0
  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.d.ts +5 -3
  76. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
  77. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +18 -3
  78. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
  79. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +30 -0
  80. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts.map +1 -1
  81. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js +112 -39
  82. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
  83. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +14 -1
  84. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  85. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js +258 -8
  86. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js.map +1 -1
  87. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +206 -3
  88. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
  89. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +29 -21
  90. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
  91. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +94 -14
  92. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
  93. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
  94. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +29 -1
  95. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
  96. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +30 -0
  97. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
  98. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +69 -6
  99. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
  100. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +12 -0
  101. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts +36 -5
  102. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
  103. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +103 -10
  104. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
  105. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  106. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -1
  107. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  108. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  109. package/payload/platform/services/claude-session-manager/dist/http-server.js +42 -4
  110. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  111. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  112. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +19 -5
  113. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  114. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +9 -0
  115. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  116. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +5 -1
  117. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  118. package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
  119. package/payload/platform/services/telegram-channel/dist/instructions.js +13 -0
  120. package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
  121. package/payload/platform/services/telegram-channel/dist/notification.d.ts +13 -0
  122. package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
  123. package/payload/platform/services/telegram-channel/dist/notification.js +13 -2
  124. package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
  125. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +52 -0
  126. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  127. package/payload/platform/services/whatsapp-channel/dist/notification.js +64 -1
  128. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  129. package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
  130. package/payload/platform/services/whatsapp-channel/dist/server.js +14 -2
  131. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
  132. package/payload/platform/templates/account-schema/SCHEMA.md +17 -10
  133. package/payload/platform/templates/agents/admin/IDENTITY.md +5 -0
  134. package/payload/platform/templates/specialists/agents/data-manager.md +2 -2
  135. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  136. package/payload/server/{chunk-BFRB2U75.js → chunk-CV6AEMKH.js} +1 -0
  137. package/payload/server/{manager-CTVTF4YB.js → manager-FQSQSSJ3.js} +1 -1
  138. package/payload/server/public/activity.html +6 -6
  139. package/payload/server/public/agents.html +5 -5
  140. package/payload/server/public/assets/{AdminLoginScreens-AnJZfgFz.js → AdminLoginScreens-BLsDYWVi.js} +1 -1
  141. package/payload/server/public/assets/AdminLoginScreens-BLsDYWVi.js.br +0 -0
  142. package/payload/server/public/assets/AdminLoginScreens-BLsDYWVi.js.gz +0 -0
  143. package/payload/server/public/assets/{AdminShell-CEVqyQqg.js → AdminShell-BZS8jzFA.js} +1 -1
  144. package/payload/server/public/assets/AdminShell-BZS8jzFA.js.br +0 -0
  145. package/payload/server/public/assets/AdminShell-BZS8jzFA.js.gz +0 -0
  146. package/payload/server/public/assets/{activity-czUaUl8I.js → activity-DOjvoLdd.js} +1 -1
  147. package/payload/server/public/assets/activity-DOjvoLdd.js.br +0 -0
  148. package/payload/server/public/assets/activity-DOjvoLdd.js.gz +0 -0
  149. package/payload/server/public/assets/{admin-B0iRcfuk.js → admin-JrSNg29g.js} +1 -1
  150. package/payload/server/public/assets/admin-JrSNg29g.js.br +0 -0
  151. package/payload/server/public/assets/admin-JrSNg29g.js.gz +0 -0
  152. package/payload/server/public/assets/{agents-BocONCeQ.js → agents--9WMJVLC.js} +1 -1
  153. package/payload/server/public/assets/agents--9WMJVLC.js.br +0 -0
  154. package/payload/server/public/assets/agents--9WMJVLC.js.gz +0 -0
  155. package/payload/server/public/assets/{browser-Cy-rJm3t.js → browser-DiiMmTrM.js} +1 -1
  156. package/payload/server/public/assets/browser-DiiMmTrM.js.br +0 -0
  157. package/payload/server/public/assets/browser-DiiMmTrM.js.gz +0 -0
  158. package/payload/server/public/assets/{calendar-DUTKxWtd.js → calendar-CazmCzgO.js} +1 -1
  159. package/payload/server/public/assets/calendar-CazmCzgO.js.br +0 -0
  160. package/payload/server/public/assets/calendar-CazmCzgO.js.gz +0 -0
  161. package/payload/server/public/assets/chat-CB0TcyXX.js +1 -0
  162. package/payload/server/public/assets/chat-CB0TcyXX.js.br +0 -0
  163. package/payload/server/public/assets/chat-CB0TcyXX.js.gz +0 -0
  164. package/payload/server/public/assets/chevron-left-0tVo23Dh.js +1 -0
  165. package/payload/server/public/assets/chevron-left-0tVo23Dh.js.br +0 -0
  166. package/payload/server/public/assets/clock-D2cZ0sge.js +1 -0
  167. package/payload/server/public/assets/clock-D2cZ0sge.js.br +0 -0
  168. package/payload/server/public/assets/clock-D2cZ0sge.js.gz +0 -0
  169. package/payload/server/public/assets/{copy-DE9qmAs5.js → copy-C87QIN_o.js} +1 -1
  170. package/payload/server/public/assets/copy-C87QIN_o.js.br +0 -0
  171. package/payload/server/public/assets/copy-C87QIN_o.js.gz +0 -0
  172. package/payload/server/public/assets/data-CK7AMxPt.js +1 -0
  173. package/payload/server/public/assets/data-CK7AMxPt.js.br +0 -0
  174. package/payload/server/public/assets/data-CK7AMxPt.js.gz +0 -0
  175. package/payload/server/public/assets/{field-DE2tEfTo.js → field-C3kQgGWE.js} +1 -1
  176. package/payload/server/public/assets/field-C3kQgGWE.js.br +0 -0
  177. package/payload/server/public/assets/field-C3kQgGWE.js.gz +0 -0
  178. package/payload/server/public/assets/{file-text-BHfL2gqo.js → file-text-rWowl9RN.js} +1 -1
  179. package/payload/server/public/assets/file-text-rWowl9RN.js.br +0 -0
  180. package/payload/server/public/assets/file-text-rWowl9RN.js.gz +0 -0
  181. package/payload/server/public/assets/{graph-08S_BofN.js → graph-CVJKz1Uo.js} +1 -1
  182. package/payload/server/public/assets/graph-CVJKz1Uo.js.br +0 -0
  183. package/payload/server/public/assets/graph-CVJKz1Uo.js.gz +0 -0
  184. package/payload/server/public/assets/{graph-labels-C640Er5R.js → graph-labels-kneGnsHB.js} +1 -1
  185. package/payload/server/public/assets/graph-labels-kneGnsHB.js.br +0 -0
  186. package/payload/server/public/assets/graph-labels-kneGnsHB.js.gz +0 -0
  187. package/payload/server/public/assets/{jsx-runtime-FxjwOUbA.css → jsx-runtime-rMaiYjNu.css} +1 -1
  188. package/payload/server/public/assets/jsx-runtime-rMaiYjNu.css.br +0 -0
  189. package/payload/server/public/assets/{jsx-runtime-FxjwOUbA.css.gz → jsx-runtime-rMaiYjNu.css.gz} +0 -0
  190. package/payload/server/public/assets/{operator-DH5Kw3fL.js → operator-BGvB4hu4.js} +1 -1
  191. package/payload/server/public/assets/operator-BGvB4hu4.js.br +0 -0
  192. package/payload/server/public/assets/operator-BGvB4hu4.js.gz +0 -0
  193. package/payload/server/public/assets/{page-BDpa4HWT.js → page-DBQLOasI.js} +1 -1
  194. package/payload/server/public/assets/page-DBQLOasI.js.br +0 -0
  195. package/payload/server/public/assets/page-DBQLOasI.js.gz +0 -0
  196. package/payload/server/public/assets/{page-yn7ivq8O.js → page-DyVAu7tm.js} +1 -1
  197. package/payload/server/public/assets/page-DyVAu7tm.js.br +0 -0
  198. package/payload/server/public/assets/page-DyVAu7tm.js.gz +0 -0
  199. package/payload/server/public/assets/play-DgP7vl0r.js +1 -0
  200. package/payload/server/public/assets/play-DgP7vl0r.js.br +0 -0
  201. package/payload/server/public/assets/play-DgP7vl0r.js.gz +0 -0
  202. package/payload/server/public/assets/{public-D_qjqet7.js → public-BvUQR3hd.js} +1 -1
  203. package/payload/server/public/assets/public-BvUQR3hd.js.br +0 -0
  204. package/payload/server/public/assets/public-BvUQR3hd.js.gz +0 -0
  205. package/payload/server/public/assets/{rotate-ccw-Ixkq1iUA.js → rotate-ccw-Dnn7gbPh.js} +1 -1
  206. package/payload/server/public/assets/rotate-ccw-Dnn7gbPh.js.br +0 -0
  207. package/payload/server/public/assets/rotate-ccw-Dnn7gbPh.js.gz +0 -0
  208. package/payload/server/public/assets/{routines-Cxjlmcp7.js → routines-N8NmxPOZ.js} +1 -1
  209. package/payload/server/public/assets/routines-N8NmxPOZ.js.br +0 -0
  210. package/payload/server/public/assets/routines-N8NmxPOZ.js.gz +0 -0
  211. package/payload/server/public/assets/{skills-DEo9hSVX.js → skills-B2CRgO-U.js} +1 -1
  212. package/payload/server/public/assets/skills-B2CRgO-U.js.br +0 -0
  213. package/payload/server/public/assets/skills-B2CRgO-U.js.gz +0 -0
  214. package/payload/server/public/assets/{tasks-BxApOIXI.js → tasks-8QLGtlSj.js} +1 -1
  215. package/payload/server/public/assets/tasks-8QLGtlSj.js.br +0 -0
  216. package/payload/server/public/assets/tasks-8QLGtlSj.js.gz +0 -0
  217. package/payload/server/public/assets/{triangle-alert-BYzMcXv8.js → triangle-alert-el772yUQ.js} +1 -1
  218. package/payload/server/public/assets/triangle-alert-el772yUQ.js.br +0 -0
  219. package/payload/server/public/assets/triangle-alert-el772yUQ.js.gz +0 -0
  220. package/payload/server/public/assets/{useCopyFeedback-Bk2HVcjy.js → useCopyFeedback-DfNAu8hQ.js} +1 -1
  221. package/payload/server/public/assets/useCopyFeedback-DfNAu8hQ.js.br +0 -0
  222. package/payload/server/public/assets/useCopyFeedback-DfNAu8hQ.js.gz +0 -0
  223. package/payload/server/public/assets/{useMediaQuery-DEti-vAx.js → useMediaQuery-B469O83-.js} +1 -1
  224. package/payload/server/public/assets/useMediaQuery-B469O83-.js.br +0 -0
  225. package/payload/server/public/assets/{useMediaQuery-DEti-vAx.js.gz → useMediaQuery-B469O83-.js.gz} +0 -0
  226. package/payload/server/public/assets/{useVoiceRecorder-kQ92rL-f.js → useVoiceRecorder-Bb-51cJv.js} +1 -1
  227. package/payload/server/public/assets/useVoiceRecorder-Bb-51cJv.js.br +0 -0
  228. package/payload/server/public/assets/useVoiceRecorder-Bb-51cJv.js.gz +0 -0
  229. package/payload/server/public/assets/{wrench-BhLkHffv.js → wrench-Ck4phkdB.js} +1 -1
  230. package/payload/server/public/assets/wrench-Ck4phkdB.js.br +0 -0
  231. package/payload/server/public/assets/wrench-Ck4phkdB.js.gz +0 -0
  232. package/payload/server/public/browser.html +5 -5
  233. package/payload/server/public/calendar.html +8 -8
  234. package/payload/server/public/chat.html +14 -14
  235. package/payload/server/public/data.html +12 -12
  236. package/payload/server/public/field.html +3 -3
  237. package/payload/server/public/graph.html +10 -10
  238. package/payload/server/public/index.html +14 -14
  239. package/payload/server/public/operator.html +15 -15
  240. package/payload/server/public/public.html +14 -14
  241. package/payload/server/public/routines.html +8 -8
  242. package/payload/server/public/skills.html +6 -6
  243. package/payload/server/public/tasks.html +7 -7
  244. package/payload/server/server.js +3114 -1371
  245. package/payload/server/public/assets/AdminLoginScreens-AnJZfgFz.js.br +0 -0
  246. package/payload/server/public/assets/AdminLoginScreens-AnJZfgFz.js.gz +0 -0
  247. package/payload/server/public/assets/AdminShell-CEVqyQqg.js.br +0 -0
  248. package/payload/server/public/assets/AdminShell-CEVqyQqg.js.gz +0 -0
  249. package/payload/server/public/assets/activity-czUaUl8I.js.br +0 -0
  250. package/payload/server/public/assets/activity-czUaUl8I.js.gz +0 -0
  251. package/payload/server/public/assets/admin-B0iRcfuk.js.br +0 -0
  252. package/payload/server/public/assets/admin-B0iRcfuk.js.gz +0 -0
  253. package/payload/server/public/assets/agents-BocONCeQ.js.br +0 -0
  254. package/payload/server/public/assets/agents-BocONCeQ.js.gz +0 -0
  255. package/payload/server/public/assets/browser-Cy-rJm3t.js.br +0 -0
  256. package/payload/server/public/assets/browser-Cy-rJm3t.js.gz +0 -0
  257. package/payload/server/public/assets/calendar-DUTKxWtd.js.br +0 -0
  258. package/payload/server/public/assets/calendar-DUTKxWtd.js.gz +0 -0
  259. package/payload/server/public/assets/chat-Cis7sHsZ.js +0 -1
  260. package/payload/server/public/assets/chat-Cis7sHsZ.js.br +0 -0
  261. package/payload/server/public/assets/chat-Cis7sHsZ.js.gz +0 -0
  262. package/payload/server/public/assets/chevron-left-Bhhx8j2r.js +0 -1
  263. package/payload/server/public/assets/chevron-left-Bhhx8j2r.js.br +0 -0
  264. package/payload/server/public/assets/clock-Ca3nx7Cc.js +0 -1
  265. package/payload/server/public/assets/clock-Ca3nx7Cc.js.br +0 -0
  266. package/payload/server/public/assets/clock-Ca3nx7Cc.js.gz +0 -0
  267. package/payload/server/public/assets/copy-DE9qmAs5.js.br +0 -0
  268. package/payload/server/public/assets/copy-DE9qmAs5.js.gz +0 -0
  269. package/payload/server/public/assets/data-CkaAEeP1.js +0 -1
  270. package/payload/server/public/assets/data-CkaAEeP1.js.br +0 -0
  271. package/payload/server/public/assets/data-CkaAEeP1.js.gz +0 -0
  272. package/payload/server/public/assets/field-DE2tEfTo.js.br +0 -0
  273. package/payload/server/public/assets/field-DE2tEfTo.js.gz +0 -0
  274. package/payload/server/public/assets/file-text-BHfL2gqo.js.br +0 -0
  275. package/payload/server/public/assets/file-text-BHfL2gqo.js.gz +0 -0
  276. package/payload/server/public/assets/graph-08S_BofN.js.br +0 -0
  277. package/payload/server/public/assets/graph-08S_BofN.js.gz +0 -0
  278. package/payload/server/public/assets/graph-labels-C640Er5R.js.br +0 -0
  279. package/payload/server/public/assets/graph-labels-C640Er5R.js.gz +0 -0
  280. package/payload/server/public/assets/jsx-runtime-FxjwOUbA.css.br +0 -0
  281. package/payload/server/public/assets/operator-DH5Kw3fL.js.br +0 -0
  282. package/payload/server/public/assets/operator-DH5Kw3fL.js.gz +0 -0
  283. package/payload/server/public/assets/page-BDpa4HWT.js.br +0 -0
  284. package/payload/server/public/assets/page-BDpa4HWT.js.gz +0 -0
  285. package/payload/server/public/assets/page-yn7ivq8O.js.br +0 -0
  286. package/payload/server/public/assets/page-yn7ivq8O.js.gz +0 -0
  287. package/payload/server/public/assets/play-CMN7ht-S.js +0 -1
  288. package/payload/server/public/assets/play-CMN7ht-S.js.br +0 -0
  289. package/payload/server/public/assets/play-CMN7ht-S.js.gz +0 -0
  290. package/payload/server/public/assets/public-D_qjqet7.js.br +0 -0
  291. package/payload/server/public/assets/public-D_qjqet7.js.gz +0 -0
  292. package/payload/server/public/assets/rotate-ccw-Ixkq1iUA.js.br +0 -0
  293. package/payload/server/public/assets/rotate-ccw-Ixkq1iUA.js.gz +0 -0
  294. package/payload/server/public/assets/routines-Cxjlmcp7.js.br +0 -0
  295. package/payload/server/public/assets/routines-Cxjlmcp7.js.gz +0 -0
  296. package/payload/server/public/assets/skills-DEo9hSVX.js.br +0 -0
  297. package/payload/server/public/assets/skills-DEo9hSVX.js.gz +0 -0
  298. package/payload/server/public/assets/tasks-BxApOIXI.js.br +0 -0
  299. package/payload/server/public/assets/tasks-BxApOIXI.js.gz +0 -0
  300. package/payload/server/public/assets/triangle-alert-BYzMcXv8.js.br +0 -0
  301. package/payload/server/public/assets/triangle-alert-BYzMcXv8.js.gz +0 -0
  302. package/payload/server/public/assets/useCopyFeedback-Bk2HVcjy.js.br +0 -0
  303. package/payload/server/public/assets/useCopyFeedback-Bk2HVcjy.js.gz +0 -0
  304. package/payload/server/public/assets/useMediaQuery-DEti-vAx.js.br +0 -0
  305. package/payload/server/public/assets/useVoiceRecorder-kQ92rL-f.js.br +0 -0
  306. package/payload/server/public/assets/useVoiceRecorder-kQ92rL-f.js.gz +0 -0
  307. package/payload/server/public/assets/wrench-BhLkHffv.js.br +0 -0
  308. package/payload/server/public/assets/wrench-BhLkHffv.js.gz +0 -0
  309. /package/payload/server/public/assets/{jsx-runtime-BL3pljPe.js → jsx-runtime-BmNepPEn.js} +0 -0
  310. /package/payload/server/public/assets/{jsx-runtime-BL3pljPe.js.br → jsx-runtime-BmNepPEn.js.br} +0 -0
  311. /package/payload/server/public/assets/{jsx-runtime-BL3pljPe.js.gz → jsx-runtime-BmNepPEn.js.gz} +0 -0
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isStorableChannelKey = isStorableChannelKey;
4
+ exports.isBusinessChannelKey = isBusinessChannelKey;
5
+ exports.channelKeyToFileStem = channelKeyToFileStem;
6
+ exports.fileStemToChannelKey = fileStemToChannelKey;
7
+ exports.collectTelegramReach = collectTelegramReach;
8
+ exports.telegramStoreRoot = telegramStoreRoot;
9
+ /**
10
+ * Task 2625 — which Telegram chats a registered bot can already message.
11
+ *
12
+ * Telegram does not let a bot open a conversation: the person must message it
13
+ * first (core.telegram.org/bots). So "can I reach X" is answerable only from
14
+ * what has already arrived, and the record of that is the message store the
15
+ * webhook writes. Before this module nothing enumerated it, and the agent
16
+ * refused a send that one telegram-card call would have made.
17
+ *
18
+ * Shared rather than duplicated plugin-side, unlike the live-location and card
19
+ * stores: BOTH callers need this same walk — the MCP tool answers one account on
20
+ * demand, the hourly census counts every account — so duplicating it would mean
21
+ * writing the walk twice and holding it together with a boundary test. The
22
+ * filename rule lives here too, and `ui/app/lib/telegram/message-store.ts`
23
+ * re-exports it, so the store that writes a filename and the walk that reads one
24
+ * cannot disagree.
25
+ *
26
+ * `collectTelegramReach` takes `storeDir` from its caller, but the DERIVATION of
27
+ * that directory lives here too, in `telegramStoreRoot`. Task 2625 left it to
28
+ * each caller on the grounds that a library must not know what a brand is, and
29
+ * the two callers promptly disagreed: the webhook wrote the brand config dir
30
+ * while `telegram-reach` read the brand install dir, so the tool reported every
31
+ * chat unreachable and named its own live sender as never having messaged
32
+ * (Task 2644). One derivation, for the same reason the filename rule is here.
33
+ */
34
+ const node_fs_1 = require("node:fs");
35
+ const node_os_1 = require("node:os");
36
+ const node_path_1 = require("node:path");
37
+ /**
38
+ * Is this a channel key that can safely become a path segment?
39
+ *
40
+ * Both halves of an admin key are Telegram numeric ids (a bot id is positive; a
41
+ * chat or sender id is an integer and is negative for groups), so requiring
42
+ * exactly that is both the truthful shape check and a complete traversal guard:
43
+ * no `.`, `/` or `\` can survive it.
44
+ *
45
+ * Task 2615 — the business shape `<botId>:biz:<senderId>` joins the guard rather
46
+ * than bypassing it. Both alternatives are anchored and admit only digits, an
47
+ * optional leading minus and the literal `biz`, so neither can carry a `.`, `/`
48
+ * or `\` either.
49
+ */
50
+ function isStorableChannelKey(channelKey) {
51
+ return /^-?\d+:-?\d+$/.test(channelKey) || /^-?\d+:biz:-?\d+$/.test(channelKey);
52
+ }
53
+ /** Task 2615 — is this the three-part business shape?
54
+ *
55
+ * Its own predicate rather than a `.includes(':biz:')` at each caller: a
56
+ * business conversation is reached through the business-connection send route
57
+ * and its 24-hour window, not by addressing a chat id, so anything that answers
58
+ * "can we message this person now" has to be able to tell the two apart. */
59
+ function isBusinessChannelKey(channelKey) {
60
+ return /^-?\d+:biz:-?\d+$/.test(channelKey);
61
+ }
62
+ /** The filename stem for a channel key.
63
+ *
64
+ * Throws on a key that is neither two numeric ids nor the business shape.
65
+ * Refusing loudly is correct here: every caller reaches this with a key it has
66
+ * already validated, so an unstorable key means a caller skipped its guard, and
67
+ * silently sanitising it would build a path nobody asked for. */
68
+ function channelKeyToFileStem(channelKey) {
69
+ if (!isStorableChannelKey(channelKey)) {
70
+ throw new Error(`telegram-message-store: refusing unstorable channelKey ${JSON.stringify(channelKey)}`);
71
+ }
72
+ // Task 2615 — every colon, not only the first: a business key has two.
73
+ return channelKey.replaceAll(":", "_");
74
+ }
75
+ /** The inverse of `channelKeyToFileStem`.
76
+ *
77
+ * Task 2615 — a stem whose second segment is exactly `biz` is a three-part
78
+ * business key. Otherwise only the FIRST `_` is a separator, because both halves
79
+ * of an admin key are numeric Telegram ids and nothing later in that stem is
80
+ * one. */
81
+ function fileStemToChannelKey(stem) {
82
+ const i = stem.indexOf("_");
83
+ if (i <= 0)
84
+ return stem;
85
+ const rest = stem.slice(i + 1);
86
+ if (rest.startsWith("biz_")) {
87
+ return `${stem.slice(0, i)}:biz:${rest.slice("biz_".length)}`;
88
+ }
89
+ return `${stem.slice(0, i)}:${rest}`;
90
+ }
91
+ function parseLines(raw) {
92
+ const out = [];
93
+ for (const line of raw.split("\n")) {
94
+ if (!line.trim())
95
+ continue;
96
+ try {
97
+ out.push(JSON.parse(line));
98
+ }
99
+ catch {
100
+ // A partial write from a crash mid-append is skipped, never fatal: one
101
+ // corrupt line must not hide every other chat in the account.
102
+ }
103
+ }
104
+ return out;
105
+ }
106
+ /** Every conversation file's newest inbound PRIVATE row, keyed
107
+ * `<botId>:<senderId>`, plus the message rows read getting there. */
108
+ function scanStore(storeDir) {
109
+ const newest = new Map();
110
+ let storeRows = 0;
111
+ if (!storeDir || !(0, node_fs_1.existsSync)(storeDir))
112
+ return { newest, storeRows };
113
+ let entries;
114
+ try {
115
+ entries = (0, node_fs_1.readdirSync)(storeDir);
116
+ }
117
+ catch {
118
+ return { newest, storeRows };
119
+ }
120
+ for (const entry of entries) {
121
+ if (!entry.endsWith(".jsonl"))
122
+ continue;
123
+ const stem = entry.slice(0, -".jsonl".length);
124
+ const channelKey = fileStemToChannelKey(stem);
125
+ if (!isStorableChannelKey(channelKey))
126
+ continue;
127
+ // Task 2615's business conversations are skipped entirely, rows included.
128
+ // A business chat is NOT reached by addressing a chat id: it needs the
129
+ // business-connection send route and its own 24-hour window, which Task 2625
130
+ // put out of scope. Listing one here would report it as sendable with
131
+ // telegram-card, which is the same wrong answer in the opposite direction to
132
+ // the refusal this tool exists to prevent.
133
+ if (isBusinessChannelKey(channelKey))
134
+ continue;
135
+ const botId = channelKey.slice(0, channelKey.indexOf(":"));
136
+ let raw;
137
+ try {
138
+ raw = (0, node_fs_1.readFileSync)((0, node_path_1.join)(storeDir, entry), "utf8");
139
+ }
140
+ catch {
141
+ continue;
142
+ }
143
+ for (const row of parseLines(raw)) {
144
+ // An update row is a patch, not a message: counting it would inflate
145
+ // storeRows and it carries no sender at all.
146
+ if (row.kind === "update")
147
+ continue;
148
+ storeRows += 1;
149
+ if (row.origin !== "inbound")
150
+ continue;
151
+ const chatId = typeof row.chatId === "string" ? row.chatId : null;
152
+ const senderId = typeof row.senderId === "string" ? row.senderId : null;
153
+ const dateSent = typeof row.dateSent === "string" ? row.dateSent : null;
154
+ if (chatId === null || senderId === null || dateSent === null)
155
+ continue;
156
+ // Private chats only. A DM chat id equals the sender id; a group's differs
157
+ // (telegram-gateway.ts:66-68). A group is not a route to a person.
158
+ if (chatId !== senderId)
159
+ continue;
160
+ const key = `${botId}:${senderId}`;
161
+ const prev = newest.get(key);
162
+ if (prev !== undefined && prev.dateSent.localeCompare(dateSent) >= 0)
163
+ continue;
164
+ newest.set(key, {
165
+ chatId,
166
+ senderId,
167
+ senderName: typeof row.senderName === "string" ? row.senderName : null,
168
+ dateSent,
169
+ });
170
+ }
171
+ }
172
+ return { newest, storeRows };
173
+ }
174
+ /** Reachability for one account: every registered bot, the private chats that
175
+ * have messaged it, and the allowlisted people who have not. */
176
+ function collectTelegramReach(input) {
177
+ const { newest, storeRows } = scanStore(input.storeDir);
178
+ const bots = input.bots.map((bot) => {
179
+ const adminUsers = bot.adminUsers ?? [];
180
+ const adminSet = new Set(adminUsers.map((u) => String(u)));
181
+ const chats = [];
182
+ const seen = new Set();
183
+ for (const [key, row] of newest) {
184
+ if (key.slice(0, key.indexOf(":")) !== bot.id)
185
+ continue;
186
+ seen.add(row.senderId);
187
+ chats.push({
188
+ chatId: row.chatId,
189
+ senderId: row.senderId,
190
+ displayName: row.senderName,
191
+ lastInbound: row.dateSent,
192
+ admin: adminSet.has(row.senderId),
193
+ reachable: true,
194
+ });
195
+ }
196
+ chats.sort((a, b) => (b.lastInbound ?? "").localeCompare(a.lastInbound ?? ""));
197
+ for (const user of adminUsers) {
198
+ const senderId = String(user);
199
+ if (seen.has(senderId))
200
+ continue;
201
+ // Listed, never messaged. Reported rather than omitted, because "we are
202
+ // allowed to talk to them" and "they have opened the chat" are different
203
+ // facts and only the second one makes a send possible.
204
+ chats.push({
205
+ chatId: null,
206
+ senderId,
207
+ displayName: null,
208
+ lastInbound: null,
209
+ admin: true,
210
+ reachable: false,
211
+ });
212
+ }
213
+ return { botId: bot.id, role: bot.role, adminUsers, chats };
214
+ });
215
+ return { bots, storeRows };
216
+ }
217
+ /** The brand's config directory NAME, from its own brand.json.
218
+ *
219
+ * Resolved WITHOUT the platform's `paths.ts`, which throws at module init on a
220
+ * brand.json missing a port field. The inbound Telegram webhook imports this
221
+ * path, so a throw here takes delivery down; a brand.json that cannot be read
222
+ * falls back to `.maxy` instead. */
223
+ function configDirName(platformRoot) {
224
+ const brandPath = (0, node_path_1.join)(platformRoot, "config", "brand.json");
225
+ if ((0, node_fs_1.existsSync)(brandPath)) {
226
+ try {
227
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(brandPath, "utf8"));
228
+ if (typeof parsed.configDir === "string")
229
+ return parsed.configDir;
230
+ }
231
+ catch {
232
+ // A brand.json that will not parse falls back rather than throwing.
233
+ }
234
+ }
235
+ return ".maxy";
236
+ }
237
+ /** The brand's Telegram message store root, for a given platform root.
238
+ *
239
+ * The ONE derivation of this path. `ui/app/lib/telegram/message-store.ts`
240
+ * writes under it and `plugins/telegram/mcp` reads under it, both through this
241
+ * function, so the writer and the reader cannot name different directories. */
242
+ function telegramStoreRoot(platformRoot) {
243
+ const brandDir = process.env.MAXY_DIR_OVERRIDE ?? (0, node_path_1.resolve)((0, node_os_1.homedir)(), configDirName(platformRoot));
244
+ return (0, node_path_1.join)(brandDir, "data", "telegram-messages");
245
+ }
246
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,268 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
3
+ import { tmpdir, homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ import {
6
+ collectTelegramReach,
7
+ isStorableChannelKey,
8
+ isBusinessChannelKey,
9
+ channelKeyToFileStem,
10
+ fileStemToChannelKey,
11
+ telegramStoreRoot,
12
+ } from "../index.js";
13
+
14
+ const BOT = "8801383568";
15
+ const KIT = "8860040117";
16
+ const NEO = "1311221864";
17
+ const GROUP = "-1002222222222";
18
+
19
+ let storeDir: string;
20
+
21
+ /** One inbound message row, in the shape message-store.ts writes. */
22
+ const inbound = (over: Record<string, unknown> = {}) => ({
23
+ messageId: `telegram:acct:${BOT}:${KIT}:in:1`,
24
+ sessionId: "s",
25
+ dateSent: "2026-08-09T07:46:31.000Z",
26
+ body: "hello",
27
+ fromMe: false,
28
+ senderId: KIT,
29
+ senderName: "Kit Smalley",
30
+ chatId: KIT,
31
+ channelKey: `${BOT}:${KIT}`,
32
+ scope: "admin",
33
+ origin: "inbound",
34
+ createdAt: "2026-08-09T07:46:31.000Z",
35
+ ...over,
36
+ });
37
+
38
+ function writeConversation(channelKey: string, rows: unknown[]): void {
39
+ const file = join(storeDir, `${channelKeyToFileStem(channelKey)}.jsonl`);
40
+ writeFileSync(file, rows.map((r) => JSON.stringify(r)).join("\n") + "\n", "utf8");
41
+ }
42
+
43
+ beforeEach(() => {
44
+ storeDir = mkdtempSync(join(tmpdir(), "tg-reach-"));
45
+ });
46
+
47
+ afterEach(() => {
48
+ rmSync(storeDir, { recursive: true, force: true });
49
+ });
50
+
51
+ describe("the key helpers", () => {
52
+ it("accepts two numeric ids and rejects a traversal", () => {
53
+ expect(isStorableChannelKey(`${BOT}:${KIT}`)).toBe(true);
54
+ expect(isStorableChannelKey(`${BOT}:${GROUP}`)).toBe(true);
55
+ expect(isStorableChannelKey("../../../../etc/passwd:x")).toBe(false);
56
+ });
57
+
58
+ it("round-trips a key through its filename stem", () => {
59
+ expect(fileStemToChannelKey(channelKeyToFileStem(`${BOT}:${KIT}`))).toBe(`${BOT}:${KIT}`);
60
+ });
61
+
62
+ // Task 2615's three-part business shape. Round-tripping it is what keeps its
63
+ // conversations readable at all; telling it apart is what keeps them out of
64
+ // the reachable list.
65
+ it("round-trips a business key and recognises it as one", () => {
66
+ const biz = `${BOT}:biz:${KIT}`;
67
+ expect(isStorableChannelKey(biz)).toBe(true);
68
+ expect(channelKeyToFileStem(biz)).toBe(`${BOT}_biz_${KIT}`);
69
+ expect(fileStemToChannelKey(`${BOT}_biz_${KIT}`)).toBe(biz);
70
+ expect(isBusinessChannelKey(biz)).toBe(true);
71
+ expect(isBusinessChannelKey(`${BOT}:${KIT}`)).toBe(false);
72
+ });
73
+
74
+ it("refuses to build a stem from an unstorable key", () => {
75
+ expect(() => channelKeyToFileStem("a/b:c")).toThrow(/refusing unstorable channelKey/);
76
+ });
77
+ });
78
+
79
+ describe("collectTelegramReach", () => {
80
+ it("reports one entry per registered bot", () => {
81
+ const out = collectTelegramReach({
82
+ storeDir,
83
+ bots: [
84
+ { id: BOT, role: "admin", adminUsers: [] },
85
+ { id: "7777777777", role: "public" },
86
+ ],
87
+ });
88
+ expect(out.bots.map((b) => b.botId)).toEqual([BOT, "7777777777"]);
89
+ });
90
+
91
+ it("returns an empty chat list for a bot with no inbound, not an error", () => {
92
+ const out = collectTelegramReach({ storeDir, bots: [{ id: BOT, role: "admin" }] });
93
+ expect(out.bots[0].chats).toEqual([]);
94
+ expect(out.storeRows).toBe(0);
95
+ });
96
+
97
+ it("lists a chat that has messaged, with the newest inbound name and time", () => {
98
+ writeConversation(`${BOT}:${KIT}`, [
99
+ inbound(),
100
+ inbound({
101
+ messageId: "m2",
102
+ dateSent: "2026-08-09T09:00:00.000Z",
103
+ senderName: "Kit S",
104
+ }),
105
+ ]);
106
+ const out = collectTelegramReach({ storeDir, bots: [{ id: BOT, role: "admin" }] });
107
+ expect(out.bots[0].chats).toEqual([
108
+ {
109
+ chatId: KIT,
110
+ senderId: KIT,
111
+ displayName: "Kit S",
112
+ lastInbound: "2026-08-09T09:00:00.000Z",
113
+ admin: false,
114
+ reachable: true,
115
+ },
116
+ ]);
117
+ expect(out.storeRows).toBe(2);
118
+ });
119
+
120
+ it("marks a chat that is also an adminUsers entry", () => {
121
+ writeConversation(`${BOT}:${KIT}`, [inbound()]);
122
+ const out = collectTelegramReach({
123
+ storeDir,
124
+ bots: [{ id: BOT, role: "admin", adminUsers: [Number(KIT)] }],
125
+ });
126
+ expect(out.bots[0].chats[0].admin).toBe(true);
127
+ });
128
+
129
+ it("lists an adminUsers entry that has never messaged as not reachable", () => {
130
+ const out = collectTelegramReach({
131
+ storeDir,
132
+ bots: [{ id: BOT, role: "admin", adminUsers: [Number(KIT)] }],
133
+ });
134
+ expect(out.bots[0].chats).toEqual([
135
+ {
136
+ chatId: null,
137
+ senderId: KIT,
138
+ displayName: null,
139
+ lastInbound: null,
140
+ admin: true,
141
+ reachable: false,
142
+ },
143
+ ]);
144
+ });
145
+
146
+ it("excludes a group: its chatId differs from its senderId", () => {
147
+ writeConversation(`${BOT}:${KIT}`, [inbound({ chatId: GROUP })]);
148
+ const out = collectTelegramReach({ storeDir, bots: [{ id: BOT, role: "admin" }] });
149
+ expect(out.bots[0].chats).toEqual([]);
150
+ expect(out.storeRows).toBe(1);
151
+ });
152
+
153
+ it("does not make a chat reachable on agent or operator rows alone", () => {
154
+ writeConversation(`${BOT}:${KIT}`, [
155
+ inbound({ origin: "agent" }),
156
+ inbound({ messageId: "m2", origin: "operator-manual" }),
157
+ ]);
158
+ const out = collectTelegramReach({ storeDir, bots: [{ id: BOT, role: "admin" }] });
159
+ expect(out.bots[0].chats).toEqual([]);
160
+ expect(out.storeRows).toBe(2);
161
+ });
162
+
163
+ it("never counts an update row as a message and never makes it a chat", () => {
164
+ writeConversation(`${BOT}:${KIT}`, [
165
+ { kind: "update", targetMessageId: "m1", body: "x", createdAt: "2026-08-09T07:47:00.000Z" },
166
+ ]);
167
+ const out = collectTelegramReach({ storeDir, bots: [{ id: BOT, role: "admin" }] });
168
+ expect(out.storeRows).toBe(0);
169
+ expect(out.bots[0].chats).toEqual([]);
170
+ });
171
+
172
+ it("counts rows belonging to an unregistered bot, so a mis-scoped bot list is visible", () => {
173
+ writeConversation(`9999999999:${KIT}`, [inbound({ channelKey: `9999999999:${KIT}` })]);
174
+ const out = collectTelegramReach({ storeDir, bots: [{ id: BOT, role: "admin" }] });
175
+ expect(out.bots[0].chats).toEqual([]);
176
+ expect(out.storeRows).toBe(1);
177
+ });
178
+
179
+ // A business chat is reached through the business-connection route and its
180
+ // 24-hour window, never by addressing a chat id, so reporting one here would
181
+ // be the same wrong answer as the refusal this tool exists to prevent, only in
182
+ // the opposite direction. Its rows are not counted either: they were never
183
+ // walked.
184
+ it("skips a business conversation entirely, rows included", () => {
185
+ writeConversation(`${BOT}:biz:${KIT}`, [inbound({ channelKey: `${BOT}:biz:${KIT}` })]);
186
+ const out = collectTelegramReach({ storeDir, bots: [{ id: BOT, role: "admin" }] });
187
+ expect(out.bots[0].chats).toEqual([]);
188
+ expect(out.storeRows).toBe(0);
189
+ });
190
+
191
+ it("reads an absent store directory as no rows rather than throwing", () => {
192
+ const out = collectTelegramReach({
193
+ storeDir: join(storeDir, "nope"),
194
+ bots: [{ id: BOT, role: "admin" }],
195
+ });
196
+ expect(out.storeRows).toBe(0);
197
+ expect(out.bots[0].chats).toEqual([]);
198
+ });
199
+
200
+ it("orders reachable chats newest first, then the never-messaged admins", () => {
201
+ writeConversation(`${BOT}:${KIT}`, [inbound()]);
202
+ writeConversation(`${BOT}:${NEO}`, [
203
+ inbound({
204
+ senderId: NEO,
205
+ chatId: NEO,
206
+ channelKey: `${BOT}:${NEO}`,
207
+ senderName: "Neo",
208
+ dateSent: "2026-08-09T08:08:12.000Z",
209
+ }),
210
+ ]);
211
+ const out = collectTelegramReach({
212
+ storeDir,
213
+ bots: [{ id: BOT, role: "admin", adminUsers: [Number(KIT), 5555555555] }],
214
+ });
215
+ expect(out.bots[0].chats.map((c) => c.senderId)).toEqual([NEO, KIT, "5555555555"]);
216
+ });
217
+ });
218
+
219
+ describe("telegramStoreRoot", () => {
220
+ let root: string;
221
+
222
+ beforeEach(() => {
223
+ root = mkdtempSync(join(tmpdir(), "tg-store-root-"));
224
+ delete process.env.MAXY_DIR_OVERRIDE;
225
+ });
226
+
227
+ afterEach(() => {
228
+ delete process.env.MAXY_DIR_OVERRIDE;
229
+ rmSync(root, { recursive: true, force: true });
230
+ });
231
+
232
+ function writeBrand(configDir: unknown): string {
233
+ const platformRoot = join(root, "platform");
234
+ mkdirSync(join(platformRoot, "config"), { recursive: true });
235
+ writeFileSync(
236
+ join(platformRoot, "config", "brand.json"),
237
+ typeof configDir === "string" ? JSON.stringify({ configDir }) : "{ not json",
238
+ "utf8",
239
+ );
240
+ return platformRoot;
241
+ }
242
+
243
+ it("reads configDir from brand.json", () => {
244
+ expect(telegramStoreRoot(writeBrand(".maxy-code"))).toBe(
245
+ join(homedir(), ".maxy-code", "data", "telegram-messages"),
246
+ );
247
+ });
248
+
249
+ it("falls back to .maxy when brand.json is absent", () => {
250
+ const platformRoot = join(root, "platform");
251
+ mkdirSync(platformRoot, { recursive: true });
252
+ expect(telegramStoreRoot(platformRoot)).toBe(
253
+ join(homedir(), ".maxy", "data", "telegram-messages"),
254
+ );
255
+ });
256
+
257
+ it("falls back to .maxy when brand.json is unparseable, without throwing", () => {
258
+ expect(telegramStoreRoot(writeBrand(null))).toBe(
259
+ join(homedir(), ".maxy", "data", "telegram-messages"),
260
+ );
261
+ });
262
+
263
+ it("MAXY_DIR_OVERRIDE wins over brand.json", () => {
264
+ const platformRoot = writeBrand(".maxy-code");
265
+ process.env.MAXY_DIR_OVERRIDE = root;
266
+ expect(telegramStoreRoot(platformRoot)).toBe(join(root, "data", "telegram-messages"));
267
+ });
268
+ });