@llblab/pi-kit 0.12.1 → 0.14.0

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 (299) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -2
  3. package/node_modules/@llblab/pi-state-flow/AGENTS.md +7 -7
  4. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +8 -9
  5. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +26 -0
  6. package/node_modules/@llblab/pi-state-flow/README.md +1 -3
  7. package/node_modules/@llblab/pi-state-flow/dist/index.d.ts +21 -0
  8. package/node_modules/@llblab/pi-state-flow/dist/index.js +20 -0
  9. package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.d.ts +39 -0
  10. package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.js +78 -0
  11. package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.d.ts +110 -0
  12. package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.js +334 -0
  13. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.d.ts +49 -0
  14. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.js +67 -0
  15. package/node_modules/@llblab/pi-state-flow/dist/lib/config.d.ts +11 -0
  16. package/node_modules/@llblab/pi-state-flow/dist/lib/config.js +53 -0
  17. package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +23 -0
  18. package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +109 -0
  19. package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.d.ts +111 -0
  20. package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +189 -0
  21. package/node_modules/@llblab/pi-state-flow/dist/lib/discovery.d.ts +21 -0
  22. package/node_modules/@llblab/pi-state-flow/dist/lib/discovery.js +125 -0
  23. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.d.ts +102 -0
  24. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +507 -0
  25. package/node_modules/@llblab/pi-state-flow/dist/lib/episode.d.ts +8 -0
  26. package/node_modules/@llblab/pi-state-flow/dist/lib/episode.js +27 -0
  27. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.d.ts +22 -0
  28. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +1263 -0
  29. package/node_modules/@llblab/pi-state-flow/dist/lib/git.d.ts +72 -0
  30. package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +565 -0
  31. package/node_modules/@llblab/pi-state-flow/dist/lib/history.d.ts +22 -0
  32. package/node_modules/@llblab/pi-state-flow/dist/lib/history.js +79 -0
  33. package/node_modules/@llblab/pi-state-flow/dist/lib/json.d.ts +12 -0
  34. package/node_modules/@llblab/pi-state-flow/dist/lib/json.js +109 -0
  35. package/node_modules/@llblab/pi-state-flow/dist/lib/logging.d.ts +25 -0
  36. package/node_modules/@llblab/pi-state-flow/dist/lib/logging.js +24 -0
  37. package/node_modules/@llblab/pi-state-flow/dist/lib/maintenance.d.ts +36 -0
  38. package/node_modules/@llblab/pi-state-flow/dist/lib/maintenance.js +98 -0
  39. package/node_modules/@llblab/pi-state-flow/dist/lib/memory.d.ts +15 -0
  40. package/node_modules/@llblab/pi-state-flow/dist/lib/memory.js +42 -0
  41. package/node_modules/@llblab/pi-state-flow/dist/lib/migration.d.ts +13 -0
  42. package/node_modules/@llblab/pi-state-flow/dist/lib/migration.js +133 -0
  43. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +7 -0
  44. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +59 -0
  45. package/node_modules/@llblab/pi-state-flow/dist/lib/publication.d.ts +69 -0
  46. package/node_modules/@llblab/pi-state-flow/dist/lib/publication.js +335 -0
  47. package/node_modules/@llblab/pi-state-flow/dist/lib/query.d.ts +27 -0
  48. package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +35 -0
  49. package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.d.ts +8 -0
  50. package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.js +27 -0
  51. package/node_modules/@llblab/pi-state-flow/dist/lib/rehydration.d.ts +36 -0
  52. package/node_modules/@llblab/pi-state-flow/dist/lib/rehydration.js +38 -0
  53. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +142 -0
  54. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +529 -0
  55. package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +21 -0
  56. package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +44 -0
  57. package/node_modules/@llblab/pi-state-flow/dist/lib/skills.d.ts +25 -0
  58. package/node_modules/@llblab/pi-state-flow/dist/lib/skills.js +131 -0
  59. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +88 -0
  60. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +255 -0
  61. package/node_modules/@llblab/pi-state-flow/dist/lib/state.d.ts +55 -0
  62. package/node_modules/@llblab/pi-state-flow/dist/lib/state.js +31 -0
  63. package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +38 -0
  64. package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +79 -0
  65. package/node_modules/@llblab/pi-state-flow/dist/lib/storage.d.ts +46 -0
  66. package/node_modules/@llblab/pi-state-flow/dist/lib/storage.js +217 -0
  67. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +98 -0
  68. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +231 -0
  69. package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.d.ts +39 -0
  70. package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.js +203 -0
  71. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.d.ts +25 -0
  72. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +204 -0
  73. package/node_modules/@llblab/pi-state-flow/dist/package.json +79 -0
  74. package/node_modules/@llblab/pi-state-flow/dist/pi-state-flow/index.js +1 -0
  75. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +138 -0
  76. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +11 -5
  77. package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +5 -1
  78. package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +3 -3
  79. package/node_modules/@llblab/pi-state-flow/docs/usage.md +6 -4
  80. package/node_modules/@llblab/pi-state-flow/index.ts +1 -0
  81. package/node_modules/@llblab/pi-state-flow/lib/compaction.ts +17 -1
  82. package/node_modules/@llblab/pi-state-flow/lib/config.ts +6 -1
  83. package/node_modules/@llblab/pi-state-flow/lib/durable.ts +88 -96
  84. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +64 -12
  85. package/node_modules/@llblab/pi-state-flow/lib/git.ts +32 -188
  86. package/node_modules/@llblab/pi-state-flow/lib/migration.ts +84 -48
  87. package/node_modules/@llblab/pi-state-flow/lib/query.ts +40 -0
  88. package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +7 -30
  89. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +48 -50
  90. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +41 -97
  91. package/node_modules/@llblab/pi-state-flow/lib/storage.ts +17 -12
  92. package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +4 -4
  93. package/node_modules/@llblab/pi-state-flow/package.json +23 -6
  94. package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +3 -1
  95. package/node_modules/@llblab/pi-telegram/AGENTS.md +5 -3
  96. package/node_modules/@llblab/pi-telegram/BACKLOG.md +0 -6
  97. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +22 -0
  98. package/node_modules/@llblab/pi-telegram/README.md +6 -3
  99. package/node_modules/@llblab/pi-telegram/dist/api/activity.d.ts +6 -0
  100. package/node_modules/@llblab/pi-telegram/dist/api/activity.js +6 -0
  101. package/node_modules/@llblab/pi-telegram/dist/api/commands.d.ts +6 -0
  102. package/node_modules/@llblab/pi-telegram/dist/api/commands.js +6 -0
  103. package/node_modules/@llblab/pi-telegram/dist/api/delivery.d.ts +6 -0
  104. package/node_modules/@llblab/pi-telegram/dist/api/delivery.js +6 -0
  105. package/node_modules/@llblab/pi-telegram/dist/api/inbound.d.ts +6 -0
  106. package/node_modules/@llblab/pi-telegram/dist/api/inbound.js +6 -0
  107. package/node_modules/@llblab/pi-telegram/dist/api/keyboard.d.ts +6 -0
  108. package/node_modules/@llblab/pi-telegram/dist/api/keyboard.js +6 -0
  109. package/node_modules/@llblab/pi-telegram/dist/api/outbound.d.ts +6 -0
  110. package/node_modules/@llblab/pi-telegram/dist/api/outbound.js +6 -0
  111. package/node_modules/@llblab/pi-telegram/dist/api/sections.d.ts +7 -0
  112. package/node_modules/@llblab/pi-telegram/dist/api/sections.js +6 -0
  113. package/node_modules/@llblab/pi-telegram/dist/api/status.d.ts +6 -0
  114. package/node_modules/@llblab/pi-telegram/dist/api/status.js +6 -0
  115. package/node_modules/@llblab/pi-telegram/dist/api/updates.d.ts +6 -0
  116. package/node_modules/@llblab/pi-telegram/dist/api/updates.js +6 -0
  117. package/node_modules/@llblab/pi-telegram/dist/api/voice.d.ts +6 -0
  118. package/node_modules/@llblab/pi-telegram/dist/api/voice.js +6 -0
  119. package/node_modules/@llblab/pi-telegram/dist/index.d.ts +6 -0
  120. package/node_modules/@llblab/pi-telegram/dist/index.js +6 -0
  121. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +52 -0
  122. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +596 -0
  123. package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +220 -0
  124. package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +574 -0
  125. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.d.ts +28 -0
  126. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.js +86 -0
  127. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +250 -0
  128. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +936 -0
  129. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.d.ts +18 -0
  130. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +254 -0
  131. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +464 -0
  132. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +1689 -0
  133. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +292 -0
  134. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +2242 -0
  135. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.d.ts +64 -0
  136. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +140 -0
  137. package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +518 -0
  138. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +2055 -0
  139. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +170 -0
  140. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +611 -0
  141. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +70 -0
  142. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +744 -0
  143. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +541 -0
  144. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +1155 -0
  145. package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +252 -0
  146. package/node_modules/@llblab/pi-telegram/dist/lib/config.js +889 -0
  147. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +163 -0
  148. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +542 -0
  149. package/node_modules/@llblab/pi-telegram/dist/lib/extension.d.ts +7 -0
  150. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +1604 -0
  151. package/node_modules/@llblab/pi-telegram/dist/lib/generative-app-worker.mjs +104 -0
  152. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +212 -0
  153. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.js +1006 -0
  154. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +91 -0
  155. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +502 -0
  156. package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +665 -0
  157. package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +3701 -0
  158. package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.d.ts +23 -0
  159. package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.js +37 -0
  160. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +157 -0
  161. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +395 -0
  162. package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +164 -0
  163. package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +1208 -0
  164. package/node_modules/@llblab/pi-telegram/dist/lib/logging.d.ts +50 -0
  165. package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +274 -0
  166. package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +181 -0
  167. package/node_modules/@llblab/pi-telegram/dist/lib/media.js +602 -0
  168. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +217 -0
  169. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +663 -0
  170. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.d.ts +37 -0
  171. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.js +408 -0
  172. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +115 -0
  173. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +595 -0
  174. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +32 -0
  175. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +112 -0
  176. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +29 -0
  177. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +82 -0
  178. package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +171 -0
  179. package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +323 -0
  180. package/node_modules/@llblab/pi-telegram/dist/lib/model.d.ts +127 -0
  181. package/node_modules/@llblab/pi-telegram/dist/lib/model.js +409 -0
  182. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +241 -0
  183. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +639 -0
  184. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.d.ts +69 -0
  185. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +248 -0
  186. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +42 -0
  187. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +678 -0
  188. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.d.ts +55 -0
  189. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.js +152 -0
  190. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +185 -0
  191. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +516 -0
  192. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.d.ts +77 -0
  193. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.js +174 -0
  194. package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +40 -0
  195. package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +94 -0
  196. package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +72 -0
  197. package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +121 -0
  198. package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +351 -0
  199. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +1196 -0
  200. package/node_modules/@llblab/pi-telegram/dist/lib/preview.d.ts +192 -0
  201. package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +614 -0
  202. package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.d.ts +24 -0
  203. package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.js +118 -0
  204. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.d.ts +57 -0
  205. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.js +167 -0
  206. package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +766 -0
  207. package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +1965 -0
  208. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +86 -0
  209. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +285 -0
  210. package/node_modules/@llblab/pi-telegram/dist/lib/rendering.d.ts +20 -0
  211. package/node_modules/@llblab/pi-telegram/dist/lib/rendering.js +983 -0
  212. package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +214 -0
  213. package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +737 -0
  214. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +207 -0
  215. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +2282 -0
  216. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +172 -0
  217. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.js +402 -0
  218. package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +165 -0
  219. package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +327 -0
  220. package/node_modules/@llblab/pi-telegram/dist/lib/setup.d.ts +82 -0
  221. package/node_modules/@llblab/pi-telegram/dist/lib/setup.js +150 -0
  222. package/node_modules/@llblab/pi-telegram/dist/lib/skills.d.ts +8 -0
  223. package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +12 -0
  224. package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +442 -0
  225. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +1000 -0
  226. package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +179 -0
  227. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +782 -0
  228. package/node_modules/@llblab/pi-telegram/dist/lib/target.d.ts +20 -0
  229. package/node_modules/@llblab/pi-telegram/dist/lib/target.js +27 -0
  230. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +541 -0
  231. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +1159 -0
  232. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.d.ts +89 -0
  233. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.js +317 -0
  234. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +288 -0
  235. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +560 -0
  236. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +46 -0
  237. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +257 -0
  238. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +46 -0
  239. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +78 -0
  240. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +239 -0
  241. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +644 -0
  242. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +621 -0
  243. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +3679 -0
  244. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.d.ts +15 -0
  245. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.js +56 -0
  246. package/node_modules/@llblab/pi-telegram/dist/lib/turns.d.ts +109 -0
  247. package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +500 -0
  248. package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +1290 -0
  249. package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +3634 -0
  250. package/node_modules/@llblab/pi-telegram/dist/lib/voice.d.ts +117 -0
  251. package/node_modules/@llblab/pi-telegram/dist/lib/voice.js +174 -0
  252. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +264 -0
  253. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +1136 -0
  254. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +219 -0
  255. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +587 -0
  256. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.d.ts +30 -0
  257. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.js +54 -0
  258. package/node_modules/@llblab/pi-telegram/dist/package.json +126 -0
  259. package/node_modules/@llblab/pi-telegram/dist/pi-telegram/index.js +1 -0
  260. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/SKILL.md +107 -0
  261. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/references/capability-adapters.md +27 -0
  262. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/references/layout-and-state.md +37 -0
  263. package/node_modules/@llblab/pi-telegram/dist/skills/generative-apps/SKILL.md +115 -0
  264. package/node_modules/@llblab/pi-telegram/dist/skills/show-me/SKILL.md +166 -0
  265. package/node_modules/@llblab/pi-telegram/dist/skills/show-me/references/telegram-surfaces.md +43 -0
  266. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/SKILL.md +129 -0
  267. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/configuration.md +15 -0
  268. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/delivery-and-threads.md +27 -0
  269. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/diagnosis.md +18 -0
  270. package/node_modules/@llblab/pi-telegram/docs/README.md +2 -0
  271. package/node_modules/@llblab/pi-telegram/docs/architecture.md +4 -2
  272. package/node_modules/@llblab/pi-telegram/docs/compact-matrix-literal.md +10 -3
  273. package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +15 -13
  274. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +6 -4
  275. package/node_modules/@llblab/pi-telegram/docs/outbound.md +1 -1
  276. package/node_modules/@llblab/pi-telegram/docs/public-api.md +3 -3
  277. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +89 -6
  278. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +12 -5
  279. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +44 -19
  280. package/node_modules/@llblab/pi-telegram/lib/bus.ts +4 -1
  281. package/node_modules/@llblab/pi-telegram/lib/commands.ts +2 -2
  282. package/node_modules/@llblab/pi-telegram/lib/config.ts +14 -7
  283. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +38 -6
  284. package/node_modules/@llblab/pi-telegram/lib/extension.ts +7 -0
  285. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +379 -13
  286. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +20 -6
  287. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +16 -7
  288. package/node_modules/@llblab/pi-telegram/lib/status.ts +9 -15
  289. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +12 -1
  290. package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +96 -18
  291. package/node_modules/@llblab/pi-telegram/package.json +56 -13
  292. package/node_modules/@llblab/pi-telegram/scripts/build-dist.mjs +44 -0
  293. package/node_modules/@llblab/pi-telegram/scripts/measure-bus.mjs +8 -1
  294. package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +8 -1
  295. package/node_modules/@llblab/pi-telegram/skills/generative-apps/SKILL.md +1 -1
  296. package/node_modules/@llblab/pi-telegram/skills/show-me/SKILL.md +1 -1
  297. package/node_modules/@llblab/pi-telegram/skills/show-me/references/telegram-surfaces.md +1 -1
  298. package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/SKILL.md +1 -1
  299. package/package.json +7 -7
@@ -0,0 +1,1000 @@
1
+ /**
2
+ * Telegram status rendering helpers
3
+ * Zones: telegram ui, pi agent diagnostics, tui
4
+ * Builds usage, cost, and context summaries for the interactive Telegram status view
5
+ */
6
+ const TELEGRAM_STATUS_DEFAULT_PROFILE_NAME = "default";
7
+ const TELEGRAM_STATUS_LINE_PROVIDER_REGISTRY_KEY = "__piTelegramStatusLineProviders__";
8
+ const MAX_RECENT_TELEGRAM_RUNTIME_EVENTS = 10;
9
+ const MAX_TELEGRAM_RUNTIME_EVENT_MESSAGE_LENGTH = 1000;
10
+ const MAX_TELEGRAM_RUNTIME_EVENT_DETAIL_LENGTH = 1000;
11
+ /**
12
+ * Project a config store into the status view without moving token-reference
13
+ * resolution into this structural leaf domain.
14
+ */
15
+ export function createTelegramBridgeStatusConfigGetter(source) {
16
+ return () => {
17
+ const config = source.get();
18
+ return {
19
+ ...config,
20
+ ...(source.hasBotToken ? { botHasToken: source.hasBotToken() } : {}),
21
+ ...(source.getBotTokenDiagnostic
22
+ ? { botTokenDiagnostic: source.getBotTokenDiagnostic() }
23
+ : {}),
24
+ };
25
+ };
26
+ }
27
+ function truncateTelegramRuntimeEventText(text, maxLength) {
28
+ if (text.length <= maxLength)
29
+ return text;
30
+ return `${text.slice(0, maxLength).trimEnd()}… [truncated ${text.length - maxLength} chars]`;
31
+ }
32
+ export function redactTelegramRuntimeMessage(message, botToken) {
33
+ const redacted = botToken
34
+ ? message.split(botToken).join("<redacted-token>")
35
+ : message;
36
+ return truncateTelegramRuntimeEventText(redacted, MAX_TELEGRAM_RUNTIME_EVENT_MESSAGE_LENGTH);
37
+ }
38
+ function redactTelegramRuntimeDetail(message, botToken) {
39
+ const redacted = botToken
40
+ ? message.split(botToken).join("<redacted-token>")
41
+ : message;
42
+ return truncateTelegramRuntimeEventText(redacted, MAX_TELEGRAM_RUNTIME_EVENT_DETAIL_LENGTH);
43
+ }
44
+ function normalizeTelegramRuntimeEventDetails(details, botToken) {
45
+ if (!details)
46
+ return undefined;
47
+ const normalized = {};
48
+ for (const [key, value] of Object.entries(details)) {
49
+ if (value === undefined)
50
+ continue;
51
+ if (typeof value === "string") {
52
+ normalized[key] = redactTelegramRuntimeDetail(value, botToken);
53
+ continue;
54
+ }
55
+ if (typeof value === "number" || typeof value === "boolean") {
56
+ normalized[key] = value;
57
+ continue;
58
+ }
59
+ if (value === null) {
60
+ normalized[key] = null;
61
+ continue;
62
+ }
63
+ normalized[key] = redactTelegramRuntimeDetail(String(value), botToken);
64
+ }
65
+ return Object.keys(normalized).length > 0 ? normalized : undefined;
66
+ }
67
+ function getTelegramRuntimeEventMessage(input) {
68
+ if (input.message !== undefined)
69
+ return input.message;
70
+ if (input.error instanceof Error)
71
+ return input.error.message;
72
+ return String(input.error);
73
+ }
74
+ export function recordStructuredTelegramRuntimeEvent(events, input, options) {
75
+ const details = normalizeTelegramRuntimeEventDetails(input.details, options.botToken);
76
+ events.push({
77
+ at: options.now ?? Date.now(),
78
+ category: input.category,
79
+ message: redactTelegramRuntimeMessage(getTelegramRuntimeEventMessage(input), options.botToken),
80
+ ...(details ? { details } : {}),
81
+ });
82
+ while (events.length > options.maxEvents) {
83
+ events.shift();
84
+ }
85
+ }
86
+ function getOrCreateTelegramStatusLineProviderRegistry() {
87
+ const existing = globalThis[TELEGRAM_STATUS_LINE_PROVIDER_REGISTRY_KEY];
88
+ if (existing instanceof Map)
89
+ return existing;
90
+ const registry = new Map();
91
+ globalThis[TELEGRAM_STATUS_LINE_PROVIDER_REGISTRY_KEY] = registry;
92
+ return registry;
93
+ }
94
+ /**
95
+ * Register a compact extension-provided line for the Telegram status menu.
96
+ *
97
+ * Providers are synchronous and should return undefined when their line is not
98
+ * relevant for the active model. Errors are isolated so optional extension
99
+ * status cannot break the core Telegram menu.
100
+ */
101
+ export function registerTelegramStatusLineProvider(provider, options) {
102
+ const registry = getOrCreateTelegramStatusLineProviderRegistry();
103
+ registry.set(options.id, provider);
104
+ return () => {
105
+ if (registry.get(options.id) === provider)
106
+ registry.delete(options.id);
107
+ };
108
+ }
109
+ export function getTelegramStatusLineProviderResults(ctx) {
110
+ const results = [];
111
+ const registry = getOrCreateTelegramStatusLineProviderRegistry();
112
+ for (const provider of registry.values()) {
113
+ try {
114
+ const result = provider(ctx);
115
+ if (!result?.label || !result.value)
116
+ continue;
117
+ results.push(result);
118
+ }
119
+ catch {
120
+ continue;
121
+ }
122
+ }
123
+ return results;
124
+ }
125
+ export function clearTelegramStatusLineProviders() {
126
+ getOrCreateTelegramStatusLineProviderRegistry().clear();
127
+ }
128
+ export function createTelegramRuntimeEventRecorder(options) {
129
+ const events = [];
130
+ return {
131
+ record: (category, error, details) => {
132
+ recordStructuredTelegramRuntimeEvent(events, { category, error, details }, {
133
+ botToken: options.getBotToken(),
134
+ maxEvents: options.maxEvents ?? MAX_RECENT_TELEGRAM_RUNTIME_EVENTS,
135
+ now: options.now?.(),
136
+ });
137
+ },
138
+ getEvents: () => events,
139
+ clear: () => {
140
+ events.length = 0;
141
+ },
142
+ };
143
+ }
144
+ function formatTelegramRuntimeEventCategory(event) {
145
+ const method = event.details?.method;
146
+ return typeof method === "string"
147
+ ? `${event.category}:${method}`
148
+ : event.category;
149
+ }
150
+ function formatTelegramRuntimeEventDetails(event) {
151
+ if (!event.details)
152
+ return "";
153
+ const details = Object.entries(event.details)
154
+ .filter(([key]) => key !== "method")
155
+ .map(([key, value]) => `${key}=${JSON.stringify(value)}`);
156
+ return details.length > 0 ? ` (${details.join(", ")})` : "";
157
+ }
158
+ function formatTelegramRuntimeEventSummary(event) {
159
+ return `${formatTelegramRuntimeEventCategory(event)}: ${event.message}${formatTelegramRuntimeEventDetails(event)}`;
160
+ }
161
+ function formatTelegramRuntimeEvent(event) {
162
+ return `${new Date(event.at).toISOString()} ${formatTelegramRuntimeEventSummary(event)}`;
163
+ }
164
+ function buildTelegramRuntimeEventSummary(events) {
165
+ const counts = new Map();
166
+ for (const event of events) {
167
+ const category = formatTelegramRuntimeEventCategory(event);
168
+ counts.set(category, (counts.get(category) ?? 0) + 1);
169
+ }
170
+ return Array.from(counts.entries())
171
+ .sort(([left], [right]) => left.localeCompare(right))
172
+ .map(([category, count]) => `${category}=${count}`)
173
+ .join(", ");
174
+ }
175
+ export function buildTelegramRuntimeEventLines(events) {
176
+ if (events.length === 0)
177
+ return ["recent runtime events: none"];
178
+ return [
179
+ "recent runtime events:",
180
+ `- summary: ${buildTelegramRuntimeEventSummary(events)}`,
181
+ ...events
182
+ .slice()
183
+ .reverse()
184
+ .map((event) => `- ${formatTelegramRuntimeEvent(event)}`),
185
+ ];
186
+ }
187
+ export function createTelegramStatusHtmlBuilder(deps) {
188
+ return (ctx) => buildStatusHtml({ ...ctx, isCompactionInProgress: deps.isCompactionInProgress }, deps.getActiveModel(ctx), deps.getBridgeStatusLineState?.());
189
+ }
190
+ function resolveStatusBarTheme(ctx) {
191
+ try {
192
+ const theme = ctx.ui?.theme;
193
+ return typeof theme?.fg === "function" ? theme : undefined;
194
+ }
195
+ catch {
196
+ return undefined;
197
+ }
198
+ }
199
+ export function createTelegramStatusRuntime(deps) {
200
+ const statusKey = deps.statusKey ?? "telegram";
201
+ return {
202
+ updateStatus: (ctx, error) => {
203
+ const theme = resolveStatusBarTheme(ctx);
204
+ if (!theme)
205
+ return;
206
+ ctx.ui.setStatus(statusKey, buildTelegramStatusBarText(theme, deps.getStatusBarState(ctx, error)));
207
+ },
208
+ getStatusLines: (options) => buildTelegramBridgeStatusLines(deps.getBridgeStatusLineState(), options),
209
+ getStatusState: deps.getBridgeStatusLineState,
210
+ };
211
+ }
212
+ export function createTelegramBridgeStatusRuntime(deps) {
213
+ return createTelegramStatusRuntime({
214
+ statusKey: deps.statusKey,
215
+ getStatusBarState: (_ctx, error) => {
216
+ const config = deps.getConfig();
217
+ const queuedItems = deps.getQueuedItems();
218
+ const hasPendingDispatch = deps.hasDispatchPending();
219
+ const waitingItems = hasPendingDispatch ? queuedItems.slice(1) : queuedItems;
220
+ const queuedItemCount = deps.getQueuedItemCount?.(waitingItems) ?? waitingItems.length;
221
+ const hasActiveTurn = deps.hasActiveTurn();
222
+ const hasPendingModelSwitch = deps.hasPendingModelSwitch();
223
+ const activeToolExecutions = deps.getActiveToolExecutions();
224
+ const compactionInProgress = deps.isCompactionInProgress();
225
+ const localBus = deps.getLocalBus?.();
226
+ return {
227
+ hasBotToken: config.botHasToken ?? Boolean(config.botToken),
228
+ pollingActive: deps.isPollingActive(),
229
+ paired: !!config.allowedUserId,
230
+ busRole: deps.getBusRole?.(),
231
+ followerRegistered: localBus?.followerRegistered,
232
+ busLifecyclePhase: deps.getBusLifecyclePhase?.(),
233
+ instanceSlot: deps.getInstanceSlot?.(),
234
+ instanceThreadName: deps.getInstanceThreadName?.(),
235
+ compactionInProgress,
236
+ processing: hasActiveTurn ||
237
+ hasPendingDispatch ||
238
+ hasPendingModelSwitch ||
239
+ activeToolExecutions > 0 ||
240
+ queuedItemCount > 0,
241
+ processingStatus: getTelegramStatusBarProcessingStatus({
242
+ hasActiveTurn,
243
+ hasPendingDispatch,
244
+ hasPendingModelSwitch,
245
+ activeToolExecutions,
246
+ queuedItems: queuedItemCount,
247
+ }),
248
+ queuedStatus: queuedItemCount > 0 ? ` +${queuedItemCount}` : "",
249
+ pollingStopReason: deps.getPollingState?.().stopReason,
250
+ error,
251
+ };
252
+ },
253
+ getBridgeStatusLineState: () => {
254
+ const config = deps.getConfig();
255
+ const botThreadMode = deps.getBotThreadMode?.();
256
+ const activeProfileName = deps.getActiveProfileName
257
+ ? (deps.getActiveProfileName() ?? TELEGRAM_STATUS_DEFAULT_PROFILE_NAME)
258
+ : undefined;
259
+ return {
260
+ hasBotToken: config.botHasToken ?? Boolean(config.botToken),
261
+ botUsername: config.botUsername,
262
+ botTokenDiagnostic: config.botTokenDiagnostic,
263
+ activeProfileName,
264
+ diagnosticPaths: deps.getDiagnosticPaths?.(activeProfileName),
265
+ allowedUserId: config.allowedUserId,
266
+ botThreadMode: botThreadMode?.threadMode,
267
+ botThreadModeUpdatedAtMs: botThreadMode?.updatedAtMs,
268
+ botThreadModeAction: botThreadMode?.lastReconcileAction,
269
+ busRole: deps.getBusRole?.(),
270
+ busProtocol: deps.getBusProtocol?.(),
271
+ busLifecyclePhase: deps.getBusLifecyclePhase?.(),
272
+ instanceSlot: deps.getInstanceSlot?.(),
273
+ instanceThreadName: deps.getInstanceThreadName?.(),
274
+ lockState: deps.getRuntimeLockState?.(),
275
+ pollingActive: deps.isPollingActive(),
276
+ ...(deps.getPollingState
277
+ ? { polling: deps.getPollingState() }
278
+ : {}),
279
+ ...(deps.getInboundWorkerState
280
+ ? { inboundWorker: deps.getInboundWorkerState() }
281
+ : {}),
282
+ lastUpdateId: deps.getAcceptedThroughUpdateId?.(),
283
+ activeSourceMessageIds: deps.getActiveSourceMessageIds(),
284
+ pendingDispatch: deps.hasDispatchPending(),
285
+ compactionInProgress: deps.isCompactionInProgress(),
286
+ activeToolExecutions: deps.getActiveToolExecutions(),
287
+ pendingModelSwitch: deps.hasPendingModelSwitch(),
288
+ queuedItems: deps.getQueuedItems(),
289
+ busFollowers: deps.getBusFollowers?.(),
290
+ localBus: deps.getLocalBus?.(),
291
+ topicTargets: deps.getTopicTargets?.(),
292
+ threadReservations: deps.getThreadReservations?.(),
293
+ topicSyncObservations: deps.getTopicSyncObservations?.(),
294
+ syncState: deps.getSyncState?.(),
295
+ threadReconciliation: deps.getThreadReconciliationState?.(),
296
+ busNowMs: deps.getNowMs?.(),
297
+ recentRuntimeEvents: deps.getRecentRuntimeEvents(),
298
+ };
299
+ },
300
+ });
301
+ }
302
+ export function createTelegramRuntimeLogScope(input) {
303
+ return {
304
+ instanceId: input.instanceId,
305
+ role: input.state.busRole ?? "classic-or-disconnected",
306
+ slot: input.state.instanceSlot,
307
+ threadName: input.state.instanceThreadName,
308
+ lockState: input.state.lockState,
309
+ };
310
+ }
311
+ export function createTelegramStatusSnapshot(state) {
312
+ return {
313
+ runtime: {
314
+ busRole: state.busRole,
315
+ ...(state.busLifecyclePhase
316
+ ? { busLifecyclePhase: state.busLifecyclePhase }
317
+ : {}),
318
+ botThreadMode: state.botThreadMode,
319
+ botThreadModeUpdatedAtMs: state.botThreadModeUpdatedAtMs,
320
+ botThreadModeAction: state.botThreadModeAction,
321
+ instanceSlot: state.instanceSlot,
322
+ instanceThreadName: state.instanceThreadName,
323
+ pollingActive: state.pollingActive,
324
+ ...(state.polling ? { polling: state.polling } : {}),
325
+ lockState: state.lockState,
326
+ },
327
+ liveRoster: {
328
+ busFollowers: state.busFollowers ?? [],
329
+ ...(state.localBus ? { localBus: state.localBus } : {}),
330
+ topicTargets: state.topicTargets ?? [],
331
+ reservations: state.threadReservations ?? [],
332
+ syncObservations: state.topicSyncObservations ?? [],
333
+ },
334
+ diagnostics: {
335
+ pendingDispatch: state.pendingDispatch,
336
+ compactionInProgress: state.compactionInProgress,
337
+ activeToolExecutions: state.activeToolExecutions,
338
+ pendingModelSwitch: state.pendingModelSwitch,
339
+ syncState: state.syncState,
340
+ threadReconciliation: state.threadReconciliation,
341
+ recentRuntimeEvents: state.recentRuntimeEvents,
342
+ },
343
+ };
344
+ }
345
+ const TELEGRAM_DIAGNOSTICS_SNAPSHOT_COALESCE_MS = 100;
346
+ export function createTelegramRuntimeDiagnosticsSnapshotScheduler(deps) {
347
+ const setTimer = deps.setTimer ?? setTimeout;
348
+ let timer;
349
+ let persistPromise;
350
+ let pending = false;
351
+ const recordError = (error) => {
352
+ try {
353
+ deps.recordError(error);
354
+ }
355
+ catch {
356
+ // Snapshot diagnostics cannot create an unhandled scheduler rejection.
357
+ }
358
+ };
359
+ const request = () => {
360
+ if (timer || persistPromise) {
361
+ pending = true;
362
+ return;
363
+ }
364
+ timer = setTimer(() => {
365
+ timer = undefined;
366
+ let tracked;
367
+ tracked = Promise.resolve()
368
+ .then(deps.persistSnapshot)
369
+ .catch(recordError)
370
+ .finally(() => {
371
+ if (persistPromise !== tracked)
372
+ return;
373
+ persistPromise = undefined;
374
+ if (pending) {
375
+ pending = false;
376
+ request();
377
+ }
378
+ });
379
+ persistPromise = tracked;
380
+ }, TELEGRAM_DIAGNOSTICS_SNAPSHOT_COALESCE_MS);
381
+ if (typeof timer !== "number")
382
+ timer?.unref?.();
383
+ };
384
+ return request;
385
+ }
386
+ export function getTelegramStatusBarProcessingStatus(state) {
387
+ if (state.hasPendingModelSwitch)
388
+ return "model";
389
+ if (state.hasActiveTurn || state.activeToolExecutions > 0)
390
+ return "active";
391
+ if (state.hasPendingDispatch)
392
+ return "dispatching";
393
+ if (state.queuedItems > 0)
394
+ return "queued";
395
+ return undefined;
396
+ }
397
+ function getTelegramStatusBarLabel(state) {
398
+ const threadName = state.instanceThreadName?.trim();
399
+ if (!threadName)
400
+ return "telegram";
401
+ const genericLabels = new Set(["telegram", "leader", "follower"]);
402
+ if (genericLabels.has(threadName.toLowerCase()))
403
+ return "telegram";
404
+ return threadName;
405
+ }
406
+ export function buildTelegramStatusBarText(theme, state) {
407
+ const label = theme.fg("accent", getTelegramStatusBarLabel(state));
408
+ const queued = state.queuedStatus
409
+ ? theme.fg("warning", state.queuedStatus)
410
+ : "";
411
+ if (!state.hasBotToken)
412
+ return `${label} ${theme.fg("muted", "not configured")}${queued}`;
413
+ if (state.pollingStopReason === "persistent-conflict" && state.busRole !== "follower")
414
+ return `${label} ${theme.fg("error", "error")}`;
415
+ if (!state.paired)
416
+ return `${label} ${theme.fg("warning", "awaiting pairing")}${queued}`;
417
+ if (state.busLifecyclePhase === "electing")
418
+ return `${label} ${theme.fg("warning", "electing")}${queued}`;
419
+ if (!state.pollingActive && state.busRole !== "follower")
420
+ return `${theme.fg("accent", "telegram")} ${theme.fg("dim", "disconnected")}${queued}`;
421
+ if (state.error) {
422
+ return `${label} ${theme.fg("error", "error")}${queued}`;
423
+ }
424
+ if (state.busRole === "follower" && state.followerRegistered === false) {
425
+ return `${label} ${theme.fg("warning", "reconnecting")}${queued}`;
426
+ }
427
+ if (state.busRole === "follower")
428
+ return `${label} ${theme.fg("success", "follower")}${queued}`;
429
+ if (state.busRole === "leader")
430
+ return `${label} ${theme.fg("success", "leader")}${queued}`;
431
+ return `${label} ${theme.fg("success", "connected")}${queued}`;
432
+ }
433
+ function formatTelegramBridgeBotStatus(state) {
434
+ if (state.botUsername)
435
+ return `@${state.botUsername}`;
436
+ if (state.hasBotToken)
437
+ return "unknown";
438
+ return state.botTokenDiagnostic ?? "not configured";
439
+ }
440
+ function formatTelegramStatusTarget(target) {
441
+ if (!target)
442
+ return "";
443
+ return target.threadId === undefined
444
+ ? ` target ${target.chatId}`
445
+ : ` target ${target.chatId}:${target.threadId}`;
446
+ }
447
+ function formatTelegramThreadStatusLabel(input) {
448
+ const threadName = input.threadName?.trim();
449
+ if (threadName)
450
+ return threadName;
451
+ return input.slot ? `[${input.slot}]` : "";
452
+ }
453
+ function formatTelegramBusProtocolIdentity(protocol) {
454
+ if (!protocol)
455
+ return "";
456
+ const capabilities = protocol.capabilities.length > 0
457
+ ? ` capabilities=${protocol.capabilities.join(",")}`
458
+ : " capabilities=none";
459
+ return ` protocol=v${protocol.protocolVersion} build=${protocol.runtimeBuild}${capabilities}`;
460
+ }
461
+ function buildTelegramBusFollowerLines(state) {
462
+ const followers = state.busFollowers ?? [];
463
+ if (followers.length === 0)
464
+ return [];
465
+ const nowMs = state.busNowMs ?? Date.now();
466
+ return [
467
+ "",
468
+ "bus:",
469
+ `- followers: ${followers.length}`,
470
+ ...followers.map((follower) => {
471
+ const ageSeconds = Math.max(0, Math.round((nowMs - follower.lastHeartbeatMs) / 1000));
472
+ const label = formatTelegramThreadStatusLabel(follower);
473
+ const labelSuffix = label ? ` ${label}` : "";
474
+ const statusLabel = follower.status ? ` (${follower.status})` : "";
475
+ const cwd = follower.cwd ? ` ${follower.cwd}` : "";
476
+ const target = formatTelegramStatusTarget(follower.target);
477
+ const protocol = formatTelegramBusProtocolIdentity(follower.protocol);
478
+ return `- ${follower.instanceId}:${labelSuffix} heartbeat ${ageSeconds}s ago${statusLabel}${target}${cwd}${protocol}`;
479
+ }),
480
+ ];
481
+ }
482
+ function buildTelegramLocalBusLines(state, options = {}) {
483
+ const localBus = state.localBus;
484
+ if (!localBus)
485
+ return [];
486
+ const target = formatTelegramStatusTarget(localBus.followerTarget);
487
+ const label = formatTelegramThreadStatusLabel({
488
+ slot: localBus.followerSlot,
489
+ threadName: localBus.followerThreadName,
490
+ });
491
+ const protocol = formatTelegramBusProtocolIdentity(localBus.leaderProtocol);
492
+ const followerLine = `- follower registered: ${localBus.followerRegistered ? "yes" : "no"}${label ? ` ${label}` : ""}${target}${protocol}`;
493
+ const lines = ["", "local bus:", followerLine];
494
+ if (options.verbose) {
495
+ if (localBus.leaderSocketPath) {
496
+ const transport = localBus.leaderTransport
497
+ ? ` [${localBus.leaderTransport}]`
498
+ : "";
499
+ lines.push(`- leader endpoint${transport}: ${localBus.leaderSocketPath}`);
500
+ }
501
+ if (localBus.followerSocketPath) {
502
+ const transport = localBus.followerTransport
503
+ ? ` [${localBus.followerTransport}]`
504
+ : "";
505
+ lines.push(`- follower endpoint${transport}: ${localBus.followerSocketPath}`);
506
+ }
507
+ }
508
+ return lines;
509
+ }
510
+ function buildTelegramSyncSliceLines(state) {
511
+ const syncState = state.syncState;
512
+ if (!syncState || Object.keys(syncState).length === 0)
513
+ return [];
514
+ return [
515
+ "sync:",
516
+ ...Object.entries(syncState).map(([slice, value]) => {
517
+ const status = value?.status ?? "unknown";
518
+ const action = value?.lastReconcileAction
519
+ ? ` reconcile=${value.lastReconcileAction}`
520
+ : "";
521
+ const reason = value?.reason ? ` reason=${value.reason}` : "";
522
+ return `- ${slice}: ${status}${action}${reason}`;
523
+ }),
524
+ ];
525
+ }
526
+ function buildTelegramThreadReconciliationLines(state) {
527
+ const reconciliation = state.threadReconciliation;
528
+ if (!reconciliation)
529
+ return [];
530
+ const epoch = reconciliation.leaderEpoch !== undefined
531
+ ? ` epoch=${reconciliation.leaderEpoch}`
532
+ : "";
533
+ return [
534
+ "reconciliation:",
535
+ `- phase: ${reconciliation.phase} event=${reconciliation.event}${epoch}`,
536
+ `- counts: pending=${reconciliation.pendingProvisionCount}, sync=${reconciliation.syncActionCount}, cleanup=${reconciliation.cleanupActionCount}`,
537
+ ];
538
+ }
539
+ function buildTelegramTopicTargetDiagnosticLines(state) {
540
+ const activeTargets = (state.topicTargets ?? []).filter((record) => !!record.instanceId &&
541
+ (record.status === "active" || record.status === "starting"));
542
+ const reservations = state.threadReservations ?? [];
543
+ const observations = state.topicSyncObservations ?? [];
544
+ if (activeTargets.length === 0 &&
545
+ reservations.length === 0 &&
546
+ observations.length === 0)
547
+ return [];
548
+ const byInstance = new Map();
549
+ for (const record of activeTargets) {
550
+ const key = record.instanceId;
551
+ if (!key)
552
+ continue;
553
+ const records = byInstance.get(key) ?? [];
554
+ records.push(record);
555
+ byInstance.set(key, records);
556
+ }
557
+ const duplicateLines = Array.from(byInstance.entries())
558
+ .filter(([, records]) => records.length > 1)
559
+ .map(([instanceId, records]) => {
560
+ const targets = records
561
+ .map((record) => {
562
+ const label = formatTelegramThreadStatusLabel(record);
563
+ return `${label}${formatTelegramStatusTarget(record.target) || " unknown"}`.trim();
564
+ })
565
+ .join(", ");
566
+ return `- duplicate ${instanceId}: ${records.length} active threads ${targets}`;
567
+ });
568
+ const twinLines = activeTargets.map((record) => {
569
+ const label = formatTelegramThreadStatusLabel(record);
570
+ const target = formatTelegramStatusTarget(record.target) || " unknown";
571
+ const sync = record.syncStatus ? ` sync=${record.syncStatus}` : "";
572
+ const observed = record.lastSyncObservedAtMs
573
+ ? ` observed=${new Date(record.lastSyncObservedAtMs).toISOString()}`
574
+ : "";
575
+ const probe = record.lastSyncProbeAtMs
576
+ ? ` probed=${new Date(record.lastSyncProbeAtMs).toISOString()}`
577
+ : "";
578
+ const error = record.lastSyncError
579
+ ? ` syncError=${record.lastSyncError}`
580
+ : "";
581
+ const action = record.lastReconcileAction
582
+ ? ` reconcile=${record.lastReconcileAction}`
583
+ : "";
584
+ return `- ${label}${target}${sync}${observed}${probe}${error}${action}`.trim();
585
+ });
586
+ const reservationLines = reservations.map((reservation) => {
587
+ const slot = reservation.slot ? `[${reservation.slot}]` : "";
588
+ const target = formatTelegramStatusTarget(reservation.target) || " unknown";
589
+ const reason = reservation.reason ? ` reason=${reservation.reason}` : "";
590
+ const instance = reservation.instanceId
591
+ ? ` instance=${reservation.instanceId}`
592
+ : "";
593
+ const action = reservation.lastReconcileAction
594
+ ? ` reconcile=${reservation.lastReconcileAction}`
595
+ : "";
596
+ return `- reservation ${slot}${target}${reason}${instance}${action}`.trim();
597
+ });
598
+ const observationLines = observations.map((observation) => {
599
+ const slot = observation.slot ? `[${observation.slot}]` : "";
600
+ const target = formatTelegramStatusTarget(observation.target) || " unknown";
601
+ const observed = ` observed=${new Date(observation.observedAtMs).toISOString()}`;
602
+ const instance = observation.instanceId
603
+ ? ` instance=${observation.instanceId}`
604
+ : "";
605
+ const error = observation.lastSyncError
606
+ ? ` syncError=${observation.lastSyncError}`
607
+ : "";
608
+ const action = observation.lastReconcileAction
609
+ ? ` reconcile=${observation.lastReconcileAction}`
610
+ : "";
611
+ return `- sync ${slot}${target} sync=${observation.syncStatus}${observed}${instance}${error}${action}`.trim();
612
+ });
613
+ return [
614
+ "topics:",
615
+ `- active bindings: instances=${byInstance.size}, targets=${activeTargets.length}`,
616
+ ...duplicateLines,
617
+ ...twinLines,
618
+ ...reservationLines,
619
+ ...observationLines,
620
+ ];
621
+ }
622
+ function buildTelegramBridgeCompactThreadLines(state) {
623
+ const activeTargets = (state.topicTargets ?? []).filter((record) => !!record.instanceId &&
624
+ (record.status === "active" || record.status === "starting"));
625
+ const activeLabels = activeTargets
626
+ .map(formatTelegramThreadStatusLabel)
627
+ .filter((label) => label.length > 0);
628
+ const followers = state.busFollowers ?? [];
629
+ const reservations = state.threadReservations ?? [];
630
+ const observations = state.topicSyncObservations ?? [];
631
+ if (activeLabels.length === 0 &&
632
+ followers.length === 0 &&
633
+ reservations.length === 0 &&
634
+ observations.length === 0) {
635
+ return [];
636
+ }
637
+ const lines = ["threads:"];
638
+ if (activeLabels.length > 0)
639
+ lines.push(`- active: ${activeLabels.join(", ")}`);
640
+ if (followers.length > 0)
641
+ lines.push(`- followers: ${followers.length}`);
642
+ if (reservations.length > 0)
643
+ lines.push(`- reserved: ${reservations.length}`);
644
+ const syncIssueCount = observations.filter((observation) => observation.syncStatus !== "open").length;
645
+ if (syncIssueCount > 0)
646
+ lines.push(`- sync issues: ${syncIssueCount}`);
647
+ return lines;
648
+ }
649
+ function formatTelegramPollingLifecycle(state) {
650
+ const lifecycle = state.pollingActive ? "running" : "stopped";
651
+ if (!state.polling)
652
+ return lifecycle;
653
+ if (state.pollingActive)
654
+ return `${lifecycle} (${state.polling.phase})`;
655
+ return state.polling.stopReason
656
+ ? `${lifecycle} (${state.polling.stopReason})`
657
+ : lifecycle;
658
+ }
659
+ function buildTelegramPollingDiagnosticLines(polling) {
660
+ if (!polling)
661
+ return [];
662
+ return [
663
+ `- phase: ${polling.phase}`,
664
+ ...(polling.phaseStartedAtMs !== undefined
665
+ ? [
666
+ `- phase started: ${new Date(polling.phaseStartedAtMs).toISOString()}`,
667
+ ]
668
+ : []),
669
+ ...(polling.currentUpdateId !== undefined
670
+ ? [`- current update id: ${polling.currentUpdateId}`]
671
+ : []),
672
+ ...(polling.lastSuccessfulResponseAtMs !== undefined
673
+ ? [
674
+ `- last successful response: ${new Date(polling.lastSuccessfulResponseAtMs).toISOString()} (updates=${polling.lastSuccessfulResponseUpdateCount ?? "unknown"})`,
675
+ ]
676
+ : []),
677
+ ...(polling.startedAtMs !== undefined
678
+ ? [`- started: ${new Date(polling.startedAtMs).toISOString()}`]
679
+ : []),
680
+ ...(polling.stoppedAtMs !== undefined
681
+ ? [`- stopped: ${new Date(polling.stoppedAtMs).toISOString()}`]
682
+ : []),
683
+ ...(polling.stopReason ? [`- stop reason: ${polling.stopReason}`] : []),
684
+ ];
685
+ }
686
+ function formatTelegramInboundWorkerState(worker) {
687
+ if (!worker)
688
+ return "not started";
689
+ const depth = worker.journalEntryCount;
690
+ return `${worker.phase} (depth=${depth}, queued=${worker.queuedClaimCount}, foreign=${worker.foreignQueuedCount}, deferred=${worker.deferredClaimCount}, retry=${worker.retryWaitCount}, failed=${worker.failedCount})`;
691
+ }
692
+ function buildTelegramInboundWorkerDiagnosticLines(worker) {
693
+ if (!worker)
694
+ return ["- state: not started"];
695
+ return [
696
+ `- state: ${worker.phase}`,
697
+ `- generation: ${worker.generation}`,
698
+ ...(worker.phaseStartedAtMs !== undefined
699
+ ? [`- phase started: ${new Date(worker.phaseStartedAtMs).toISOString()}`]
700
+ : []),
701
+ `- journal: entries=${worker.journalEntryCount}, bytes=${worker.journalSerializedBytes}`,
702
+ `- claims: queued=${worker.queuedClaimCount}, foreign-queued=${worker.foreignQueuedCount}, deferred=${worker.deferredClaimCount}, unsettled=${worker.unsettledExecutionCount}`,
703
+ ...(worker.foreignQueuedOwner
704
+ ? [
705
+ `- queued semantic owner: instance=${worker.foreignQueuedOwner.instanceId}, pid=${worker.foreignQueuedOwner.processId}, birth=${worker.foreignQueuedOwner.processBirthId}, session=${worker.foreignQueuedOwner.sessionGeneration}, acquisition=${worker.foreignQueuedOwner.acquisitionId}, liveness=${worker.foreignQueuedOwnerLiveness ?? "unknown"}`,
706
+ ]
707
+ : []),
708
+ `- failures: retry-wait=${worker.retryWaitCount}, terminal=${worker.failedCount}`,
709
+ ...(worker.currentUpdateId !== undefined
710
+ ? [`- current update id: ${worker.currentUpdateId}`]
711
+ : []),
712
+ ...(worker.nextRetryUpdateId !== undefined
713
+ ? [
714
+ `- next retry: update=${worker.nextRetryUpdateId}, attempt=${worker.nextRetryAttemptCount ?? "unknown"}, class=${worker.nextRetryFailureClass ?? "unknown"}${worker.nextRetryAtMs !== undefined ? ` at ${new Date(worker.nextRetryAtMs).toISOString()}` : ""}`,
715
+ ]
716
+ : []),
717
+ ...(worker.failedUpdateId !== undefined
718
+ ? [
719
+ `- terminal update: id=${worker.failedUpdateId}, failure=${worker.failedFailureId ?? "unknown"}, attempts=${worker.failedAttemptCount ?? "unknown"}, class=${worker.failedClass ?? "unknown"}${worker.terminalFailureAtMs !== undefined ? ` at ${new Date(worker.terminalFailureAtMs).toISOString()}` : ""}`,
720
+ ...(worker.failedSummary
721
+ ? [`- terminal summary: ${worker.failedSummary}`]
722
+ : []),
723
+ ]
724
+ : []),
725
+ ...(worker.oldestAdmittedAtMs !== undefined
726
+ ? [
727
+ `- oldest admitted: ${new Date(worker.oldestAdmittedAtMs).toISOString()}`,
728
+ ]
729
+ : []),
730
+ ...(worker.blockedReason
731
+ ? [`- blocked reason: ${worker.blockedReason}`]
732
+ : []),
733
+ ...(worker.blockedInputCustody
734
+ ? [`- blocked input custody: update=${worker.blockedInputCustody.updateId}, kind=${worker.blockedInputCustody.kind}`]
735
+ : []),
736
+ ...(worker.lastCompletedUpdateId !== undefined
737
+ ? [
738
+ `- last completed: ${worker.lastCompletedUpdateId}${worker.lastCompletedAtMs !== undefined ? ` at ${new Date(worker.lastCompletedAtMs).toISOString()}` : ""}`,
739
+ ]
740
+ : []),
741
+ ...(worker.lastFailurePhase
742
+ ? [
743
+ `- last failure: ${worker.lastFailurePhase}${worker.lastFailureAtMs !== undefined ? ` at ${new Date(worker.lastFailureAtMs).toISOString()}` : ""}`,
744
+ ]
745
+ : []),
746
+ ];
747
+ }
748
+ function buildTelegramBridgeCompactStatusLines(state) {
749
+ const controlQueueCount = state.queuedItems.filter((item) => item.queueLane === "control").length;
750
+ const priorityQueueCount = state.queuedItems.filter((item) => item.queueLane === "priority").length;
751
+ const defaultQueueCount = state.queuedItems.filter((item) => item.queueLane === "default").length;
752
+ const queueLine = `- queued turns: ${state.queuedItems.length}${state.queuedItems.length > 0
753
+ ? ` (control=${controlQueueCount}, priority=${priorityQueueCount}, default=${defaultQueueCount})`
754
+ : ""}`;
755
+ const executionState = state.pendingDispatch
756
+ ? "pending dispatch"
757
+ : state.activeSourceMessageIds?.length
758
+ ? "active"
759
+ : "idle";
760
+ const diagnosticsProfileName = state.activeProfileName === TELEGRAM_STATUS_DEFAULT_PROFILE_NAME
761
+ ? undefined
762
+ : state.activeProfileName;
763
+ const profileSuffix = diagnosticsProfileName
764
+ ? `.${diagnosticsProfileName.replace(/[^a-zA-Z0-9._-]+/g, "_")}`
765
+ : "";
766
+ const diagnosticsPaths = state.diagnosticPaths ?? {
767
+ state: `~/.pi/agent/tmp/telegram/state${profileSuffix}.json`,
768
+ logs: `~/.pi/agent/tmp/telegram/logs${profileSuffix}.jsonl`,
769
+ };
770
+ return [
771
+ "connection:",
772
+ `- bot: ${formatTelegramBridgeBotStatus(state)}`,
773
+ ...(state.activeProfileName
774
+ ? [`- profile: ${state.activeProfileName}`]
775
+ : []),
776
+ `- user: ${state.allowedUserId ?? "not paired"}`,
777
+ ...(state.botThreadMode ? [`- thread mode: ${state.botThreadMode}`] : []),
778
+ ...(state.busRole ? [`- role: ${state.busRole}`] : []),
779
+ ...(state.busLifecyclePhase
780
+ ? [`- lifecycle: ${state.busLifecyclePhase}`]
781
+ : []),
782
+ ...(state.instanceThreadName || state.instanceSlot
783
+ ? [`- instance: ${state.instanceThreadName ?? state.instanceSlot}`]
784
+ : []),
785
+ ...(state.lockState ? [`- owner: ${state.lockState}`] : []),
786
+ "",
787
+ "health:",
788
+ `- polling: ${formatTelegramPollingLifecycle(state)}`,
789
+ ...(state.inboundWorker
790
+ ? [
791
+ `- inbound worker: ${formatTelegramInboundWorkerState(state.inboundWorker)}`,
792
+ ]
793
+ : []),
794
+ `- state: ${executionState}`,
795
+ queueLine,
796
+ ...(state.activeToolExecutions > 0
797
+ ? [`- active tools: ${state.activeToolExecutions}`]
798
+ : []),
799
+ ...(state.pendingModelSwitch ? ["- pending model switch: yes"] : []),
800
+ ...buildTelegramBridgeCompactThreadLines(state),
801
+ ...buildTelegramBusFollowerLines(state),
802
+ ...buildTelegramLocalBusLines(state),
803
+ ...buildTelegramThreadReconciliationLines(state),
804
+ "",
805
+ "diagnostics:",
806
+ `- state: ${diagnosticsPaths.state}`,
807
+ `- logs: ${diagnosticsPaths.logs}`,
808
+ "- full dump: /telegram-status --debug",
809
+ ];
810
+ }
811
+ export function buildTelegramBridgeStatusLines(state, options = {}) {
812
+ if (options.verbose)
813
+ return buildTelegramBridgeDiagnosticStatusLines(state);
814
+ return buildTelegramBridgeCompactStatusLines(state);
815
+ }
816
+ export function buildTelegramBridgeDiagnosticStatusLines(state) {
817
+ const controlQueueCount = state.queuedItems.filter((item) => item.queueLane === "control").length;
818
+ const priorityQueueCount = state.queuedItems.filter((item) => item.queueLane === "priority").length;
819
+ const defaultQueueCount = state.queuedItems.filter((item) => item.queueLane === "default").length;
820
+ return [
821
+ "connection:",
822
+ `- bot: ${formatTelegramBridgeBotStatus(state)}`,
823
+ ...(state.activeProfileName
824
+ ? [`- profile: ${state.activeProfileName}`]
825
+ : []),
826
+ `- allowed user: ${state.allowedUserId ?? "not paired"}`,
827
+ ...(state.botThreadMode
828
+ ? [
829
+ `- thread mode: ${state.botThreadMode}${state.botThreadModeAction ? ` reconcile=${state.botThreadModeAction}` : ""}`,
830
+ ]
831
+ : []),
832
+ ...(state.busRole ? [`- bus role: ${state.busRole}`] : []),
833
+ ...(state.busProtocol
834
+ ? [`- bus${formatTelegramBusProtocolIdentity(state.busProtocol)}`]
835
+ : []),
836
+ ...(state.busLifecyclePhase
837
+ ? [`- bus lifecycle: ${state.busLifecyclePhase}`]
838
+ : []),
839
+ ...(state.instanceThreadName || state.instanceSlot
840
+ ? [`- instance: ${state.instanceThreadName ?? state.instanceSlot}`]
841
+ : []),
842
+ ...(state.lockState ? [`- owner: ${state.lockState}`] : []),
843
+ "",
844
+ "polling:",
845
+ `- state: ${formatTelegramPollingLifecycle(state)}`,
846
+ ...buildTelegramPollingDiagnosticLines(state.polling),
847
+ `- last update id: ${state.lastUpdateId ?? "none"}`,
848
+ "",
849
+ ...(state.inboundWorker
850
+ ? [
851
+ "inbound worker:",
852
+ ...buildTelegramInboundWorkerDiagnosticLines(state.inboundWorker),
853
+ "",
854
+ ]
855
+ : []),
856
+ "execution:",
857
+ `- active turn: ${state.activeSourceMessageIds?.join(",") || "no"}`,
858
+ `- pending dispatch: ${state.pendingDispatch ? "yes" : "no"}`,
859
+ `- compaction: ${state.compactionInProgress ? "running" : "idle"}`,
860
+ `- active tools: ${state.activeToolExecutions}`,
861
+ `- pending model switch: ${state.pendingModelSwitch ? "yes" : "no"}`,
862
+ "",
863
+ "queue:",
864
+ `- queued turns: ${state.queuedItems.length}`,
865
+ `- lanes: control=${controlQueueCount}, priority=${priorityQueueCount}, default=${defaultQueueCount}`,
866
+ ...buildTelegramBusFollowerLines(state),
867
+ ...buildTelegramLocalBusLines(state, { verbose: true }),
868
+ ...buildTelegramTopicTargetDiagnosticLines(state),
869
+ ...buildTelegramThreadReconciliationLines(state),
870
+ ...buildTelegramSyncSliceLines(state),
871
+ "",
872
+ ...buildTelegramRuntimeEventLines(state.recentRuntimeEvents),
873
+ ];
874
+ }
875
+ function escapeHtml(text) {
876
+ return text
877
+ .replace(/&/g, "&amp;")
878
+ .replace(/</g, "&lt;")
879
+ .replace(/>/g, "&gt;");
880
+ }
881
+ function formatTokens(count) {
882
+ if (count < 1000)
883
+ return count.toString();
884
+ if (count < 10000)
885
+ return `${(count / 1000).toFixed(1)}k`;
886
+ if (count < 1000000)
887
+ return `${Math.round(count / 1000)}k`;
888
+ if (count < 10000000)
889
+ return `${(count / 1000000).toFixed(1)}M`;
890
+ return `${Math.round(count / 1000000)}M`;
891
+ }
892
+ function collectUsageStats(ctx) {
893
+ const stats = {
894
+ totalInput: 0,
895
+ totalOutput: 0,
896
+ totalCacheRead: 0,
897
+ totalCacheWrite: 0,
898
+ totalCost: 0,
899
+ };
900
+ for (const entry of ctx.sessionManager.getEntries()) {
901
+ const usage = entry.message?.usage;
902
+ if (entry.type !== "message" ||
903
+ entry.message?.role !== "assistant" ||
904
+ !usage) {
905
+ continue;
906
+ }
907
+ stats.totalInput += usage.input;
908
+ stats.totalOutput += usage.output;
909
+ stats.totalCacheRead += usage.cacheRead;
910
+ stats.totalCacheWrite += usage.cacheWrite;
911
+ stats.totalCost += usage.cost.total;
912
+ const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
913
+ stats.latestCacheHitRate =
914
+ promptTokens > 0 ? (usage.cacheRead / promptTokens) * 100 : undefined;
915
+ }
916
+ return stats;
917
+ }
918
+ function formatStatusRowLabel(label) {
919
+ if (!label)
920
+ return label;
921
+ return `${label[0]?.toUpperCase() ?? ""}${label.slice(1)}`;
922
+ }
923
+ function buildStatusRow(label, value) {
924
+ return `<b>${escapeHtml(formatStatusRowLabel(label))}:</b> <code>${escapeHtml(value)}</code>`;
925
+ }
926
+ function buildUsageSummary(stats) {
927
+ const tokenParts = [];
928
+ if (stats.totalInput)
929
+ tokenParts.push(`↑${formatTokens(stats.totalInput)}`);
930
+ if (stats.totalOutput)
931
+ tokenParts.push(`↓${formatTokens(stats.totalOutput)}`);
932
+ return tokenParts.length > 0 ? tokenParts.join(" ") : undefined;
933
+ }
934
+ function buildCacheSummary(stats) {
935
+ const cacheParts = [];
936
+ if (stats.totalCacheRead)
937
+ cacheParts.push(`R${formatTokens(stats.totalCacheRead)}`);
938
+ if (stats.totalCacheWrite)
939
+ cacheParts.push(`W${formatTokens(stats.totalCacheWrite)}`);
940
+ if ((stats.totalCacheRead > 0 || stats.totalCacheWrite > 0) &&
941
+ stats.latestCacheHitRate !== undefined) {
942
+ cacheParts.push(`CH${stats.latestCacheHitRate.toFixed(1)}%`);
943
+ }
944
+ return cacheParts.length > 0 ? cacheParts.join(" ") : undefined;
945
+ }
946
+ function buildCostSummary(stats, usesSubscription) {
947
+ if (!stats.totalCost && !usesSubscription)
948
+ return undefined;
949
+ return `$${stats.totalCost.toFixed(3)}${usesSubscription ? " (sub)" : ""}`;
950
+ }
951
+ function buildContextSummary(ctx, activeModel) {
952
+ const usage = ctx.getContextUsage();
953
+ if (!usage)
954
+ return "unknown";
955
+ const contextWindow = usage.contextWindow ?? activeModel?.contextWindow ?? 0;
956
+ const percent = usage.percent !== null ? `${usage.percent.toFixed(1)}%` : "?";
957
+ return `${percent}/${formatTokens(contextWindow)}`;
958
+ }
959
+ function buildStatusSummary(ctx) {
960
+ if (ctx.isCompactionInProgress?.())
961
+ return "compacting";
962
+ if (ctx.hasPendingMessages?.())
963
+ return "pending";
964
+ if (ctx.isIdle?.() === false)
965
+ return "active";
966
+ if (ctx.isIdle?.() === true)
967
+ return "idle";
968
+ return "unknown";
969
+ }
970
+ function buildTelegramStatusRoleSuffix(state) {
971
+ if (state?.botThreadMode !== "enabled" || !state.busRole)
972
+ return "";
973
+ return ` @${state.busRole}`;
974
+ }
975
+ export function buildStatusHtml(ctx, activeModel, bridgeStatus) {
976
+ const stats = collectUsageStats(ctx);
977
+ const usesSubscription = activeModel
978
+ ? ctx.modelRegistry.isUsingOAuth(activeModel)
979
+ : false;
980
+ const lines = [
981
+ buildStatusRow("Status", `${buildStatusSummary(ctx)}${buildTelegramStatusRoleSuffix(bridgeStatus)}`),
982
+ ];
983
+ const usageSummary = buildUsageSummary(stats);
984
+ const cacheSummary = buildCacheSummary(stats);
985
+ const costSummary = buildCostSummary(stats, usesSubscription);
986
+ if (usageSummary) {
987
+ lines.push(buildStatusRow("Tokens", usageSummary));
988
+ }
989
+ if (cacheSummary) {
990
+ lines.push(buildStatusRow("Cache", cacheSummary));
991
+ }
992
+ if (costSummary) {
993
+ lines.push(buildStatusRow("Cost", costSummary));
994
+ }
995
+ lines.push(buildStatusRow("Context", buildContextSummary(ctx, activeModel)));
996
+ for (const row of getTelegramStatusLineProviderResults({ activeModel })) {
997
+ lines.push(buildStatusRow(row.label, row.value));
998
+ }
999
+ return lines.join("\n");
1000
+ }