@rubytech/create-realagent-code 0.1.593 → 0.1.595

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/package.json +2 -2
  2. package/payload/platform/lib/telegram-button-labels/dist/index.d.ts +19 -0
  3. package/payload/platform/lib/telegram-button-labels/dist/index.d.ts.map +1 -0
  4. package/payload/platform/lib/telegram-button-labels/dist/index.js +84 -0
  5. package/payload/platform/lib/telegram-button-labels/dist/index.js.map +1 -0
  6. package/payload/platform/lib/telegram-button-labels/src/__tests__/store.test.ts +67 -0
  7. package/payload/platform/lib/telegram-button-labels/src/index.ts +88 -0
  8. package/payload/platform/lib/telegram-button-labels/tsconfig.json +9 -0
  9. package/payload/platform/lib/telegram-button-labels/vitest.config.ts +9 -0
  10. package/payload/platform/package.json +3 -2
  11. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +12 -3
  12. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +10 -0
  13. package/payload/platform/plugins/cloudflare/PLUGIN.md +2 -0
  14. package/payload/platform/plugins/docs/references/internals.md +1 -1
  15. package/payload/platform/plugins/docs/references/telegram-guide.md +10 -1
  16. package/payload/platform/scripts/__tests__/agent-identity-reconcile.test.sh +110 -0
  17. package/payload/platform/scripts/__tests__/check-orphan-dist.test.sh +87 -0
  18. package/payload/platform/scripts/check-orphan-dist.mjs +143 -0
  19. package/payload/platform/scripts/lib/agent-identity-reconcile.sh +122 -0
  20. package/payload/platform/scripts/lib/provision-account-dir.sh +8 -26
  21. package/payload/platform/scripts/setup-account.sh +15 -0
  22. package/payload/platform/services/claude-session-manager/dist/index.js +5 -0
  23. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  24. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +5 -0
  25. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -1
  26. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +42 -1
  27. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -1
  28. package/payload/platform/templates/agents/public/IDENTITY.md +3 -3
  29. package/payload/server/server.js +543 -409
  30. package/payload/platform/lib/anthropic-key/dist/index.d.ts +0 -22
  31. package/payload/platform/lib/anthropic-key/dist/index.d.ts.map +0 -1
  32. package/payload/platform/lib/anthropic-key/dist/index.js +0 -232
  33. package/payload/platform/lib/anthropic-key/dist/index.js.map +0 -1
  34. package/payload/platform/lib/graph-search/dist/query-expansion.d.ts +0 -37
  35. package/payload/platform/lib/graph-search/dist/query-expansion.d.ts.map +0 -1
  36. package/payload/platform/lib/graph-search/dist/query-expansion.js +0 -101
  37. package/payload/platform/lib/graph-search/dist/query-expansion.js.map +0 -1
  38. package/payload/platform/lib/oauth-llm/dist/index.d.ts +0 -116
  39. package/payload/platform/lib/oauth-llm/dist/index.d.ts.map +0 -1
  40. package/payload/platform/lib/oauth-llm/dist/index.js +0 -386
  41. package/payload/platform/lib/oauth-llm/dist/index.js.map +0 -1
  42. package/payload/platform/lib/screening-patterns/dist/index.d.ts +0 -29
  43. package/payload/platform/lib/screening-patterns/dist/index.d.ts.map +0 -1
  44. package/payload/platform/lib/screening-patterns/dist/index.js +0 -48
  45. package/payload/platform/lib/screening-patterns/dist/index.js.map +0 -1
  46. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts +0 -2
  47. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts.map +0 -1
  48. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js +0 -34
  49. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js.map +0 -1
  50. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.d.ts +0 -39
  51. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.d.ts.map +0 -1
  52. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.js +0 -249
  53. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.js.map +0 -1
  54. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts +0 -6
  55. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts.map +0 -1
  56. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js +0 -32
  57. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js.map +0 -1
  58. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts +0 -283
  59. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +0 -1
  60. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +0 -1155
  61. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +0 -1
  62. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts +0 -90
  63. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts.map +0 -1
  64. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js +0 -551
  65. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js.map +0 -1
  66. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts +0 -17
  67. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts.map +0 -1
  68. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js +0 -186
  69. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js.map +0 -1
  70. package/payload/platform/plugins/email/mcp/dist/lib/screening.d.ts +0 -29
  71. package/payload/platform/plugins/email/mcp/dist/lib/screening.d.ts.map +0 -1
  72. package/payload/platform/plugins/email/mcp/dist/lib/screening.js +0 -105
  73. package/payload/platform/plugins/email/mcp/dist/lib/screening.js.map +0 -1
  74. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.d.ts +0 -38
  75. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.d.ts.map +0 -1
  76. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js +0 -817
  77. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js.map +0 -1
  78. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.d.ts +0 -30
  79. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.d.ts.map +0 -1
  80. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js +0 -215
  81. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js.map +0 -1
  82. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.d.ts +0 -19
  83. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.d.ts.map +0 -1
  84. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.js +0 -151
  85. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.js.map +0 -1
  86. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts +0 -6
  87. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts.map +0 -1
  88. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js +0 -89
  89. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js.map +0 -1
  90. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.d.ts +0 -2
  91. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.d.ts.map +0 -1
  92. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.js +0 -90
  93. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.js.map +0 -1
  94. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.d.ts +0 -2
  95. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.d.ts.map +0 -1
  96. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +0 -226
  97. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +0 -1
  98. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts +0 -60
  99. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts.map +0 -1
  100. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js +0 -169
  101. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js.map +0 -1
  102. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts +0 -248
  103. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +0 -1
  104. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +0 -824
  105. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +0 -1
  106. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts +0 -63
  107. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts.map +0 -1
  108. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js +0 -210
  109. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js.map +0 -1
  110. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts +0 -35
  111. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts.map +0 -1
  112. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.js +0 -28
  113. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.js.map +0 -1
  114. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.d.ts +0 -2
  115. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.d.ts.map +0 -1
  116. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.js +0 -68
  117. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.js.map +0 -1
  118. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.d.ts +0 -2
  119. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.d.ts.map +0 -1
  120. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js +0 -88
  121. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js.map +0 -1
  122. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts +0 -2
  123. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts.map +0 -1
  124. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.js +0 -58
  125. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.js.map +0 -1
  126. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.d.ts +0 -2
  127. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.d.ts.map +0 -1
  128. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js +0 -64
  129. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js.map +0 -1
  130. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.d.ts +0 -2
  131. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.d.ts.map +0 -1
  132. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.js +0 -70
  133. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.js.map +0 -1
  134. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.d.ts +0 -2
  135. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.d.ts.map +0 -1
  136. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.js +0 -48
  137. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.js.map +0 -1
  138. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.d.ts +0 -2
  139. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.d.ts.map +0 -1
  140. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.js +0 -74
  141. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.js.map +0 -1
  142. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.d.ts +0 -2
  143. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.d.ts.map +0 -1
  144. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.js +0 -47
  145. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.js.map +0 -1
  146. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.d.ts +0 -2
  147. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.d.ts.map +0 -1
  148. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.js +0 -65
  149. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.js.map +0 -1
  150. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.d.ts +0 -2
  151. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.d.ts.map +0 -1
  152. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.js +0 -43
  153. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.js.map +0 -1
  154. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.d.ts +0 -2
  155. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.d.ts.map +0 -1
  156. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.js +0 -65
  157. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.js.map +0 -1
  158. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.d.ts +0 -2
  159. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.d.ts.map +0 -1
  160. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.js +0 -49
  161. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.js.map +0 -1
  162. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.d.ts +0 -2
  163. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.d.ts.map +0 -1
  164. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +0 -79
  165. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +0 -1
  166. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.d.ts +0 -2
  167. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.d.ts.map +0 -1
  168. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.js +0 -329
  169. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.js.map +0 -1
  170. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.d.ts +0 -2
  171. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.d.ts.map +0 -1
  172. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +0 -81
  173. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +0 -1
  174. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.d.ts +0 -34
  175. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.d.ts.map +0 -1
  176. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.js +0 -62
  177. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.js.map +0 -1
  178. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.d.ts +0 -61
  179. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.d.ts.map +0 -1
  180. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.js +0 -102
  181. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.js.map +0 -1
  182. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.d.ts +0 -35
  183. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.d.ts.map +0 -1
  184. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.js +0 -73
  185. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.js.map +0 -1
  186. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +0 -29
  187. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts.map +0 -1
  188. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +0 -22
  189. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js.map +0 -1
  190. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts +0 -30
  191. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts.map +0 -1
  192. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js +0 -130
  193. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js.map +0 -1
  194. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts +0 -65
  195. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts.map +0 -1
  196. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js +0 -262
  197. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js.map +0 -1
  198. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/normalise-start-date.test.d.ts +0 -2
  199. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/normalise-start-date.test.d.ts.map +0 -1
  200. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/normalise-start-date.test.js +0 -100
  201. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/normalise-start-date.test.js.map +0 -1
  202. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts +0 -2
  203. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.d.ts.map +0 -1
  204. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js +0 -22
  205. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/scheduled-seat-id.test.js.map +0 -1
  206. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts +0 -11
  207. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.d.ts.map +0 -1
  208. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js +0 -19
  209. package/payload/platform/plugins/scheduling/mcp/dist/lib/scheduled-seat-id.js.map +0 -1
  210. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts +0 -8
  211. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts.map +0 -1
  212. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js +0 -83
  213. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js.map +0 -1
  214. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.d.ts +0 -151
  215. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.d.ts.map +0 -1
  216. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.js +0 -299
  217. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.js.map +0 -1
  218. package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts +0 -39
  219. package/payload/platform/services/claude-session-manager/dist/account-admin-census.d.ts.map +0 -1
  220. package/payload/platform/services/claude-session-manager/dist/account-admin-census.js +0 -122
  221. package/payload/platform/services/claude-session-manager/dist/account-admin-census.js.map +0 -1
  222. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts +0 -39
  223. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts.map +0 -1
  224. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js +0 -133
  225. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js.map +0 -1
  226. package/payload/platform/services/claude-session-manager/dist/input-postcondition.d.ts +0 -22
  227. package/payload/platform/services/claude-session-manager/dist/input-postcondition.d.ts.map +0 -1
  228. package/payload/platform/services/claude-session-manager/dist/input-postcondition.js +0 -50
  229. package/payload/platform/services/claude-session-manager/dist/input-postcondition.js.map +0 -1
  230. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts +0 -30
  231. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts.map +0 -1
  232. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js +0 -204
  233. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js.map +0 -1
  234. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.d.ts +0 -80
  235. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.d.ts.map +0 -1
  236. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.js +0 -306
  237. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.js.map +0 -1
  238. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +0 -49
  239. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +0 -1
  240. package/payload/platform/services/claude-session-manager/dist/session-store.js +0 -52
  241. package/payload/platform/services/claude-session-manager/dist/session-store.js.map +0 -1
  242. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.d.ts +0 -83
  243. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.d.ts.map +0 -1
  244. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.js +0 -345
  245. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.js.map +0 -1
  246. package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts +0 -104
  247. package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts.map +0 -1
  248. package/payload/platform/services/telegram-channel/dist/turn-follow.js +0 -408
  249. package/payload/platform/services/telegram-channel/dist/turn-follow.js.map +0 -1
  250. package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts +0 -104
  251. package/payload/platform/services/whatsapp-channel/dist/turn-follow.d.ts.map +0 -1
  252. package/payload/platform/services/whatsapp-channel/dist/turn-follow.js +0 -393
  253. package/payload/platform/services/whatsapp-channel/dist/turn-follow.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-realagent-code",
3
- "version": "0.1.593",
3
+ "version": "0.1.595",
4
4
  "description": "Install Real Agent — Built for agents. By agents.",
5
5
  "bin": {
6
6
  "create-realagent-code": "./dist/index.js"
@@ -13,7 +13,7 @@
13
13
  "build": "tsc",
14
14
  "bundle": "node scripts/bundle.js",
15
15
  "test": "npm run build && node --test 'dist/__tests__/*.test.js'",
16
- "prepublishOnly": "bash ../../platform/scripts/verify-skill-tool-surface.sh && node ../../platform/scripts/check-plugin-tools-mcp-consistency.mjs && node ../../platform/scripts/check-risk-class.mjs && node ../../platform/scripts/check-specialist-tool-surface.mjs && node ../../platform/scripts/check-agent-contract.mjs && node ../../platform/scripts/check-routing-prose-bash.mjs && node ../../platform/scripts/check-no-task-id-leaks.mjs && node ../../platform/scripts/check-no-esm-require.mjs && node ../../platform/scripts/check-no-raw-mcp-registrations.mjs && node ../../platform/scripts/check-skill-load-coverage.mjs && node ../../platform/scripts/check-routine-roster-doc.mjs && node ../../platform/scripts/check-architecture-skill-no-drift.mjs && node ../../platform/ui/scripts/check-brand-fonts.mjs && node ../../platform/ui/scripts/check-route-wiring.mjs && node ../../platform/ui/scripts/check-edge-admin-routes.mjs && npm run build && node --test 'dist/__tests__/*.test.js' && chmod +x dist/index.js && npm run bundle && bash ../../platform/scripts/smoke-boot-services.sh && node ../../platform/ui/scripts/check-bundle-node-imports.mjs --dir=./payload/server/public/assets"
16
+ "prepublishOnly": "bash ../../platform/scripts/verify-skill-tool-surface.sh && node ../../platform/scripts/check-plugin-tools-mcp-consistency.mjs && node ../../platform/scripts/check-risk-class.mjs && node ../../platform/scripts/check-specialist-tool-surface.mjs && node ../../platform/scripts/check-agent-contract.mjs && node ../../platform/scripts/check-routing-prose-bash.mjs && node ../../platform/scripts/check-no-task-id-leaks.mjs && node ../../platform/scripts/check-no-esm-require.mjs && node ../../platform/scripts/check-no-raw-mcp-registrations.mjs && node ../../platform/scripts/check-skill-load-coverage.mjs && node ../../platform/scripts/check-routine-roster-doc.mjs && node ../../platform/scripts/check-architecture-skill-no-drift.mjs && node ../../platform/ui/scripts/check-brand-fonts.mjs && node ../../platform/ui/scripts/check-route-wiring.mjs && node ../../platform/ui/scripts/check-edge-admin-routes.mjs && npm run build && node --test 'dist/__tests__/*.test.js' && chmod +x dist/index.js && node ../../platform/scripts/check-orphan-dist.mjs && npm run bundle && bash ../../platform/scripts/smoke-boot-services.sh && node ../../platform/ui/scripts/check-bundle-node-imports.mjs --dir=./payload/server/public/assets"
17
17
  },
18
18
  "files": [
19
19
  "dist",
@@ -0,0 +1,19 @@
1
+ /** Matches CARD_TTL_MS in the telegram MCP's card store. A label outlives its
2
+ * card by no useful margin, and without a ceiling every callback data string
3
+ * ever sent is kept for ever. */
4
+ export declare const BUTTON_LABEL_TTL_MS: number;
5
+ /** Scoped by bot AND chat, not by the data alone: two chats can use the same
6
+ * callback data for different words. */
7
+ export declare function buttonLabelKey(botId: string, chatId: string | number, data: string): string;
8
+ /** Record every button on one keyboard, and drop every entry gone
9
+ * BUTTON_LABEL_TTL_MS untouched. Compaction rides the write because the write
10
+ * already rewrites the whole file. An empty list writes nothing: a card with no
11
+ * buttons must not create the file. */
12
+ export declare function writeButtonLabels(storeDir: string, entries: Array<{
13
+ key: string;
14
+ label: string;
15
+ }>, now?: number): void;
16
+ /** The stored wording for this key, or null. Null past the TTL, so a caller
17
+ * falls back to the raw data rather than showing a label for a card long gone. */
18
+ export declare function readButtonLabel(storeDir: string, key: string, now?: number): string | null;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA;;kCAEkC;AAClC,eAAO,MAAM,mBAAmB,QAA0B,CAAC;AAa3D;yCACyC;AACzC,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3F;AAoBD;;;wCAGwC;AACxC,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9C,GAAG,GAAE,MAAmB,GACvB,IAAI,CASN;AAED;mFACmF;AACnF,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAmB,GACvB,MAAM,GAAG,IAAI,CAIf"}
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BUTTON_LABEL_TTL_MS = void 0;
4
+ exports.buttonLabelKey = buttonLabelKey;
5
+ exports.writeButtonLabels = writeButtonLabels;
6
+ exports.readButtonLabel = readButtonLabel;
7
+ // Task 2673 — what a button SAID, keyed by what a press CARRIES.
8
+ //
9
+ // A press delivers only its callback data, so an operator reading the
10
+ // conversation sees `[button: pax_1]` and not "1 passenger". The wording exists
11
+ // once, in the keyboard the card tool sent, and was never persisted.
12
+ //
13
+ // This is a shared platform library rather than a key inside the telegram MCP's
14
+ // own card store because the two sides live in different processes: the plugin
15
+ // writes it and the webhook route reads it, and the route imports from
16
+ // platform/lib and never from platform/plugins.
17
+ //
18
+ // Keyed on the callback data rather than the card key: the route holds botId,
19
+ // chatId and data, and never the caller's key.
20
+ const node_fs_1 = require("node:fs");
21
+ const node_path_1 = require("node:path");
22
+ const FILE = "telegram-button-labels.json";
23
+ /** Matches CARD_TTL_MS in the telegram MCP's card store. A label outlives its
24
+ * card by no useful margin, and without a ceiling every callback data string
25
+ * ever sent is kept for ever. */
26
+ exports.BUTTON_LABEL_TTL_MS = 7 * 24 * 60 * 60 * 1000;
27
+ function isEntry(v) {
28
+ if (!v || typeof v !== "object" || Array.isArray(v))
29
+ return false;
30
+ const e = v;
31
+ return typeof e.label === "string" && typeof e.at === "number" && Number.isFinite(e.at);
32
+ }
33
+ /** Scoped by bot AND chat, not by the data alone: two chats can use the same
34
+ * callback data for different words. */
35
+ function buttonLabelKey(botId, chatId, data) {
36
+ return `${botId}:${chatId}:${data}`;
37
+ }
38
+ function readAll(path) {
39
+ if (!(0, node_fs_1.existsSync)(path))
40
+ return {};
41
+ try {
42
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(path, "utf-8"));
43
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
44
+ return {};
45
+ const out = {};
46
+ for (const [k, v] of Object.entries(parsed)) {
47
+ if (isEntry(v))
48
+ out[k] = v;
49
+ }
50
+ return out;
51
+ }
52
+ catch {
53
+ // Unparseable state reads as "no label", which renders the raw data exactly
54
+ // as it did before this library existed. Throwing here would take a webhook
55
+ // down over a file no caller sees.
56
+ return {};
57
+ }
58
+ }
59
+ /** Record every button on one keyboard, and drop every entry gone
60
+ * BUTTON_LABEL_TTL_MS untouched. Compaction rides the write because the write
61
+ * already rewrites the whole file. An empty list writes nothing: a card with no
62
+ * buttons must not create the file. */
63
+ function writeButtonLabels(storeDir, entries, now = Date.now()) {
64
+ if (entries.length === 0)
65
+ return;
66
+ const path = (0, node_path_1.join)(storeDir, FILE);
67
+ const kept = {};
68
+ for (const [key, entry] of Object.entries(readAll(path))) {
69
+ if (now - entry.at < exports.BUTTON_LABEL_TTL_MS)
70
+ kept[key] = entry;
71
+ }
72
+ for (const e of entries)
73
+ kept[e.key] = { label: e.label, at: now };
74
+ (0, node_fs_1.writeFileSync)(path, JSON.stringify(kept, null, 2) + "\n", "utf-8");
75
+ }
76
+ /** The stored wording for this key, or null. Null past the TTL, so a caller
77
+ * falls back to the raw data rather than showing a label for a card long gone. */
78
+ function readButtonLabel(storeDir, key, now = Date.now()) {
79
+ const entry = readAll((0, node_path_1.join)(storeDir, FILE))[key];
80
+ if (!entry)
81
+ return null;
82
+ return now - entry.at >= exports.BUTTON_LABEL_TTL_MS ? null : entry.label;
83
+ }
84
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAoCA,wCAEC;AAwBD,8CAaC;AAID,0CAQC;AAvFD,iEAAiE;AACjE,EAAE;AACF,sEAAsE;AACtE,gFAAgF;AAChF,qEAAqE;AACrE,EAAE;AACF,gFAAgF;AAChF,+EAA+E;AAC/E,uEAAuE;AACvE,gDAAgD;AAChD,EAAE;AACF,8EAA8E;AAC9E,+CAA+C;AAC/C,qCAAkE;AAClE,yCAAiC;AAEjC,MAAM,IAAI,GAAG,6BAA6B,CAAC;AAE3C;;kCAEkC;AACrB,QAAA,mBAAmB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAO3D,SAAS,OAAO,CAAC,CAAU;IACzB,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,MAAM,CAAC,GAAG,CAA4B,CAAC;IACvC,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED;yCACyC;AACzC,SAAgB,cAAc,CAAC,KAAa,EAAE,MAAuB,EAAE,IAAY;IACjF,OAAO,GAAG,KAAK,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,CAAC,IAAA,oBAAU,EAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,OAAO,CAAC,CAAY,CAAC;QAClE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAC9E,MAAM,GAAG,GAA+B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAiC,CAAC,EAAE,CAAC;YACvE,IAAI,OAAO,CAAC,CAAC,CAAC;gBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,4EAA4E;QAC5E,mCAAmC;QACnC,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;wCAGwC;AACxC,SAAgB,iBAAiB,CAC/B,QAAgB,EAChB,OAA8C,EAC9C,MAAc,IAAI,CAAC,GAAG,EAAE;IAExB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACjC,MAAM,IAAI,GAAG,IAAA,gBAAI,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,MAAM,IAAI,GAA+B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACzD,IAAI,GAAG,GAAG,KAAK,CAAC,EAAE,GAAG,2BAAmB;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC9D,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;IACnE,IAAA,uBAAa,EAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACrE,CAAC;AAED;mFACmF;AACnF,SAAgB,eAAe,CAC7B,QAAgB,EAChB,GAAW,EACX,MAAc,IAAI,CAAC,GAAG,EAAE;IAExB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAA,gBAAI,EAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,GAAG,GAAG,KAAK,CAAC,EAAE,IAAI,2BAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AACpE,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from 'vitest'
2
+ import { mkdtempSync, rmSync, existsSync, readFileSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+ import { tmpdir } from 'node:os'
5
+ import {
6
+ BUTTON_LABEL_TTL_MS,
7
+ buttonLabelKey,
8
+ readButtonLabel,
9
+ writeButtonLabels,
10
+ } from '../index.js'
11
+
12
+ let dir: string
13
+
14
+ beforeEach(() => {
15
+ dir = mkdtempSync(join(tmpdir(), 'tg-labels-'))
16
+ })
17
+
18
+ afterEach(() => {
19
+ rmSync(dir, { recursive: true, force: true })
20
+ })
21
+
22
+ describe('button label store', () => {
23
+ it('keys on bot, chat and callback data, which is all a press carries', () => {
24
+ expect(buttonLabelKey('111', 999, 'pax_1')).toBe('111:999:pax_1')
25
+ expect(buttonLabelKey('111', '999', 'pax_1')).toBe('111:999:pax_1')
26
+ })
27
+
28
+ it('reads back a label written for that key', () => {
29
+ writeButtonLabels(dir, [{ key: buttonLabelKey('111', 999, 'pax_1'), label: '1 passenger' }])
30
+ expect(readButtonLabel(dir, buttonLabelKey('111', 999, 'pax_1'))).toBe('1 passenger')
31
+ })
32
+
33
+ it('returns null for a key never written', () => {
34
+ expect(readButtonLabel(dir, buttonLabelKey('111', 999, 'nope'))).toBeNull()
35
+ })
36
+
37
+ it('returns null past the ttl, and prunes it on the next write', () => {
38
+ const t0 = 1_000_000
39
+ const k = buttonLabelKey('111', 999, 'pax_1')
40
+ writeButtonLabels(dir, [{ key: k, label: '1 passenger' }], t0)
41
+ expect(readButtonLabel(dir, k, t0 + BUTTON_LABEL_TTL_MS)).toBeNull()
42
+ writeButtonLabels(dir, [{ key: buttonLabelKey('111', 999, 'pax_2'), label: '2 passengers' }], t0 + BUTTON_LABEL_TTL_MS)
43
+ const onDisk = JSON.parse(readFileSync(join(dir, 'telegram-button-labels.json'), 'utf-8')) as Record<string, unknown>
44
+ expect(Object.keys(onDisk)).toEqual(['111:999:pax_2'])
45
+ })
46
+
47
+ it('a later write for the same key replaces the label and refreshes its age', () => {
48
+ const t0 = 1_000_000
49
+ const k = buttonLabelKey('111', 999, 'pax_1')
50
+ writeButtonLabels(dir, [{ key: k, label: 'one' }], t0)
51
+ writeButtonLabels(dir, [{ key: k, label: 'ONE' }], t0 + 1)
52
+ expect(readButtonLabel(dir, k, t0 + 2)).toBe('ONE')
53
+ })
54
+
55
+ it('an unparseable file reads as no label and never throws', () => {
56
+ const path = join(dir, 'telegram-button-labels.json')
57
+ writeButtonLabels(dir, [{ key: 'a', label: 'b' }])
58
+ rmSync(path)
59
+ expect(readButtonLabel(dir, 'a')).toBeNull()
60
+ expect(existsSync(path)).toBe(false)
61
+ })
62
+
63
+ it('an empty entry list writes nothing, so a card with no buttons touches no file', () => {
64
+ writeButtonLabels(dir, [])
65
+ expect(existsSync(join(dir, 'telegram-button-labels.json'))).toBe(false)
66
+ })
67
+ })
@@ -0,0 +1,88 @@
1
+ // Task 2673 — what a button SAID, keyed by what a press CARRIES.
2
+ //
3
+ // A press delivers only its callback data, so an operator reading the
4
+ // conversation sees `[button: pax_1]` and not "1 passenger". The wording exists
5
+ // once, in the keyboard the card tool sent, and was never persisted.
6
+ //
7
+ // This is a shared platform library rather than a key inside the telegram MCP's
8
+ // own card store because the two sides live in different processes: the plugin
9
+ // writes it and the webhook route reads it, and the route imports from
10
+ // platform/lib and never from platform/plugins.
11
+ //
12
+ // Keyed on the callback data rather than the card key: the route holds botId,
13
+ // chatId and data, and never the caller's key.
14
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
15
+ import { join } from "node:path";
16
+
17
+ const FILE = "telegram-button-labels.json";
18
+
19
+ /** Matches CARD_TTL_MS in the telegram MCP's card store. A label outlives its
20
+ * card by no useful margin, and without a ceiling every callback data string
21
+ * ever sent is kept for ever. */
22
+ export const BUTTON_LABEL_TTL_MS = 7 * 24 * 60 * 60 * 1000;
23
+
24
+ interface LabelEntry {
25
+ label: string;
26
+ at: number;
27
+ }
28
+
29
+ function isEntry(v: unknown): v is LabelEntry {
30
+ if (!v || typeof v !== "object" || Array.isArray(v)) return false;
31
+ const e = v as Record<string, unknown>;
32
+ return typeof e.label === "string" && typeof e.at === "number" && Number.isFinite(e.at);
33
+ }
34
+
35
+ /** Scoped by bot AND chat, not by the data alone: two chats can use the same
36
+ * callback data for different words. */
37
+ export function buttonLabelKey(botId: string, chatId: string | number, data: string): string {
38
+ return `${botId}:${chatId}:${data}`;
39
+ }
40
+
41
+ function readAll(path: string): Record<string, LabelEntry> {
42
+ if (!existsSync(path)) return {};
43
+ try {
44
+ const parsed = JSON.parse(readFileSync(path, "utf-8")) as unknown;
45
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
46
+ const out: Record<string, LabelEntry> = {};
47
+ for (const [k, v] of Object.entries(parsed as Record<string, unknown>)) {
48
+ if (isEntry(v)) out[k] = v;
49
+ }
50
+ return out;
51
+ } catch {
52
+ // Unparseable state reads as "no label", which renders the raw data exactly
53
+ // as it did before this library existed. Throwing here would take a webhook
54
+ // down over a file no caller sees.
55
+ return {};
56
+ }
57
+ }
58
+
59
+ /** Record every button on one keyboard, and drop every entry gone
60
+ * BUTTON_LABEL_TTL_MS untouched. Compaction rides the write because the write
61
+ * already rewrites the whole file. An empty list writes nothing: a card with no
62
+ * buttons must not create the file. */
63
+ export function writeButtonLabels(
64
+ storeDir: string,
65
+ entries: Array<{ key: string; label: string }>,
66
+ now: number = Date.now(),
67
+ ): void {
68
+ if (entries.length === 0) return;
69
+ const path = join(storeDir, FILE);
70
+ const kept: Record<string, LabelEntry> = {};
71
+ for (const [key, entry] of Object.entries(readAll(path))) {
72
+ if (now - entry.at < BUTTON_LABEL_TTL_MS) kept[key] = entry;
73
+ }
74
+ for (const e of entries) kept[e.key] = { label: e.label, at: now };
75
+ writeFileSync(path, JSON.stringify(kept, null, 2) + "\n", "utf-8");
76
+ }
77
+
78
+ /** The stored wording for this key, or null. Null past the TTL, so a caller
79
+ * falls back to the raw data rather than showing a label for a card long gone. */
80
+ export function readButtonLabel(
81
+ storeDir: string,
82
+ key: string,
83
+ now: number = Date.now(),
84
+ ): string | null {
85
+ const entry = readAll(join(storeDir, FILE))[key];
86
+ if (!entry) return null;
87
+ return now - entry.at >= BUTTON_LABEL_TTL_MS ? null : entry.label;
88
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"],
8
+ "exclude": ["src/__tests__"]
9
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: "node",
6
+ globals: false,
7
+ include: ["src/__tests__/**/*.test.ts"],
8
+ },
9
+ });
@@ -10,8 +10,9 @@
10
10
  "pdf-lib": "^1.17.1"
11
11
  },
12
12
  "scripts": {
13
- "build": "tsc -p lib/account-schema-regions/tsconfig.json && tsc -p lib/account-ingest-token/tsconfig.json && tsc -p lib/models/tsconfig.json && tsc -p lib/agent-slug/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/shared-folder/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p lib/routine-templates/tsconfig.json && tsc -p lib/agent-dispatch-rule/tsconfig.json && tsc -p lib/canonical-instant/tsconfig.json && tsc -p lib/dispatch-read/tsconfig.json && tsc -p lib/dispatch-write/tsconfig.json && tsc -p lib/learning-constants/tsconfig.json && tsc -p lib/telegram-media/tsconfig.json && tsc -p lib/telegram-managed-bot/tsconfig.json && tsc -p lib/telegram-reach/tsconfig.json && tsc -p services/claude-session-manager/tsconfig.json && tsc -p services/whatsapp-channel/tsconfig.json && tsc -p services/webchat-channel/tsconfig.json && tsc -p services/telegram-channel/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
14
- "build:lib": "tsc -p lib/account-schema-regions/tsconfig.json && tsc -p lib/account-ingest-token/tsconfig.json && tsc -p lib/models/tsconfig.json && tsc -p lib/agent-slug/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/shared-folder/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p lib/routine-templates/tsconfig.json && tsc -p lib/agent-dispatch-rule/tsconfig.json && tsc -p lib/shared-folder/tsconfig.json && tsc -p lib/canonical-instant/tsconfig.json && tsc -p lib/dispatch-read/tsconfig.json && tsc -p lib/dispatch-write/tsconfig.json && tsc -p lib/telegram-media/tsconfig.json && tsc -p lib/telegram-managed-bot/tsconfig.json && tsc -p lib/telegram-reach/tsconfig.json",
13
+ "build": "tsc -p lib/account-schema-regions/tsconfig.json && tsc -p lib/account-ingest-token/tsconfig.json && tsc -p lib/models/tsconfig.json && tsc -p lib/agent-slug/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/shared-folder/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p lib/routine-templates/tsconfig.json && tsc -p lib/agent-dispatch-rule/tsconfig.json && tsc -p lib/canonical-instant/tsconfig.json && tsc -p lib/dispatch-read/tsconfig.json && tsc -p lib/dispatch-write/tsconfig.json && tsc -p lib/learning-constants/tsconfig.json && tsc -p lib/telegram-button-labels/tsconfig.json && tsc -p lib/telegram-media/tsconfig.json && tsc -p lib/telegram-managed-bot/tsconfig.json && tsc -p lib/telegram-reach/tsconfig.json && tsc -p services/claude-session-manager/tsconfig.json && tsc -p services/whatsapp-channel/tsconfig.json && tsc -p services/webchat-channel/tsconfig.json && tsc -p services/telegram-channel/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
14
+ "build:lib": "tsc -p lib/account-schema-regions/tsconfig.json && tsc -p lib/account-ingest-token/tsconfig.json && tsc -p lib/models/tsconfig.json && tsc -p lib/agent-slug/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/mcp-lifeline/tsconfig.json && tsc -p lib/mcp-eager/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/account-scope/tsconfig.json && tsc -p lib/shared-folder/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/ledger-core/tsconfig.json && tsc -p lib/embed-client/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/active-rules/tsconfig.json && tsc -p lib/admin-conversation-purge/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/graph-style/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/admin-access-password/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && tsc -p lib/require-port-env/tsconfig.json && tsc -p lib/aeo-llms-txt-writer/tsconfig.json && tsc -p lib/obsidian-parser/tsconfig.json && tsc -p lib/storage-broker/tsconfig.json && tsc -p lib/routine-templates/tsconfig.json && tsc -p lib/agent-dispatch-rule/tsconfig.json && tsc -p lib/shared-folder/tsconfig.json && tsc -p lib/canonical-instant/tsconfig.json && tsc -p lib/dispatch-read/tsconfig.json && tsc -p lib/dispatch-write/tsconfig.json && tsc -p lib/telegram-button-labels/tsconfig.json && tsc -p lib/telegram-media/tsconfig.json && tsc -p lib/telegram-managed-bot/tsconfig.json && tsc -p lib/telegram-reach/tsconfig.json",
15
+ "clean:dist": "node scripts/check-orphan-dist.mjs --remove",
15
16
  "gen:canonical-tools": "node scripts/generate-canonical-tool-names.mjs",
16
17
  "build:memory": "tsc -p plugins/memory/mcp/tsconfig.json",
17
18
  "build:contacts": "tsc -p plugins/contacts/mcp/tsconfig.json",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what Real Agent ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
- content-hash: sha256:c66d6d534933072b64b3b80ac132135ee30f82b6eb50a4a7950a6500cf0ca678
4
+ content-hash: sha256:4d7fafd7d648ca6953247a413d12dd0be25fd9e0c6876f1afb5ece48b1c0acdc
5
5
  brand: realagent-code
6
6
  product-name: Real Agent
7
7
  ---
@@ -2866,7 +2866,9 @@ Real Agent asks for your bot token, then asks what kind of bot this is:
2866
2866
 
2867
2867
  - an **admin bot** — only your numeric Telegram IDs may message it, and it answers as your admin agent;
2868
2868
  - a **public bot** — customer-facing, with a DM policy, answering as one of your account's agents;
2869
- - a **specialist bot** — bound to one of your own specialists, so messaging it runs that specialist with its own instructions and its own tools rather than your admin agent. You name the specialist and the numeric IDs allowed to reach it. Both are required: there is no open setting for this kind, because the specialist has real tools rather than the reply-only surface a public bot gets.
2869
+ - a **specialist bot** — bound to one of your own specialists, so messaging it runs that specialist with its own instructions and its own tools rather than your admin agent. You name the specialist and the numeric IDs allowed to reach it. Both are required: there is no open setting for this kind, because a specialist carries whatever tools its card gives it, while a public bot is held to a fixed set nobody can widen.
2870
+
2871
+ A public Telegram bot holds five things and nothing else: the reply that carries its answer, cards with tappable buttons, polls and quizzes and map pins, outgoing photos and documents and voice notes, and the ability to open a file a visitor sent it. That set is fixed by the platform for every public agent on every account, so there is no tools setting on an agent to turn any of it on or off. A public bot on webchat or WhatsApp still has the reply alone, because those channels ship no equivalent set.
2870
2872
 
2871
2873
  It verifies the token, registers the bot's webhook on your brand's edge, stores the token under your brand's config (never in a shared system directory), and sets whichever agent or specialist will answer. The bot is now connected.
2872
2874
 
@@ -3010,6 +3012,13 @@ nobody, and a vote was dropped without a trace. A press on a job-sheet card is t
3010
3012
  one exception: the dispatch plugin applies the change and tells the presser
3011
3013
  itself, so Real Agent does not answer a second time.
3012
3014
 
3015
+ A card carries its own words, so when Real Agent sends a card with buttons
3016
+ it puts the answer in the card itself and does not add a sentence beside it. On a
3017
+ public bot, that following sentence is held back on purpose, so the visitor sees
3018
+ the card once and not the same thing twice. And when someone presses a button,
3019
+ your conversation view shows the button's own wording — "1 passenger", "One way"
3020
+ — rather than the code behind it.
3021
+
3013
3022
  The same is now true of most of what Telegram sends. Reply to one of
3014
3023
  Real Agent's messages and it sees the message you replied to, so "yes, do
3015
3024
  that one" means something. React to a message with an emoji and it hears the
@@ -6455,7 +6464,7 @@ For subagents, the same spawn pushes `--add-dir` for every bundled plugin agents
6455
6464
 
6456
6465
  A boot gate refuses to start the manager when any admin-allowlisted tool `mcp__<plugin>__*` lacks a registered server. The signal is `boot-failed reason=mcp-allowlist-without-server plugin=<p> tool=<t>` followed by `process.exit(1)`. The remediation is a one-line edit to the named `PLUGIN.md`: add the `mcp:` block. The complementary observability emit `mcp-config-allowlist-coverage admin-tools=A admin-registered=R` (where `A === R`) confirms the invariant per boot.
6457
6466
 
6458
- **Whether a plugin's server mounts is decided by the generated manifest, not the `mcp:` block.** A plugin ships its MCP as `mcp/`; the manifest generator ([`scripts/generate-plugin-manifests.mjs`](../../../../scripts/generate-plugin-manifests.mjs), run at bundle time over the payload) reads the plugin's `mcp-manifest:` frontmatter. `auto` emits an `mcpServers` block into the generated `.claude-plugin/plugin.json` — routed through `lib/mcp-spawn-tee`, carrying no per-session env (`LOG_DIR`/`SESSION_ID`/`ACCOUNT_ID`/`NEO4J_*`/`PLATFORM_ROOT` ride the PTY env block described above) — and copies the tee into the plugin's `lib/`; `skip` emits nothing, so Claude Code never spawns the server. The generator recognises two server shapes. A plugin-local `mcp/` (its `hasMcp` check: `mcp/dist/index.js` or `mcp/package.json`) uses `auto` or `skip`. A tool-plugin whose `mcp:` server is a shared `platform/lib/<name>` binary rather than a plugin-local `mcp/` (e.g. `graph`, served by `platform/lib/graph-mcp`) is annotated `mcp-manifest: shared-lib`: the generator emits that plugin's `mcp:` block verbatim into `mcpServers` — command, args (anchored on `${PLATFORM_ROOT}`, routed through the shared `lib/mcp-spawn-tee`), and env — which Claude Code expands at spawn from the PTY env block. No tee copy is made into the plugin, because both the tee and the server resolve from `${PLATFORM_ROOT}` outside the per-plugin cache. `graph` is the one shared-lib tool-plugin; every other tool-plugin ships a plugin-local `mcp/` and uses `auto`. A plugin with an `mcp:` block, no plugin-local `mcp/`, and no `mcp-manifest: shared-lib` annotation is a FATAL at generation time. Premium plugins import platform libs (`mcp-lifeline`, etc.) via a source-tree relative path; the bundler's premium-lib shipper (`packages/create-maxy-code/scripts/bundle.js`) rewrites that path and vendors each referenced `platform/lib/<name>` into `premium-plugins/<bundle>/lib/<name>/`, so the auto-mounted dist resolves its imports. The `mcp-allowlist-without-server` gate above proves only that a plugin's PLUGIN.md `mcp:` block matches its allowlist — it reads source, not the generated manifest — so a plugin left on `skip` passes that gate while its server silently never mounts (its tools are listed but not live). The `tool-registration` gate below closes that blind spot.
6467
+ **Whether a plugin's server mounts is decided by the generated manifest, not the `mcp:` block.** A plugin ships its MCP as `mcp/`; the manifest generator ([`scripts/generate-plugin-manifests.mjs`](../../../../scripts/generate-plugin-manifests.mjs), run at bundle time over the payload) reads the plugin's `mcp-manifest:` frontmatter. `auto` emits an `mcpServers` block into the generated `.claude-plugin/plugin.json` — routed through `lib/mcp-spawn-tee`, carrying no per-session env (`LOG_DIR`/`SESSION_ID`/`ACCOUNT_ID`/`NEO4J_*`/`PLATFORM_ROOT` ride the PTY env block described above) — and copies the tee into the plugin's `lib/`; `skip` emits nothing, so Claude Code never spawns the server. `skip` covers two shapes: a plugin whose canonical surface is a user-scoped MCP, and a plugin that registers zero tools and keeps `mcp/` only as a test host — `cloudflare` is the latter, so its `skip` is not a pointer to a server elsewhere. The generator recognises two server shapes. A plugin-local `mcp/` (its `hasMcp` check: `mcp/dist/index.js` or `mcp/package.json`) uses `auto` or `skip`. A tool-plugin whose `mcp:` server is a shared `platform/lib/<name>` binary rather than a plugin-local `mcp/` (e.g. `graph`, served by `platform/lib/graph-mcp`) is annotated `mcp-manifest: shared-lib`: the generator emits that plugin's `mcp:` block verbatim into `mcpServers` — command, args (anchored on `${PLATFORM_ROOT}`, routed through the shared `lib/mcp-spawn-tee`), and env — which Claude Code expands at spawn from the PTY env block. No tee copy is made into the plugin, because both the tee and the server resolve from `${PLATFORM_ROOT}` outside the per-plugin cache. `graph` is the one shared-lib tool-plugin; every other tool-plugin ships a plugin-local `mcp/` and uses `auto`. A plugin with an `mcp:` block, no plugin-local `mcp/`, and no `mcp-manifest: shared-lib` annotation is a FATAL at generation time. Premium plugins import platform libs (`mcp-lifeline`, etc.) via a source-tree relative path; the bundler's premium-lib shipper (`packages/create-maxy-code/scripts/bundle.js`) rewrites that path and vendors each referenced `platform/lib/<name>` into `premium-plugins/<bundle>/lib/<name>/`, so the auto-mounted dist resolves its imports. The `mcp-allowlist-without-server` gate above proves only that a plugin's PLUGIN.md `mcp:` block matches its allowlist — it reads source, not the generated manifest — so a plugin left on `skip` passes that gate while its server silently never mounts (its tools are listed but not live). The `tool-registration` gate below closes that blind spot.
6459
6468
 
6460
6469
  A second boot gate walks every specialist `.md` under `platform/templates/specialists/agents/`, every bundled `<plugin>/agents/` directory, and the per-account `<accountDir>/specialists/agents/` directory, parses each file's `tools:` frontmatter line (canonical long-prefix names), and classifies every tool name as one of: CC-native (Read, Bash, …), a tool the loaded `PLUGIN.md` set actually serves (matched as the long canonical name in `toolSurface.all`), a third-party MCP bridge (a `mcp__plugin_*` name whose plugin segment is NOT a maxy platform plugin — Playwright etc., upstream-owned, passes unconditionally), `unknown-tool-in-plugin` (maxy plugin namespace served but tool name absent), `unknown-plugin-namespace` (namespace served by nothing), `brand-excluded-plugin` (namespace served by nothing on this brand, **but** the brand's `brand.json#plugins.excluded` list names it), or `malformed-name` (not CC-native and not `mcp__`-shaped). The first three pass. The next two refuse boot with one `boot-failed reason=specialist-tool-drift specialist=<name> tool=<t> drift=<class> path=<…>` line per defect, then `process.exit(1)`. A maxy-plugin `mcp__plugin_*` name is validated against `toolSurface.all`, so a typo or stale long-prefix tool name still refuses boot rather than passing as a bridge; the build-time `check-canonical-tool-names.mjs` gate catches the same drift in instruction files before publish. `brand-excluded-plugin` is a structural pass: it lands in a per-specialist strip-list, the manager continues to boot, and at spawn time `pty-spawner` removes those tool names from the `--agent <name>` spawn's `--allowed-tools` argv. The complementary observability emit `specialist-tool-strip specialist=<name> plugin=<p> tools=<csv> reason=brand-excluded` fires one line per stripped (specialist, plugin) pair so an operator who reads `server.log` sees the brand filter doing work without cross-referencing `brand.json` against the template. The startup-self-test line `startup-self-test specialist-tool-drift=ok inspected=<N> stripped-specialists=<M>` confirms the gate ran and how many specialists carry strip-lists.
6461
6470
 
@@ -9,6 +9,16 @@ Invoked by the admin agent directly.
9
9
 
10
10
  This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
11
11
 
12
+ ## 2026-08-11 (0.1.595)
13
+
14
+ - A Telegram bot no longer describes the card it just sent you. The card arrived and the bot then narrated it in a second message, because the rule that withholds that text never took effect.
15
+ - Pressing a button now reads as the button's own label rather than the code behind it. A standing check reports if card text stops being withheld again.
16
+
17
+ ## 2026-08-11 (0.1.594)
18
+
19
+ - A public Telegram bot no longer tells people it cannot do things it can. Its own description denied the tools it had actually been given, so it refused work it was equipped for.
20
+ - Code deleted from the platform no longer ships anyway. Removing a source file left its compiled output behind, so retired code was still being packaged and installed.
21
+
12
22
  ## 2026-08-11 (0.1.593)
13
23
 
14
24
  - A public Telegram bot can now use buttons, media and the rest of the channel. It held no tool at all, so every answer it gave was plain text.
@@ -28,6 +28,8 @@ Each installation has its own Cloudflare account. Two auth paths serve two opera
28
28
 
29
29
  The plugin registers no agent-facing MCP tools. Every Cloudflare operation is the agent invoking `cloudflared` or `wrangler` directly via Bash, or calling the Cloudflare API with a reused per-scope narrow token, with stdout/stderr streamed verbatim into the PTY chat (secrets redacted). The OAuth URL printed by `cloudflared tunnel login` is linkified by the native PTY; the operator clicks it in their own browser. The one shell helper is [bin/cf-token.sh](bin/cf-token.sh), a deterministic per-scope token resolver that faithfully relays the Cloudflare token API (it invents no flags and drives no dashboard); there is no wrapper around `cloudflared` or `wrangler`, no orchestrator state machine, no MCP-tool surface.
30
30
 
31
+ The frontmatter carries `mcp-manifest: skip` because the manifest generator requires an annotation from any plugin with an `mcp/` directory, and `skip` is the value that emits no `mcpServers` block. It does not mean the tools live in a user-scoped server somewhere else: there are none. `mcp/` survives only as the test host for `bin/` and for the skill templates' Pages Functions; its entry point registers nothing.
32
+
31
33
  ### Skills
32
34
 
33
35
  | Skill | Purpose |
@@ -501,7 +501,7 @@ For subagents, the same spawn pushes `--add-dir` for every bundled plugin agents
501
501
 
502
502
  A boot gate refuses to start the manager when any admin-allowlisted tool `mcp__<plugin>__*` lacks a registered server. The signal is `boot-failed reason=mcp-allowlist-without-server plugin=<p> tool=<t>` followed by `process.exit(1)`. The remediation is a one-line edit to the named `PLUGIN.md`: add the `mcp:` block. The complementary observability emit `mcp-config-allowlist-coverage admin-tools=A admin-registered=R` (where `A === R`) confirms the invariant per boot.
503
503
 
504
- **Whether a plugin's server mounts is decided by the generated manifest, not the `mcp:` block.** A plugin ships its MCP as `mcp/`; the manifest generator ([`scripts/generate-plugin-manifests.mjs`](../../../../scripts/generate-plugin-manifests.mjs), run at bundle time over the payload) reads the plugin's `mcp-manifest:` frontmatter. `auto` emits an `mcpServers` block into the generated `.claude-plugin/plugin.json` — routed through `lib/mcp-spawn-tee`, carrying no per-session env (`LOG_DIR`/`SESSION_ID`/`ACCOUNT_ID`/`NEO4J_*`/`PLATFORM_ROOT` ride the PTY env block described above) — and copies the tee into the plugin's `lib/`; `skip` emits nothing, so Claude Code never spawns the server. The generator recognises two server shapes. A plugin-local `mcp/` (its `hasMcp` check: `mcp/dist/index.js` or `mcp/package.json`) uses `auto` or `skip`. A tool-plugin whose `mcp:` server is a shared `platform/lib/<name>` binary rather than a plugin-local `mcp/` (e.g. `graph`, served by `platform/lib/graph-mcp`) is annotated `mcp-manifest: shared-lib`: the generator emits that plugin's `mcp:` block verbatim into `mcpServers` — command, args (anchored on `${PLATFORM_ROOT}`, routed through the shared `lib/mcp-spawn-tee`), and env — which Claude Code expands at spawn from the PTY env block. No tee copy is made into the plugin, because both the tee and the server resolve from `${PLATFORM_ROOT}` outside the per-plugin cache. `graph` is the one shared-lib tool-plugin; every other tool-plugin ships a plugin-local `mcp/` and uses `auto`. A plugin with an `mcp:` block, no plugin-local `mcp/`, and no `mcp-manifest: shared-lib` annotation is a FATAL at generation time. Premium plugins import platform libs (`mcp-lifeline`, etc.) via a source-tree relative path; the bundler's premium-lib shipper (`packages/create-maxy-code/scripts/bundle.js`) rewrites that path and vendors each referenced `platform/lib/<name>` into `premium-plugins/<bundle>/lib/<name>/`, so the auto-mounted dist resolves its imports. The `mcp-allowlist-without-server` gate above proves only that a plugin's PLUGIN.md `mcp:` block matches its allowlist — it reads source, not the generated manifest — so a plugin left on `skip` passes that gate while its server silently never mounts (its tools are listed but not live). The `tool-registration` gate below closes that blind spot.
504
+ **Whether a plugin's server mounts is decided by the generated manifest, not the `mcp:` block.** A plugin ships its MCP as `mcp/`; the manifest generator ([`scripts/generate-plugin-manifests.mjs`](../../../../scripts/generate-plugin-manifests.mjs), run at bundle time over the payload) reads the plugin's `mcp-manifest:` frontmatter. `auto` emits an `mcpServers` block into the generated `.claude-plugin/plugin.json` — routed through `lib/mcp-spawn-tee`, carrying no per-session env (`LOG_DIR`/`SESSION_ID`/`ACCOUNT_ID`/`NEO4J_*`/`PLATFORM_ROOT` ride the PTY env block described above) — and copies the tee into the plugin's `lib/`; `skip` emits nothing, so Claude Code never spawns the server. `skip` covers two shapes: a plugin whose canonical surface is a user-scoped MCP, and a plugin that registers zero tools and keeps `mcp/` only as a test host — `cloudflare` is the latter, so its `skip` is not a pointer to a server elsewhere. The generator recognises two server shapes. A plugin-local `mcp/` (its `hasMcp` check: `mcp/dist/index.js` or `mcp/package.json`) uses `auto` or `skip`. A tool-plugin whose `mcp:` server is a shared `platform/lib/<name>` binary rather than a plugin-local `mcp/` (e.g. `graph`, served by `platform/lib/graph-mcp`) is annotated `mcp-manifest: shared-lib`: the generator emits that plugin's `mcp:` block verbatim into `mcpServers` — command, args (anchored on `${PLATFORM_ROOT}`, routed through the shared `lib/mcp-spawn-tee`), and env — which Claude Code expands at spawn from the PTY env block. No tee copy is made into the plugin, because both the tee and the server resolve from `${PLATFORM_ROOT}` outside the per-plugin cache. `graph` is the one shared-lib tool-plugin; every other tool-plugin ships a plugin-local `mcp/` and uses `auto`. A plugin with an `mcp:` block, no plugin-local `mcp/`, and no `mcp-manifest: shared-lib` annotation is a FATAL at generation time. Premium plugins import platform libs (`mcp-lifeline`, etc.) via a source-tree relative path; the bundler's premium-lib shipper (`packages/create-maxy-code/scripts/bundle.js`) rewrites that path and vendors each referenced `platform/lib/<name>` into `premium-plugins/<bundle>/lib/<name>/`, so the auto-mounted dist resolves its imports. The `mcp-allowlist-without-server` gate above proves only that a plugin's PLUGIN.md `mcp:` block matches its allowlist — it reads source, not the generated manifest — so a plugin left on `skip` passes that gate while its server silently never mounts (its tools are listed but not live). The `tool-registration` gate below closes that blind spot.
505
505
 
506
506
  A second boot gate walks every specialist `.md` under `platform/templates/specialists/agents/`, every bundled `<plugin>/agents/` directory, and the per-account `<accountDir>/specialists/agents/` directory, parses each file's `tools:` frontmatter line (canonical long-prefix names), and classifies every tool name as one of: CC-native (Read, Bash, …), a tool the loaded `PLUGIN.md` set actually serves (matched as the long canonical name in `toolSurface.all`), a third-party MCP bridge (a `mcp__plugin_*` name whose plugin segment is NOT a maxy platform plugin — Playwright etc., upstream-owned, passes unconditionally), `unknown-tool-in-plugin` (maxy plugin namespace served but tool name absent), `unknown-plugin-namespace` (namespace served by nothing), `brand-excluded-plugin` (namespace served by nothing on this brand, **but** the brand's `brand.json#plugins.excluded` list names it), or `malformed-name` (not CC-native and not `mcp__`-shaped). The first three pass. The next two refuse boot with one `boot-failed reason=specialist-tool-drift specialist=<name> tool=<t> drift=<class> path=<…>` line per defect, then `process.exit(1)`. A maxy-plugin `mcp__plugin_*` name is validated against `toolSurface.all`, so a typo or stale long-prefix tool name still refuses boot rather than passing as a bridge; the build-time `check-canonical-tool-names.mjs` gate catches the same drift in instruction files before publish. `brand-excluded-plugin` is a structural pass: it lands in a per-specialist strip-list, the manager continues to boot, and at spawn time `pty-spawner` removes those tool names from the `--agent <name>` spawn's `--allowed-tools` argv. The complementary observability emit `specialist-tool-strip specialist=<name> plugin=<p> tools=<csv> reason=brand-excluded` fires one line per stripped (specialist, plugin) pair so an operator who reads `server.log` sees the brand filter doing work without cross-referencing `brand.json` against the template. The startup-self-test line `startup-self-test specialist-tool-drift=ok inspected=<N> stripped-specialists=<M>` confirms the gate ran and how many specialists carry strip-lists.
507
507
 
@@ -43,7 +43,9 @@ Tell {{productName}}: "Set up Telegram" or "Configure the Telegram bot." Setup r
43
43
 
44
44
  - an **admin bot** — only your numeric Telegram IDs may message it, and it answers as your admin agent;
45
45
  - a **public bot** — customer-facing, with a DM policy, answering as one of your account's agents;
46
- - a **specialist bot** — bound to one of your own specialists, so messaging it runs that specialist with its own instructions and its own tools rather than your admin agent. You name the specialist and the numeric IDs allowed to reach it. Both are required: there is no open setting for this kind, because the specialist has real tools rather than the reply-only surface a public bot gets.
46
+ - a **specialist bot** — bound to one of your own specialists, so messaging it runs that specialist with its own instructions and its own tools rather than your admin agent. You name the specialist and the numeric IDs allowed to reach it. Both are required: there is no open setting for this kind, because a specialist carries whatever tools its card gives it, while a public bot is held to a fixed set nobody can widen.
47
+
48
+ A public Telegram bot holds five things and nothing else: the reply that carries its answer, cards with tappable buttons, polls and quizzes and map pins, outgoing photos and documents and voice notes, and the ability to open a file a visitor sent it. That set is fixed by the platform for every public agent on every account, so there is no tools setting on an agent to turn any of it on or off. A public bot on webchat or WhatsApp still has the reply alone, because those channels ship no equivalent set.
47
49
 
48
50
  It verifies the token, registers the bot's webhook on your brand's edge, stores the token under your brand's config (never in a shared system directory), and sets whichever agent or specialist will answer. The bot is now connected.
49
51
 
@@ -187,6 +189,13 @@ nobody, and a vote was dropped without a trace. A press on a job-sheet card is t
187
189
  one exception: the dispatch plugin applies the change and tells the presser
188
190
  itself, so {{productName}} does not answer a second time.
189
191
 
192
+ A card carries its own words, so when {{productName}} sends a card with buttons
193
+ it puts the answer in the card itself and does not add a sentence beside it. On a
194
+ public bot, that following sentence is held back on purpose, so the visitor sees
195
+ the card once and not the same thing twice. And when someone presses a button,
196
+ your conversation view shows the button's own wording — "1 passenger", "One way"
197
+ — rather than the code behind it.
198
+
190
199
  The same is now true of most of what Telegram sends. Reply to one of
191
200
  {{productName}}'s messages and it sees the message you replied to, so "yes, do
192
201
  that one" means something. React to a message with an emoji and it hears the
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env bash
2
+ # Task 2671 — reconcile_all_accounts_identities converges every account's
3
+ # public-agent IDENTITY.md against the shipped template. The failure it exists
4
+ # for is silent: the re-sync it replaces ran for the house account alone, so a
5
+ # sub-account's agent kept a stale prompt indefinitely and nothing said so.
6
+ set -uo pipefail
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ PLAT_SCRIPTS="$SCRIPT_DIR/.."
9
+ PASS=0; FAIL=0; FAILED=()
10
+ assert_eq() { if [ "$1" = "$2" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILED+=("$3: expected [$2] got [$1]"); fi; }
11
+
12
+ . "$PLAT_SCRIPTS/lib/agent-identity-reconcile.sh"
13
+
14
+ T=$(mktemp -d)
15
+ TPL="$T/IDENTITY.md"
16
+ printf '# Public Agent\n\nShipped text.\n' > "$TPL"
17
+ export MAXY_PUBLIC_IDENTITY_TEMPLATE="$TPL"
18
+
19
+ seed_account() {
20
+ # seed_account <accounts_dir> <account_id>
21
+ local root="$1/$2"
22
+ mkdir -p "$root/agents"
23
+ printf '{"accountId":"%s"}\n' "$2" > "$root/account.json"
24
+ echo "$root"
25
+ }
26
+ seed_agent() {
27
+ # seed_agent <account_root> <slug> <body>
28
+ mkdir -p "$1/agents/$2"
29
+ printf '%s' "$3" > "$1/agents/$2/IDENTITY.md"
30
+ }
31
+
32
+ ACCTS="$T/accounts"
33
+ A1="$(seed_account "$ACCTS" aaaaaaaa-0000-0000-0000-000000000001)"
34
+ A2="$(seed_account "$ACCTS" bbbbbbbb-0000-0000-0000-000000000002)"
35
+
36
+ seed_agent "$A1" beagle 'STALE — you have no tools.'
37
+ seed_agent "$A1" admin 'ADMIN identity, never touched.'
38
+ seed_agent "$A1" passive 'PASSIVE identity, never touched.'
39
+ # Byte-identical to the template, so `cp` rather than a command substitution:
40
+ # `$(cat …)` strips the trailing newline and the copy would read as drift.
41
+ mkdir -p "$A2/agents/fares" && cp "$TPL" "$A2/agents/fares/IDENTITY.md"
42
+ # An agent dir with no IDENTITY.md: counted by nothing, created by nothing.
43
+ mkdir -p "$A2/agents/halfmade"
44
+ # A dir with no account.json is not an account.
45
+ mkdir -p "$ACCTS/not-an-account/agents"
46
+
47
+ OUT1="$(reconcile_all_accounts_identities "$ACCTS" 2>&1)"; RC1=$?
48
+
49
+ assert_eq "$RC1" "0" "clean-run-exit-zero"
50
+ assert_eq "$(printf '%s' "$OUT1" | grep -c 'accounts=2 agents=2 divergent=1')" "1" "summary-counts"
51
+ assert_eq "$(cat "$A1/agents/beagle/IDENTITY.md")" "$(cat "$TPL")" "stale-rewritten"
52
+ assert_eq "$(cat "$A1/agents/admin/IDENTITY.md")" "ADMIN identity, never touched." "admin-skipped"
53
+ assert_eq "$(cat "$A1/agents/passive/IDENTITY.md")" "PASSIVE identity, never touched." "passive-skipped"
54
+ assert_eq "$(printf '%s' "$OUT1" | grep -c 'agent=beagle status=updated')" "1" "stale-logged-updated"
55
+ assert_eq "$(printf '%s' "$OUT1" | grep -c 'agent=fares status=already-current')" "1" "current-logged-current"
56
+ assert_eq "$(printf '%s' "$OUT1" | grep -c 'agent=admin\|agent=passive\|agent=halfmade')" "0" "excluded-not-logged"
57
+ assert_eq "$([ -e "$A2/agents/halfmade/IDENTITY.md" ] && echo yes || echo no)" "no" "never-creates"
58
+
59
+ # Second run: same agent count, nothing left divergent. A zero that follows a
60
+ # non-zero is the only zero that proves the pass runs — `divergent=0` on its own
61
+ # is what a stopped counter prints too.
62
+ OUT2="$(reconcile_all_accounts_identities "$ACCTS" 2>&1)"; RC2=$?
63
+ assert_eq "$RC2" "0" "idempotent-exit-zero"
64
+ assert_eq "$(printf '%s' "$OUT2" | grep -c 'accounts=2 agents=2 divergent=0')" "1" "idempotent-summary"
65
+
66
+ # Missing template: reported per agent, counted divergent, never fatal, and the
67
+ # agent's file is left exactly as it was rather than truncated.
68
+ export MAXY_PUBLIC_IDENTITY_TEMPLATE="$T/absent.md"
69
+ BEFORE="$(cat "$A1/agents/beagle/IDENTITY.md")"
70
+ OUT3="$(reconcile_all_accounts_identities "$ACCTS" 2>&1)"; RC3=$?
71
+ assert_eq "$RC3" "0" "no-template-not-fatal"
72
+ assert_eq "$(printf '%s' "$OUT3" | grep -c 'status=no-template')" "2" "no-template-logged-per-agent"
73
+ assert_eq "$(printf '%s' "$OUT3" | grep -c 'accounts=2 agents=2 divergent=2')" "1" "no-template-counted-divergent"
74
+ assert_eq "$(cat "$A1/agents/beagle/IDENTITY.md")" "$BEFORE" "no-template-leaves-file"
75
+
76
+ # An empty destination after a copy aborts the install: that state traps the
77
+ # brand server in STARTING and was observed on a live device.
78
+ export MAXY_PUBLIC_IDENTITY_TEMPLATE="$TPL"
79
+ printf 'drifted again' > "$A1/agents/beagle/IDENTITY.md"
80
+ CP_STUB="$T/bin"; mkdir -p "$CP_STUB"
81
+ printf '#!/usr/bin/env bash\n: > "${@: -1}"\nexit 0\n' > "$CP_STUB/cp"; chmod +x "$CP_STUB/cp"
82
+ OUT4="$(PATH="$CP_STUB:$PATH" reconcile_all_accounts_identities "$ACCTS" 2>&1)"; RC4=$?
83
+ assert_eq "$RC4" "1" "empty-copy-is-fatal"
84
+ assert_eq "$(printf '%s' "$OUT4" | grep -c 'status=empty-after-copy')" "1" "empty-copy-logged"
85
+ assert_eq "$(printf '%s' "$OUT4" | grep -c 'FATAL')" "1" "empty-copy-fatal-line"
86
+
87
+ # setup-account.sh runs under `set -euo pipefail`, and the reconciler is called
88
+ # there as a bare command. A non-zero from any per-agent call therefore kills the
89
+ # whole install, and it kills it on exactly the runs that had work to do — the
90
+ # ones where an agent diverged. Reproduced before the fix: the summary line never
91
+ # printed and the sourcing shell exited 1 after the first `status=updated`.
92
+ export MAXY_PUBLIC_IDENTITY_TEMPLATE="$TPL"
93
+ printf 'drifted under set -e' > "$A1/agents/beagle/IDENTITY.md"
94
+ OUT5="$(bash -c '
95
+ set -euo pipefail
96
+ . "'"$PLAT_SCRIPTS"'/lib/agent-identity-reconcile.sh"
97
+ reconcile_all_accounts_identities "'"$ACCTS"'"
98
+ echo REACHED-END' 2>&1)"; RC5=$?
99
+ assert_eq "$RC5" "0" "set-e-does-not-abort"
100
+ assert_eq "$(printf '%s' "$OUT5" | grep -c 'REACHED-END')" "1" "set-e-reaches-end"
101
+ assert_eq "$(printf '%s' "$OUT5" | grep -c 'accounts=2 agents=2 divergent=1')" "1" "set-e-summary-printed"
102
+
103
+ rm -rf "$T"
104
+
105
+ if [ "$FAIL" -gt 0 ]; then
106
+ printf 'FAIL %d, PASS %d\n' "$FAIL" "$PASS"
107
+ printf ' %s\n' "${FAILED[@]}"
108
+ exit 1
109
+ fi
110
+ printf 'PASS %d\n' "$PASS"