@llblab/pi-kit 0.1.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 (523) hide show
  1. package/AGENTS.md +35 -0
  2. package/BACKLOG.md +3 -0
  3. package/CHANGELOG.md +9 -0
  4. package/LICENSE +21 -0
  5. package/README.md +43 -0
  6. package/node_modules/@llblab/pi-actors/AGENTS.md +150 -0
  7. package/node_modules/@llblab/pi-actors/BACKLOG.md +6 -0
  8. package/node_modules/@llblab/pi-actors/CHANGELOG.md +865 -0
  9. package/node_modules/@llblab/pi-actors/README.md +231 -0
  10. package/node_modules/@llblab/pi-actors/banner.jpg +0 -0
  11. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/artifact-manifest.json +9 -0
  12. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/control-endpoint.json +6 -0
  13. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/control-record.json +9 -0
  14. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/recipe-summary.json +8 -0
  15. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/run-state.json +10 -0
  16. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/trace-event.json +9 -0
  17. package/node_modules/@llblab/pi-actors/dist/index.d.ts +7 -0
  18. package/node_modules/@llblab/pi-actors/dist/index.js +17 -0
  19. package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +146 -0
  20. package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +800 -0
  21. package/node_modules/@llblab/pi-actors/dist/lib/automatic-review-runtime.d.ts +20 -0
  22. package/node_modules/@llblab/pi-actors/dist/lib/automatic-review-runtime.js +103 -0
  23. package/node_modules/@llblab/pi-actors/dist/lib/command-templates.d.ts +85 -0
  24. package/node_modules/@llblab/pi-actors/dist/lib/command-templates.js +804 -0
  25. package/node_modules/@llblab/pi-actors/dist/lib/config.d.ts +34 -0
  26. package/node_modules/@llblab/pi-actors/dist/lib/config.js +216 -0
  27. package/node_modules/@llblab/pi-actors/dist/lib/control-projection.d.ts +20 -0
  28. package/node_modules/@llblab/pi-actors/dist/lib/control-projection.js +66 -0
  29. package/node_modules/@llblab/pi-actors/dist/lib/control.d.ts +15 -0
  30. package/node_modules/@llblab/pi-actors/dist/lib/control.js +97 -0
  31. package/node_modules/@llblab/pi-actors/dist/lib/draft-consolidation-transaction.d.ts +65 -0
  32. package/node_modules/@llblab/pi-actors/dist/lib/draft-consolidation-transaction.js +610 -0
  33. package/node_modules/@llblab/pi-actors/dist/lib/draft-consolidation.d.ts +35 -0
  34. package/node_modules/@llblab/pi-actors/dist/lib/draft-consolidation.js +126 -0
  35. package/node_modules/@llblab/pi-actors/dist/lib/draft-review.d.ts +56 -0
  36. package/node_modules/@llblab/pi-actors/dist/lib/draft-review.js +254 -0
  37. package/node_modules/@llblab/pi-actors/dist/lib/draft-sleep.d.ts +65 -0
  38. package/node_modules/@llblab/pi-actors/dist/lib/draft-sleep.js +467 -0
  39. package/node_modules/@llblab/pi-actors/dist/lib/execution-output.d.ts +25 -0
  40. package/node_modules/@llblab/pi-actors/dist/lib/execution-output.js +88 -0
  41. package/node_modules/@llblab/pi-actors/dist/lib/execution-sessions.d.ts +17 -0
  42. package/node_modules/@llblab/pi-actors/dist/lib/execution-sessions.js +85 -0
  43. package/node_modules/@llblab/pi-actors/dist/lib/execution.d.ts +99 -0
  44. package/node_modules/@llblab/pi-actors/dist/lib/execution.js +725 -0
  45. package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.d.ts +21 -0
  46. package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +141 -0
  47. package/node_modules/@llblab/pi-actors/dist/lib/file-state.d.ts +18 -0
  48. package/node_modules/@llblab/pi-actors/dist/lib/file-state.js +310 -0
  49. package/node_modules/@llblab/pi-actors/dist/lib/identity.d.ts +9 -0
  50. package/node_modules/@llblab/pi-actors/dist/lib/identity.js +27 -0
  51. package/node_modules/@llblab/pi-actors/dist/lib/inspector-actions.d.ts +16 -0
  52. package/node_modules/@llblab/pi-actors/dist/lib/inspector-actions.js +57 -0
  53. package/node_modules/@llblab/pi-actors/dist/lib/inspector-command.d.ts +7 -0
  54. package/node_modules/@llblab/pi-actors/dist/lib/inspector-command.js +37 -0
  55. package/node_modules/@llblab/pi-actors/dist/lib/inspector-overlay.d.ts +100 -0
  56. package/node_modules/@llblab/pi-actors/dist/lib/inspector-overlay.js +824 -0
  57. package/node_modules/@llblab/pi-actors/dist/lib/inspector.d.ts +20 -0
  58. package/node_modules/@llblab/pi-actors/dist/lib/inspector.js +136 -0
  59. package/node_modules/@llblab/pi-actors/dist/lib/limits.d.ts +28 -0
  60. package/node_modules/@llblab/pi-actors/dist/lib/limits.js +28 -0
  61. package/node_modules/@llblab/pi-actors/dist/lib/model-context.d.ts +56 -0
  62. package/node_modules/@llblab/pi-actors/dist/lib/model-context.js +220 -0
  63. package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +186 -0
  64. package/node_modules/@llblab/pi-actors/dist/lib/observability.js +951 -0
  65. package/node_modules/@llblab/pi-actors/dist/lib/paths.d.ts +27 -0
  66. package/node_modules/@llblab/pi-actors/dist/lib/paths.js +72 -0
  67. package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +19 -0
  68. package/node_modules/@llblab/pi-actors/dist/lib/pi.js +21 -0
  69. package/node_modules/@llblab/pi-actors/dist/lib/preflight-diagnostics.d.ts +27 -0
  70. package/node_modules/@llblab/pi-actors/dist/lib/preflight-diagnostics.js +86 -0
  71. package/node_modules/@llblab/pi-actors/dist/lib/prompts.d.ts +24 -0
  72. package/node_modules/@llblab/pi-actors/dist/lib/prompts.js +49 -0
  73. package/node_modules/@llblab/pi-actors/dist/lib/recipe-control.d.ts +7 -0
  74. package/node_modules/@llblab/pi-actors/dist/lib/recipe-control.js +43 -0
  75. package/node_modules/@llblab/pi-actors/dist/lib/recipes-context.d.ts +36 -0
  76. package/node_modules/@llblab/pi-actors/dist/lib/recipes-context.js +197 -0
  77. package/node_modules/@llblab/pi-actors/dist/lib/recipes-discovery.d.ts +77 -0
  78. package/node_modules/@llblab/pi-actors/dist/lib/recipes-discovery.js +783 -0
  79. package/node_modules/@llblab/pi-actors/dist/lib/recipes-references.d.ts +113 -0
  80. package/node_modules/@llblab/pi-actors/dist/lib/recipes-references.js +1108 -0
  81. package/node_modules/@llblab/pi-actors/dist/lib/recipes-usage.d.ts +21 -0
  82. package/node_modules/@llblab/pi-actors/dist/lib/recipes-usage.js +494 -0
  83. package/node_modules/@llblab/pi-actors/dist/lib/registry.d.ts +67 -0
  84. package/node_modules/@llblab/pi-actors/dist/lib/registry.js +504 -0
  85. package/node_modules/@llblab/pi-actors/dist/lib/review-control.d.ts +14 -0
  86. package/node_modules/@llblab/pi-actors/dist/lib/review-control.js +110 -0
  87. package/node_modules/@llblab/pi-actors/dist/lib/review-diagnostics.d.ts +11 -0
  88. package/node_modules/@llblab/pi-actors/dist/lib/review-diagnostics.js +148 -0
  89. package/node_modules/@llblab/pi-actors/dist/lib/review-projection.d.ts +14 -0
  90. package/node_modules/@llblab/pi-actors/dist/lib/review-projection.js +166 -0
  91. package/node_modules/@llblab/pi-actors/dist/lib/run-evidence-policy.d.ts +95 -0
  92. package/node_modules/@llblab/pi-actors/dist/lib/run-evidence-policy.js +177 -0
  93. package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.d.ts +18 -0
  94. package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +125 -0
  95. package/node_modules/@llblab/pi-actors/dist/lib/runs-artifacts.d.ts +21 -0
  96. package/node_modules/@llblab/pi-actors/dist/lib/runs-artifacts.js +68 -0
  97. package/node_modules/@llblab/pi-actors/dist/lib/runs-control-delivery.d.ts +28 -0
  98. package/node_modules/@llblab/pi-actors/dist/lib/runs-control-delivery.js +150 -0
  99. package/node_modules/@llblab/pi-actors/dist/lib/runs-control.d.ts +21 -0
  100. package/node_modules/@llblab/pi-actors/dist/lib/runs-control.js +89 -0
  101. package/node_modules/@llblab/pi-actors/dist/lib/runs-controls.d.ts +39 -0
  102. package/node_modules/@llblab/pi-actors/dist/lib/runs-controls.js +283 -0
  103. package/node_modules/@llblab/pi-actors/dist/lib/runs-identity.d.ts +5 -0
  104. package/node_modules/@llblab/pi-actors/dist/lib/runs-identity.js +11 -0
  105. package/node_modules/@llblab/pi-actors/dist/lib/runs-index.d.ts +27 -0
  106. package/node_modules/@llblab/pi-actors/dist/lib/runs-index.js +142 -0
  107. package/node_modules/@llblab/pi-actors/dist/lib/runs-ownership.d.ts +7 -0
  108. package/node_modules/@llblab/pi-actors/dist/lib/runs-ownership.js +96 -0
  109. package/node_modules/@llblab/pi-actors/dist/lib/runs-parent-teardown.d.ts +51 -0
  110. package/node_modules/@llblab/pi-actors/dist/lib/runs-parent-teardown.js +172 -0
  111. package/node_modules/@llblab/pi-actors/dist/lib/runs-process.d.ts +22 -0
  112. package/node_modules/@llblab/pi-actors/dist/lib/runs-process.js +125 -0
  113. package/node_modules/@llblab/pi-actors/dist/lib/runs-retention.d.ts +18 -0
  114. package/node_modules/@llblab/pi-actors/dist/lib/runs-retention.js +108 -0
  115. package/node_modules/@llblab/pi-actors/dist/lib/runs-start.d.ts +12 -0
  116. package/node_modules/@llblab/pi-actors/dist/lib/runs-start.js +68 -0
  117. package/node_modules/@llblab/pi-actors/dist/lib/runs-status.d.ts +10 -0
  118. package/node_modules/@llblab/pi-actors/dist/lib/runs-status.js +68 -0
  119. package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.d.ts +48 -0
  120. package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.js +491 -0
  121. package/node_modules/@llblab/pi-actors/dist/lib/runtime-identity.d.ts +7 -0
  122. package/node_modules/@llblab/pi-actors/dist/lib/runtime-identity.js +35 -0
  123. package/node_modules/@llblab/pi-actors/dist/lib/runtime-triage.d.ts +29 -0
  124. package/node_modules/@llblab/pi-actors/dist/lib/runtime-triage.js +60 -0
  125. package/node_modules/@llblab/pi-actors/dist/lib/runtime.d.ts +69 -0
  126. package/node_modules/@llblab/pi-actors/dist/lib/runtime.js +339 -0
  127. package/node_modules/@llblab/pi-actors/dist/lib/schema.d.ts +60 -0
  128. package/node_modules/@llblab/pi-actors/dist/lib/schema.js +428 -0
  129. package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.d.ts +45 -0
  130. package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.js +204 -0
  131. package/node_modules/@llblab/pi-actors/dist/lib/state-readers.d.ts +21 -0
  132. package/node_modules/@llblab/pi-actors/dist/lib/state-readers.js +74 -0
  133. package/node_modules/@llblab/pi-actors/dist/lib/temp.d.ts +10 -0
  134. package/node_modules/@llblab/pi-actors/dist/lib/temp.js +90 -0
  135. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-lineage-transaction.d.ts +27 -0
  136. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-lineage-transaction.js +597 -0
  137. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-lineage.d.ts +24 -0
  138. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-lineage.js +98 -0
  139. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-scheduler.d.ts +80 -0
  140. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-scheduler.js +494 -0
  141. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-transaction.d.ts +50 -0
  142. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-transaction.js +362 -0
  143. package/node_modules/@llblab/pi-actors/dist/lib/tool-review.d.ts +56 -0
  144. package/node_modules/@llblab/pi-actors/dist/lib/tool-review.js +197 -0
  145. package/node_modules/@llblab/pi-actors/dist/lib/tools-access.d.ts +19 -0
  146. package/node_modules/@llblab/pi-actors/dist/lib/tools-access.js +44 -0
  147. package/node_modules/@llblab/pi-actors/dist/lib/tools-inspect.d.ts +15 -0
  148. package/node_modules/@llblab/pi-actors/dist/lib/tools-inspect.js +532 -0
  149. package/node_modules/@llblab/pi-actors/dist/lib/tools-local.d.ts +17 -0
  150. package/node_modules/@llblab/pi-actors/dist/lib/tools-local.js +191 -0
  151. package/node_modules/@llblab/pi-actors/dist/lib/tools-message.d.ts +9 -0
  152. package/node_modules/@llblab/pi-actors/dist/lib/tools-message.js +139 -0
  153. package/node_modules/@llblab/pi-actors/dist/lib/tools-register.d.ts +18 -0
  154. package/node_modules/@llblab/pi-actors/dist/lib/tools-register.js +41 -0
  155. package/node_modules/@llblab/pi-actors/dist/lib/tools-response.d.ts +20 -0
  156. package/node_modules/@llblab/pi-actors/dist/lib/tools-response.js +243 -0
  157. package/node_modules/@llblab/pi-actors/dist/lib/tools-spawn.d.ts +15 -0
  158. package/node_modules/@llblab/pi-actors/dist/lib/tools-spawn.js +133 -0
  159. package/node_modules/@llblab/pi-actors/dist/lib/tools.d.ts +28 -0
  160. package/node_modules/@llblab/pi-actors/dist/lib/tools.js +49 -0
  161. package/node_modules/@llblab/pi-actors/dist/lib/trace-projection.d.ts +22 -0
  162. package/node_modules/@llblab/pi-actors/dist/lib/trace-projection.js +231 -0
  163. package/node_modules/@llblab/pi-actors/dist/pi-actors/index.js +1 -0
  164. package/node_modules/@llblab/pi-actors/dist/scripts/async-runner.mjs +555 -0
  165. package/node_modules/@llblab/pi-actors/dist/scripts/build-dist.mjs +60 -0
  166. package/node_modules/@llblab/pi-actors/dist/scripts/conformance.mjs +63 -0
  167. package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +126 -0
  168. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/command-validate.json +13 -0
  169. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/jsonl-tail.json +10 -0
  170. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/recipe-validate.json +11 -0
  171. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/resource-locker-snapshot.json +11 -0
  172. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/resource-locker.json +25 -0
  173. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/run-ops-snapshot.json +15 -0
  174. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/run-state-files.json +13 -0
  175. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/run-summary.json +9 -0
  176. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/diagnostics.md +44 -0
  177. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/persistent-tools.md +76 -0
  178. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/recipes.md +51 -0
  179. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/runs.md +41 -0
  180. package/node_modules/@llblab/pi-actors/dist/skills/actors/scripts/resource-locker.mjs +425 -0
  181. package/node_modules/@llblab/pi-actors/dist/skills/actors/scripts/run-utils.mjs +164 -0
  182. package/node_modules/@llblab/pi-actors/dist/skills/actors/scripts/validate-recipe.mjs +370 -0
  183. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/SKILL.md +33 -0
  184. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/bundle.json +77 -0
  185. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/file-write.json +14 -0
  186. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/manifest.json +14 -0
  187. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/report.json +39 -0
  188. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/write.json +53 -0
  189. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/scripts/artifact-utils.mjs +63 -0
  190. package/node_modules/@llblab/pi-actors/dist/skills/music-player/SKILL.md +57 -0
  191. package/node_modules/@llblab/pi-actors/dist/skills/music-player/genapps/music-player.mjs +360 -0
  192. package/node_modules/@llblab/pi-actors/dist/skills/music-player/recipes/playback.json +29 -0
  193. package/node_modules/@llblab/pi-actors/dist/skills/music-player/scripts/playback-client.mjs +143 -0
  194. package/node_modules/@llblab/pi-actors/dist/skills/music-player/scripts/playback.mjs +1446 -0
  195. package/node_modules/@llblab/pi-actors/dist/skills/project-work/SKILL.md +37 -0
  196. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/changelog-head.json +11 -0
  197. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/changelog-section.json +11 -0
  198. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/docs-maintenance.json +66 -0
  199. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/git-log.json +11 -0
  200. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/git-status.json +9 -0
  201. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/markdown-index.json +14 -0
  202. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/package-summary.json +9 -0
  203. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/release-readiness.json +115 -0
  204. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/release-summary.json +74 -0
  205. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/repo-health.json +75 -0
  206. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/run-ops.json +56 -0
  207. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/skill-summary.json +11 -0
  208. package/node_modules/@llblab/pi-actors/dist/skills/project-work/scripts/project-utils.mjs +89 -0
  209. package/node_modules/@llblab/pi-actors/dist/skills/recipe-memory/SKILL.md +36 -0
  210. package/node_modules/@llblab/pi-actors/dist/skills/recipe-memory/recipes/draft-review.json +14 -0
  211. package/node_modules/@llblab/pi-actors/dist/skills/recipe-memory/recipes/tool-review.json +14 -0
  212. package/node_modules/@llblab/pi-actors/dist/skills/swarm/SKILL.md +84 -0
  213. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/architect.json +82 -0
  214. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/checkpoint-continuation.json +51 -0
  215. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/development-tasking.json +67 -0
  216. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/lens-review.json +63 -0
  217. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/quorum-review.json +65 -0
  218. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/research-synthesis.json +81 -0
  219. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/review-readiness.json +59 -0
  220. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-artifact.json +21 -0
  221. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-checkpoint.json +21 -0
  222. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-conflict-report.json +19 -0
  223. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-contradiction-map.json +20 -0
  224. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-critic.json +22 -0
  225. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-evidence-map.json +20 -0
  226. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-followup.json +21 -0
  227. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-judge.json +22 -0
  228. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-merge.json +24 -0
  229. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-normalize.json +20 -0
  230. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-plan.json +20 -0
  231. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-preflight.json +18 -0
  232. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-prompt.json +16 -0
  233. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-prompts.json +39 -0
  234. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-quorum.json +31 -0
  235. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-review-coordinator.json +170 -0
  236. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-review.json +26 -0
  237. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-task-card.json +22 -0
  238. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-tools.json +15 -0
  239. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-verify.json +23 -0
  240. package/node_modules/@llblab/pi-actors/dist/skills/swarm/references/development-swarm.md +189 -0
  241. package/node_modules/@llblab/pi-actors/dist/skills/swarm/references/review-swarms.md +115 -0
  242. package/node_modules/@llblab/pi-actors/docs/README.md +20 -0
  243. package/node_modules/@llblab/pi-actors/docs/actor-inspector.md +50 -0
  244. package/node_modules/@llblab/pi-actors/docs/async-runs.md +141 -0
  245. package/node_modules/@llblab/pi-actors/docs/command-templates.md +321 -0
  246. package/node_modules/@llblab/pi-actors/docs/recipe-library.md +89 -0
  247. package/node_modules/@llblab/pi-actors/docs/releasing.md +28 -0
  248. package/node_modules/@llblab/pi-actors/docs/template-recipes.md +175 -0
  249. package/node_modules/@llblab/pi-actors/docs/tool-registry.md +90 -0
  250. package/node_modules/@llblab/pi-actors/fixtures/protocol/artifact-manifest.json +9 -0
  251. package/node_modules/@llblab/pi-actors/fixtures/protocol/control-endpoint.json +6 -0
  252. package/node_modules/@llblab/pi-actors/fixtures/protocol/control-record.json +9 -0
  253. package/node_modules/@llblab/pi-actors/fixtures/protocol/recipe-summary.json +8 -0
  254. package/node_modules/@llblab/pi-actors/fixtures/protocol/run-state.json +10 -0
  255. package/node_modules/@llblab/pi-actors/fixtures/protocol/trace-event.json +9 -0
  256. package/node_modules/@llblab/pi-actors/index.ts +30 -0
  257. package/node_modules/@llblab/pi-actors/lib/async-runs.ts +1245 -0
  258. package/node_modules/@llblab/pi-actors/lib/automatic-review-runtime.ts +148 -0
  259. package/node_modules/@llblab/pi-actors/lib/command-templates.ts +1116 -0
  260. package/node_modules/@llblab/pi-actors/lib/config.ts +261 -0
  261. package/node_modules/@llblab/pi-actors/lib/control-projection.ts +105 -0
  262. package/node_modules/@llblab/pi-actors/lib/control.ts +117 -0
  263. package/node_modules/@llblab/pi-actors/lib/draft-consolidation-transaction.ts +821 -0
  264. package/node_modules/@llblab/pi-actors/lib/draft-consolidation.ts +181 -0
  265. package/node_modules/@llblab/pi-actors/lib/draft-review.ts +325 -0
  266. package/node_modules/@llblab/pi-actors/lib/draft-sleep.ts +575 -0
  267. package/node_modules/@llblab/pi-actors/lib/execution-output.ts +123 -0
  268. package/node_modules/@llblab/pi-actors/lib/execution-sessions.ts +111 -0
  269. package/node_modules/@llblab/pi-actors/lib/execution.ts +1153 -0
  270. package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +181 -0
  271. package/node_modules/@llblab/pi-actors/lib/file-state.ts +306 -0
  272. package/node_modules/@llblab/pi-actors/lib/identity.ts +29 -0
  273. package/node_modules/@llblab/pi-actors/lib/inspector-actions.ts +79 -0
  274. package/node_modules/@llblab/pi-actors/lib/inspector-command.ts +54 -0
  275. package/node_modules/@llblab/pi-actors/lib/inspector-overlay.ts +901 -0
  276. package/node_modules/@llblab/pi-actors/lib/inspector.ts +204 -0
  277. package/node_modules/@llblab/pi-actors/lib/limits.ts +29 -0
  278. package/node_modules/@llblab/pi-actors/lib/model-context.ts +359 -0
  279. package/node_modules/@llblab/pi-actors/lib/observability.ts +1337 -0
  280. package/node_modules/@llblab/pi-actors/lib/paths.ts +111 -0
  281. package/node_modules/@llblab/pi-actors/lib/pi.ts +47 -0
  282. package/node_modules/@llblab/pi-actors/lib/preflight-diagnostics.ts +132 -0
  283. package/node_modules/@llblab/pi-actors/lib/prompts.ts +69 -0
  284. package/node_modules/@llblab/pi-actors/lib/recipe-control.ts +52 -0
  285. package/node_modules/@llblab/pi-actors/lib/recipes-context.ts +268 -0
  286. package/node_modules/@llblab/pi-actors/lib/recipes-discovery.ts +1060 -0
  287. package/node_modules/@llblab/pi-actors/lib/recipes-references.ts +1598 -0
  288. package/node_modules/@llblab/pi-actors/lib/recipes-usage.ts +638 -0
  289. package/node_modules/@llblab/pi-actors/lib/registry.ts +806 -0
  290. package/node_modules/@llblab/pi-actors/lib/review-control.ts +136 -0
  291. package/node_modules/@llblab/pi-actors/lib/review-diagnostics.ts +164 -0
  292. package/node_modules/@llblab/pi-actors/lib/review-projection.ts +196 -0
  293. package/node_modules/@llblab/pi-actors/lib/run-evidence-policy.ts +242 -0
  294. package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +155 -0
  295. package/node_modules/@llblab/pi-actors/lib/runs-artifacts.ts +96 -0
  296. package/node_modules/@llblab/pi-actors/lib/runs-control-delivery.ts +209 -0
  297. package/node_modules/@llblab/pi-actors/lib/runs-control.ts +148 -0
  298. package/node_modules/@llblab/pi-actors/lib/runs-controls.ts +282 -0
  299. package/node_modules/@llblab/pi-actors/lib/runs-identity.ts +14 -0
  300. package/node_modules/@llblab/pi-actors/lib/runs-index.ts +192 -0
  301. package/node_modules/@llblab/pi-actors/lib/runs-ownership.ts +136 -0
  302. package/node_modules/@llblab/pi-actors/lib/runs-parent-teardown.ts +257 -0
  303. package/node_modules/@llblab/pi-actors/lib/runs-process.ts +174 -0
  304. package/node_modules/@llblab/pi-actors/lib/runs-retention.ts +140 -0
  305. package/node_modules/@llblab/pi-actors/lib/runs-start.ts +113 -0
  306. package/node_modules/@llblab/pi-actors/lib/runs-status.ts +101 -0
  307. package/node_modules/@llblab/pi-actors/lib/runs-trace.ts +611 -0
  308. package/node_modules/@llblab/pi-actors/lib/runtime-identity.ts +39 -0
  309. package/node_modules/@llblab/pi-actors/lib/runtime-triage.ts +106 -0
  310. package/node_modules/@llblab/pi-actors/lib/runtime.ts +430 -0
  311. package/node_modules/@llblab/pi-actors/lib/schema.ts +525 -0
  312. package/node_modules/@llblab/pi-actors/lib/session-evidence.ts +302 -0
  313. package/node_modules/@llblab/pi-actors/lib/state-readers.ts +93 -0
  314. package/node_modules/@llblab/pi-actors/lib/temp.ts +99 -0
  315. package/node_modules/@llblab/pi-actors/lib/tool-review-lineage-transaction.ts +881 -0
  316. package/node_modules/@llblab/pi-actors/lib/tool-review-lineage.ts +145 -0
  317. package/node_modules/@llblab/pi-actors/lib/tool-review-scheduler.ts +635 -0
  318. package/node_modules/@llblab/pi-actors/lib/tool-review-transaction.ts +563 -0
  319. package/node_modules/@llblab/pi-actors/lib/tool-review.ts +270 -0
  320. package/node_modules/@llblab/pi-actors/lib/tools-access.ts +68 -0
  321. package/node_modules/@llblab/pi-actors/lib/tools-inspect.ts +673 -0
  322. package/node_modules/@llblab/pi-actors/lib/tools-local.ts +303 -0
  323. package/node_modules/@llblab/pi-actors/lib/tools-message.ts +176 -0
  324. package/node_modules/@llblab/pi-actors/lib/tools-register.ts +63 -0
  325. package/node_modules/@llblab/pi-actors/lib/tools-response.ts +285 -0
  326. package/node_modules/@llblab/pi-actors/lib/tools-spawn.ts +212 -0
  327. package/node_modules/@llblab/pi-actors/lib/tools.ts +88 -0
  328. package/node_modules/@llblab/pi-actors/lib/trace-projection.ts +306 -0
  329. package/node_modules/@llblab/pi-actors/package.json +76 -0
  330. package/node_modules/@llblab/pi-actors/scripts/async-runner.mjs +555 -0
  331. package/node_modules/@llblab/pi-actors/scripts/build-dist.mjs +60 -0
  332. package/node_modules/@llblab/pi-actors/scripts/conformance.mjs +63 -0
  333. package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +126 -0
  334. package/node_modules/@llblab/pi-actors/skills/actors/recipes/command-validate.json +13 -0
  335. package/node_modules/@llblab/pi-actors/skills/actors/recipes/jsonl-tail.json +10 -0
  336. package/node_modules/@llblab/pi-actors/skills/actors/recipes/recipe-validate.json +11 -0
  337. package/node_modules/@llblab/pi-actors/skills/actors/recipes/resource-locker-snapshot.json +11 -0
  338. package/node_modules/@llblab/pi-actors/skills/actors/recipes/resource-locker.json +25 -0
  339. package/node_modules/@llblab/pi-actors/skills/actors/recipes/run-ops-snapshot.json +15 -0
  340. package/node_modules/@llblab/pi-actors/skills/actors/recipes/run-state-files.json +13 -0
  341. package/node_modules/@llblab/pi-actors/skills/actors/recipes/run-summary.json +9 -0
  342. package/node_modules/@llblab/pi-actors/skills/actors/references/diagnostics.md +44 -0
  343. package/node_modules/@llblab/pi-actors/skills/actors/references/persistent-tools.md +76 -0
  344. package/node_modules/@llblab/pi-actors/skills/actors/references/recipes.md +51 -0
  345. package/node_modules/@llblab/pi-actors/skills/actors/references/runs.md +41 -0
  346. package/node_modules/@llblab/pi-actors/skills/actors/scripts/resource-locker.mjs +425 -0
  347. package/node_modules/@llblab/pi-actors/skills/actors/scripts/run-utils.mjs +164 -0
  348. package/node_modules/@llblab/pi-actors/skills/actors/scripts/validate-recipe.mjs +370 -0
  349. package/node_modules/@llblab/pi-actors/skills/artifacts/SKILL.md +33 -0
  350. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/bundle.json +77 -0
  351. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/file-write.json +14 -0
  352. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/manifest.json +14 -0
  353. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/report.json +39 -0
  354. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/write.json +53 -0
  355. package/node_modules/@llblab/pi-actors/skills/artifacts/scripts/artifact-utils.mjs +63 -0
  356. package/node_modules/@llblab/pi-actors/skills/music-player/SKILL.md +57 -0
  357. package/node_modules/@llblab/pi-actors/skills/music-player/genapps/music-player.mjs +360 -0
  358. package/node_modules/@llblab/pi-actors/skills/music-player/recipes/playback.json +29 -0
  359. package/node_modules/@llblab/pi-actors/skills/music-player/scripts/playback-client.mjs +143 -0
  360. package/node_modules/@llblab/pi-actors/skills/music-player/scripts/playback.mjs +1446 -0
  361. package/node_modules/@llblab/pi-actors/skills/project-work/SKILL.md +37 -0
  362. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/changelog-head.json +11 -0
  363. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/changelog-section.json +11 -0
  364. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/docs-maintenance.json +66 -0
  365. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/git-log.json +11 -0
  366. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/git-status.json +9 -0
  367. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/markdown-index.json +14 -0
  368. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/package-summary.json +9 -0
  369. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/release-readiness.json +115 -0
  370. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/release-summary.json +74 -0
  371. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/repo-health.json +75 -0
  372. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/run-ops.json +56 -0
  373. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/skill-summary.json +11 -0
  374. package/node_modules/@llblab/pi-actors/skills/project-work/scripts/project-utils.mjs +89 -0
  375. package/node_modules/@llblab/pi-actors/skills/recipe-memory/SKILL.md +36 -0
  376. package/node_modules/@llblab/pi-actors/skills/recipe-memory/recipes/draft-review.json +14 -0
  377. package/node_modules/@llblab/pi-actors/skills/recipe-memory/recipes/tool-review.json +14 -0
  378. package/node_modules/@llblab/pi-actors/skills/swarm/SKILL.md +84 -0
  379. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/architect.json +82 -0
  380. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/checkpoint-continuation.json +51 -0
  381. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/development-tasking.json +67 -0
  382. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/lens-review.json +63 -0
  383. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/quorum-review.json +65 -0
  384. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/research-synthesis.json +81 -0
  385. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/review-readiness.json +59 -0
  386. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-artifact.json +21 -0
  387. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-checkpoint.json +21 -0
  388. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-conflict-report.json +19 -0
  389. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-contradiction-map.json +20 -0
  390. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-critic.json +22 -0
  391. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-evidence-map.json +20 -0
  392. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-followup.json +21 -0
  393. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-judge.json +22 -0
  394. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-merge.json +24 -0
  395. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-normalize.json +20 -0
  396. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-plan.json +20 -0
  397. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-preflight.json +18 -0
  398. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-prompt.json +16 -0
  399. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-prompts.json +39 -0
  400. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-quorum.json +31 -0
  401. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-review-coordinator.json +170 -0
  402. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-review.json +26 -0
  403. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-task-card.json +22 -0
  404. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-tools.json +15 -0
  405. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-verify.json +23 -0
  406. package/node_modules/@llblab/pi-actors/skills/swarm/references/development-swarm.md +189 -0
  407. package/node_modules/@llblab/pi-actors/skills/swarm/references/review-swarms.md +115 -0
  408. package/node_modules/@llblab/pi-codex-usage/AGENTS.md +17 -0
  409. package/node_modules/@llblab/pi-codex-usage/BACKLOG.md +8 -0
  410. package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +80 -0
  411. package/node_modules/@llblab/pi-codex-usage/LICENSE +22 -0
  412. package/node_modules/@llblab/pi-codex-usage/README.md +113 -0
  413. package/node_modules/@llblab/pi-codex-usage/banner.jpg +0 -0
  414. package/node_modules/@llblab/pi-codex-usage/index.ts +1525 -0
  415. package/node_modules/@llblab/pi-codex-usage/package.json +59 -0
  416. package/node_modules/@llblab/pi-grow-loop/AGENTS.md +56 -0
  417. package/node_modules/@llblab/pi-grow-loop/BACKLOG.md +3 -0
  418. package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +126 -0
  419. package/node_modules/@llblab/pi-grow-loop/README.md +216 -0
  420. package/node_modules/@llblab/pi-grow-loop/banner.jpg +0 -0
  421. package/node_modules/@llblab/pi-grow-loop/index.ts +219 -0
  422. package/node_modules/@llblab/pi-grow-loop/package.json +64 -0
  423. package/node_modules/@llblab/pi-grow-loop/skills/grow-loop/SKILL.md +131 -0
  424. package/node_modules/@llblab/pi-grow-loop/skills/while-true/SKILL.md +233 -0
  425. package/node_modules/@llblab/pi-telegram/AGENTS.md +157 -0
  426. package/node_modules/@llblab/pi-telegram/BACKLOG.md +15 -0
  427. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +886 -0
  428. package/node_modules/@llblab/pi-telegram/README.md +330 -0
  429. package/node_modules/@llblab/pi-telegram/api/activity.ts +15 -0
  430. package/node_modules/@llblab/pi-telegram/api/commands.ts +11 -0
  431. package/node_modules/@llblab/pi-telegram/api/delivery.ts +21 -0
  432. package/node_modules/@llblab/pi-telegram/api/inbound.ts +14 -0
  433. package/node_modules/@llblab/pi-telegram/api/keyboard.ts +11 -0
  434. package/node_modules/@llblab/pi-telegram/api/outbound.ts +11 -0
  435. package/node_modules/@llblab/pi-telegram/api/sections.ts +17 -0
  436. package/node_modules/@llblab/pi-telegram/api/status.ts +12 -0
  437. package/node_modules/@llblab/pi-telegram/api/updates.ts +16 -0
  438. package/node_modules/@llblab/pi-telegram/api/voice.ts +24 -0
  439. package/node_modules/@llblab/pi-telegram/docs/README.md +25 -0
  440. package/node_modules/@llblab/pi-telegram/docs/activity.md +304 -0
  441. package/node_modules/@llblab/pi-telegram/docs/architecture.md +418 -0
  442. package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +48 -0
  443. package/node_modules/@llblab/pi-telegram/docs/command-templates.md +365 -0
  444. package/node_modules/@llblab/pi-telegram/docs/compact-matrix-literal.md +176 -0
  445. package/node_modules/@llblab/pi-telegram/docs/delivery.md +225 -0
  446. package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +310 -0
  447. package/node_modules/@llblab/pi-telegram/docs/inbound.md +136 -0
  448. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +467 -0
  449. package/node_modules/@llblab/pi-telegram/docs/outbound.md +193 -0
  450. package/node_modules/@llblab/pi-telegram/docs/public-api.md +599 -0
  451. package/node_modules/@llblab/pi-telegram/docs/sections.md +452 -0
  452. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +256 -0
  453. package/node_modules/@llblab/pi-telegram/docs/updates.md +171 -0
  454. package/node_modules/@llblab/pi-telegram/docs/voice.md +217 -0
  455. package/node_modules/@llblab/pi-telegram/index.ts +1336 -0
  456. package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +714 -0
  457. package/node_modules/@llblab/pi-telegram/lib/activity.ts +782 -0
  458. package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +121 -0
  459. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +1129 -0
  460. package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +379 -0
  461. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +1941 -0
  462. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +2119 -0
  463. package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +244 -0
  464. package/node_modules/@llblab/pi-telegram/lib/bus.ts +2645 -0
  465. package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +954 -0
  466. package/node_modules/@llblab/pi-telegram/lib/commands.ts +1854 -0
  467. package/node_modules/@llblab/pi-telegram/lib/config.ts +1143 -0
  468. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +891 -0
  469. package/node_modules/@llblab/pi-telegram/lib/generative-app-worker.mjs +104 -0
  470. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +958 -0
  471. package/node_modules/@llblab/pi-telegram/lib/inbound.ts +824 -0
  472. package/node_modules/@llblab/pi-telegram/lib/journal.ts +3140 -0
  473. package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +59 -0
  474. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +623 -0
  475. package/node_modules/@llblab/pi-telegram/lib/locks.ts +1422 -0
  476. package/node_modules/@llblab/pi-telegram/lib/logs.ts +393 -0
  477. package/node_modules/@llblab/pi-telegram/lib/media.ts +921 -0
  478. package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +1182 -0
  479. package/node_modules/@llblab/pi-telegram/lib/menu-queue.ts +926 -0
  480. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +876 -0
  481. package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +274 -0
  482. package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +185 -0
  483. package/node_modules/@llblab/pi-telegram/lib/menu.ts +867 -0
  484. package/node_modules/@llblab/pi-telegram/lib/model.ts +672 -0
  485. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +981 -0
  486. package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +331 -0
  487. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +515 -0
  488. package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +285 -0
  489. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +1007 -0
  490. package/node_modules/@llblab/pi-telegram/lib/ownership.ts +298 -0
  491. package/node_modules/@llblab/pi-telegram/lib/paths.ts +127 -0
  492. package/node_modules/@llblab/pi-telegram/lib/pi.ts +197 -0
  493. package/node_modules/@llblab/pi-telegram/lib/polling.ts +1588 -0
  494. package/node_modules/@llblab/pi-telegram/lib/preview.ts +846 -0
  495. package/node_modules/@llblab/pi-telegram/lib/prompt-templates.ts +158 -0
  496. package/node_modules/@llblab/pi-telegram/lib/prompts.ts +218 -0
  497. package/node_modules/@llblab/pi-telegram/lib/queue.ts +3075 -0
  498. package/node_modules/@llblab/pi-telegram/lib/recovery.ts +464 -0
  499. package/node_modules/@llblab/pi-telegram/lib/rendering.ts +1213 -0
  500. package/node_modules/@llblab/pi-telegram/lib/replies.ts +892 -0
  501. package/node_modules/@llblab/pi-telegram/lib/routing.ts +2889 -0
  502. package/node_modules/@llblab/pi-telegram/lib/runtime.ts +628 -0
  503. package/node_modules/@llblab/pi-telegram/lib/sections.ts +710 -0
  504. package/node_modules/@llblab/pi-telegram/lib/setup.ts +220 -0
  505. package/node_modules/@llblab/pi-telegram/lib/skills.ts +21 -0
  506. package/node_modules/@llblab/pi-telegram/lib/status.ts +1550 -0
  507. package/node_modules/@llblab/pi-telegram/lib/sync.ts +883 -0
  508. package/node_modules/@llblab/pi-telegram/lib/target.ts +49 -0
  509. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +1747 -0
  510. package/node_modules/@llblab/pi-telegram/lib/text-groups.ts +487 -0
  511. package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +1002 -0
  512. package/node_modules/@llblab/pi-telegram/lib/threads.ts +3183 -0
  513. package/node_modules/@llblab/pi-telegram/lib/time-injection.ts +78 -0
  514. package/node_modules/@llblab/pi-telegram/lib/turns.ts +753 -0
  515. package/node_modules/@llblab/pi-telegram/lib/updates.ts +4950 -0
  516. package/node_modules/@llblab/pi-telegram/lib/voice.ts +340 -0
  517. package/node_modules/@llblab/pi-telegram/package.json +83 -0
  518. package/node_modules/@llblab/pi-telegram/screenshot.png +0 -0
  519. package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +435 -0
  520. package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/SKILL.md +241 -0
  521. package/node_modules/@llblab/pi-telegram/skills/generative-apps/SKILL.md +114 -0
  522. package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/SKILL.md +149 -0
  523. package/package.json +67 -0
@@ -0,0 +1,1550 @@
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
+
7
+ const TELEGRAM_STATUS_DEFAULT_PROFILE_NAME = "default";
8
+
9
+ export type TelegramStatusQueueLane = "control" | "priority" | "default";
10
+
11
+ export interface TelegramUsageStats {
12
+ totalInput: number;
13
+ totalOutput: number;
14
+ totalCacheRead: number;
15
+ totalCacheWrite: number;
16
+ totalCost: number;
17
+ }
18
+
19
+ interface TelegramUsageMessage {
20
+ role: string;
21
+ usage?: {
22
+ input: number;
23
+ output: number;
24
+ cacheRead: number;
25
+ cacheWrite: number;
26
+ cost: { total: number };
27
+ };
28
+ }
29
+
30
+ interface TelegramStatusSessionEntry {
31
+ type: string;
32
+ message?: TelegramUsageMessage;
33
+ }
34
+
35
+ interface TelegramContextUsage {
36
+ contextWindow?: number;
37
+ percent: number | null;
38
+ }
39
+
40
+ export interface TelegramStatusActiveModel {
41
+ provider?: string;
42
+ id?: string;
43
+ contextWindow?: number;
44
+ }
45
+
46
+ export interface TelegramStatusLineProviderContext {
47
+ activeModel: TelegramStatusActiveModel | undefined;
48
+ }
49
+
50
+ export interface TelegramStatusLineProviderResult {
51
+ label: string;
52
+ value: string;
53
+ }
54
+
55
+ export type TelegramStatusLineProvider = (
56
+ ctx: TelegramStatusLineProviderContext,
57
+ ) => TelegramStatusLineProviderResult | undefined;
58
+
59
+ export interface TelegramStatusContext {
60
+ sessionManager: { getEntries(): TelegramStatusSessionEntry[] };
61
+ getContextUsage(): TelegramContextUsage | undefined;
62
+ isIdle?: () => boolean;
63
+ hasPendingMessages?: () => boolean;
64
+ isCompactionInProgress?: () => boolean;
65
+ modelRegistry: {
66
+ isUsingOAuth(model: TelegramStatusActiveModel): boolean;
67
+ };
68
+ }
69
+
70
+ export type TelegramRuntimeEventDetailValue = string | number | boolean | null;
71
+
72
+ const TELEGRAM_STATUS_LINE_PROVIDER_REGISTRY_KEY =
73
+ "__piTelegramStatusLineProviders__";
74
+ const MAX_RECENT_TELEGRAM_RUNTIME_EVENTS = 10;
75
+ const MAX_TELEGRAM_RUNTIME_EVENT_MESSAGE_LENGTH = 1000;
76
+ const MAX_TELEGRAM_RUNTIME_EVENT_DETAIL_LENGTH = 1000;
77
+
78
+ export interface TelegramRuntimeEvent {
79
+ at: number;
80
+ category: string;
81
+ message: string;
82
+ details?: Record<string, TelegramRuntimeEventDetailValue>;
83
+ }
84
+
85
+ export interface TelegramRuntimeEventInput {
86
+ category: string;
87
+ error?: unknown;
88
+ message?: string;
89
+ details?: Record<string, unknown>;
90
+ }
91
+
92
+ export interface TelegramRuntimeEventRecorder {
93
+ record: (
94
+ category: string,
95
+ error: unknown,
96
+ details?: Record<string, unknown>,
97
+ ) => void;
98
+ getEvents: () => TelegramRuntimeEvent[];
99
+ clear: () => void;
100
+ }
101
+
102
+ export interface TelegramRuntimeEventRecorderOptions {
103
+ getBotToken: () => string | undefined;
104
+ maxEvents?: number;
105
+ now?: () => number;
106
+ }
107
+
108
+ export interface TelegramBridgeStatusBusFollower {
109
+ instanceId: string;
110
+ cwd?: string;
111
+ lastHeartbeatMs: number;
112
+ target?: { chatId: number; threadId?: number };
113
+ protocol?: {
114
+ protocolVersion: number;
115
+ runtimeBuild: string;
116
+ capabilities: string[];
117
+ };
118
+ slot?: string;
119
+ threadName?: string;
120
+ status?: string;
121
+ }
122
+
123
+ export interface TelegramBridgeStatusLocalBus {
124
+ leaderSocketPath?: string;
125
+ leaderTransport?: "pipe" | "socket";
126
+ followerSocketPath?: string;
127
+ followerTransport?: "pipe" | "socket";
128
+ followerRegistered?: boolean;
129
+ followerTarget?: { chatId: number; threadId?: number };
130
+ followerSlot?: string;
131
+ followerThreadName?: string;
132
+ leaderProtocol?: {
133
+ protocolVersion: number;
134
+ runtimeBuild: string;
135
+ capabilities: string[];
136
+ };
137
+ }
138
+
139
+ export interface TelegramBridgeStatusTopicTarget {
140
+ instanceId?: string;
141
+ status?: string;
142
+ target?: { chatId: number; threadId?: number };
143
+ slot?: string;
144
+ threadName?: string;
145
+ syncStatus?: string;
146
+ lastSyncObservedAtMs?: number;
147
+ lastSyncProbeAtMs?: number;
148
+ lastSyncError?: string;
149
+ lastReconcileAction?: string;
150
+ }
151
+
152
+ export interface TelegramBridgeStatusThreadReservation {
153
+ target?: { chatId: number; threadId?: number };
154
+ slot?: string;
155
+ reason?: string;
156
+ instanceId?: string;
157
+ expiresAtMs?: number;
158
+ lastReconcileAction?: string;
159
+ }
160
+
161
+ export interface TelegramBridgeStatusSyncObservation {
162
+ target?: { chatId: number; threadId?: number };
163
+ syncStatus: string;
164
+ observedAtMs: number;
165
+ instanceId?: string;
166
+ slot?: string;
167
+ lastSyncError?: string;
168
+ lastReconcileAction?: string;
169
+ }
170
+
171
+ export interface TelegramBridgeStatusSyncSlice {
172
+ status: string;
173
+ updatedAtMs?: number;
174
+ suspectAtMs?: number;
175
+ reason?: string;
176
+ lastReconcileAction?: string;
177
+ }
178
+
179
+ export interface TelegramBridgeThreadReconciliationState {
180
+ phase: string;
181
+ event: string;
182
+ atMs: number;
183
+ leaderEpoch?: number | string;
184
+ pendingProvisionCount: number;
185
+ syncActionCount: number;
186
+ cleanupActionCount: number;
187
+ }
188
+
189
+ export type TelegramBridgeBusRole = "leader" | "follower";
190
+ export type TelegramBridgeBusLifecyclePhase = "electing";
191
+
192
+ export interface TelegramBridgePollingState {
193
+ phase: string;
194
+ phaseStartedAtMs?: number;
195
+ currentUpdateId?: number;
196
+ startedAtMs?: number;
197
+ stoppedAtMs?: number;
198
+ lastSuccessfulResponseAtMs?: number;
199
+ lastSuccessfulResponseUpdateCount?: number;
200
+ stopReason?: string;
201
+ }
202
+
203
+ export interface TelegramBridgeInboundWorkerState {
204
+ phase: string;
205
+ generation: number;
206
+ phaseStartedAtMs?: number;
207
+ currentUpdateId?: number;
208
+ blockedReason?: string;
209
+ journalEntryCount: number;
210
+ journalSerializedBytes: number;
211
+ oldestAdmittedAtMs?: number;
212
+ deferredClaimCount: number;
213
+ queuedClaimCount: number;
214
+ foreignQueuedCount: number;
215
+ foreignQueuedOwnerLiveness?: "alive" | "dead" | "unverifiable";
216
+ foreignQueuedOwner?: {
217
+ instanceId: string;
218
+ processId: number;
219
+ processBirthId: string;
220
+ sessionGeneration: number;
221
+ acquisitionId: string;
222
+ acquiredAtMs: number;
223
+ };
224
+ retryWaitCount: number;
225
+ failedCount: number;
226
+ nextRetryUpdateId?: number;
227
+ nextRetryAtMs?: number;
228
+ nextRetryAttemptCount?: number;
229
+ nextRetryFailureClass?: string;
230
+ failedUpdateId?: number;
231
+ failedFailureId?: string;
232
+ failedAttemptCount?: number;
233
+ failedClass?: string;
234
+ failedSummary?: string;
235
+ terminalFailureAtMs?: number;
236
+ unsettledExecutionCount: number;
237
+ lastCompletedUpdateId?: number;
238
+ lastCompletedAtMs?: number;
239
+ lastFailureAtMs?: number;
240
+ lastFailurePhase?: string;
241
+ }
242
+
243
+ export interface TelegramBridgeStatusLineState {
244
+ hasBotToken?: boolean;
245
+ botUsername?: string;
246
+ activeProfileName?: string;
247
+ diagnosticPaths?: { state: string; logs: string };
248
+ allowedUserId?: number;
249
+ botThreadMode?: "unknown" | "enabled" | "disabled";
250
+ botThreadModeUpdatedAtMs?: number;
251
+ botThreadModeAction?: string;
252
+ busRole?: TelegramBridgeBusRole;
253
+ busProtocol?: {
254
+ protocolVersion: number;
255
+ runtimeBuild: string;
256
+ capabilities: string[];
257
+ };
258
+ busLifecyclePhase?: TelegramBridgeBusLifecyclePhase;
259
+ instanceSlot?: string;
260
+ instanceThreadName?: string;
261
+ lockState?: string;
262
+ pollingActive: boolean;
263
+ polling?: TelegramBridgePollingState;
264
+ inboundWorker?: TelegramBridgeInboundWorkerState;
265
+ lastUpdateId?: number;
266
+ activeSourceMessageIds?: number[];
267
+ pendingDispatch: boolean;
268
+ compactionInProgress: boolean;
269
+ activeToolExecutions: number;
270
+ pendingModelSwitch: boolean;
271
+ queuedItems: Array<{ queueLane: TelegramStatusQueueLane }>;
272
+ busFollowers?: TelegramBridgeStatusBusFollower[];
273
+ localBus?: TelegramBridgeStatusLocalBus;
274
+ topicTargets?: TelegramBridgeStatusTopicTarget[];
275
+ threadReservations?: TelegramBridgeStatusThreadReservation[];
276
+ topicSyncObservations?: TelegramBridgeStatusSyncObservation[];
277
+ syncState?: Record<string, TelegramBridgeStatusSyncSlice | undefined>;
278
+ threadReconciliation?: TelegramBridgeThreadReconciliationState;
279
+ busNowMs?: number;
280
+ recentRuntimeEvents: TelegramRuntimeEvent[];
281
+ }
282
+
283
+ export interface TelegramStatusBarTheme {
284
+ fg: (
285
+ token: "accent" | "dim" | "error" | "muted" | "warning" | "success",
286
+ text: string,
287
+ ) => string;
288
+ }
289
+
290
+ export interface TelegramStatusBarState {
291
+ hasBotToken: boolean;
292
+ pollingActive: boolean;
293
+ paired: boolean;
294
+ busRole?: TelegramBridgeBusRole;
295
+ busLifecyclePhase?: TelegramBridgeBusLifecyclePhase;
296
+ instanceSlot?: string;
297
+ instanceThreadName?: string;
298
+ compactionInProgress: boolean;
299
+ processing: boolean;
300
+ processingStatus?: string;
301
+ queuedStatus: string;
302
+ error?: string;
303
+ }
304
+
305
+ export interface TelegramStatusRuntimeContext {
306
+ ui: {
307
+ theme: TelegramStatusBarTheme;
308
+ setStatus: (key: string, text: string) => void;
309
+ };
310
+ }
311
+
312
+ export interface TelegramStatusRuntimeDeps<
313
+ TContext extends TelegramStatusRuntimeContext,
314
+ > {
315
+ statusKey?: string;
316
+ getStatusBarState: (ctx: TContext, error?: string) => TelegramStatusBarState;
317
+ getBridgeStatusLineState: () => TelegramBridgeStatusLineState;
318
+ }
319
+
320
+ export interface TelegramBridgeStatusConfig {
321
+ botToken?: string;
322
+ botUsername?: string;
323
+ allowedUserId?: number;
324
+ lastUpdateId?: number;
325
+ }
326
+
327
+ export interface TelegramBridgeStatusRuntimeDeps<
328
+ TQueueItem extends { queueLane: TelegramStatusQueueLane },
329
+ > {
330
+ statusKey?: string;
331
+ getConfig: () => TelegramBridgeStatusConfig;
332
+ getActiveProfileName?: () => string | undefined;
333
+ getDiagnosticPaths?: (profileName?: string) => {
334
+ state: string;
335
+ logs: string;
336
+ };
337
+ isPollingActive: () => boolean;
338
+ getPollingState?: () => TelegramBridgePollingState;
339
+ getInboundWorkerState?: () => TelegramBridgeInboundWorkerState | undefined;
340
+ getActiveSourceMessageIds: () => number[] | undefined;
341
+ hasActiveTurn: () => boolean;
342
+ hasDispatchPending: () => boolean;
343
+ isCompactionInProgress: () => boolean;
344
+ getActiveToolExecutions: () => number;
345
+ hasPendingModelSwitch: () => boolean;
346
+ getQueuedItems: () => TQueueItem[];
347
+ formatQueuedStatus: (items: TQueueItem[]) => string;
348
+ getRecentRuntimeEvents: () => TelegramRuntimeEvent[];
349
+ getRuntimeLockState?: () => string;
350
+ getBusRole?: () => TelegramBridgeBusRole | undefined;
351
+ getBusProtocol?: () => {
352
+ protocolVersion: number;
353
+ runtimeBuild: string;
354
+ capabilities: string[];
355
+ };
356
+ getBusLifecyclePhase?: () => TelegramBridgeBusLifecyclePhase | undefined;
357
+ getBotThreadMode?: () =>
358
+ | {
359
+ threadMode: "unknown" | "enabled" | "disabled";
360
+ updatedAtMs?: number;
361
+ lastReconcileAction?: string;
362
+ }
363
+ | undefined;
364
+ getBusFollowers?: () => TelegramBridgeStatusBusFollower[];
365
+ getLocalBus?: () => TelegramBridgeStatusLocalBus | undefined;
366
+ getTopicTargets?: () => TelegramBridgeStatusTopicTarget[];
367
+ getThreadReservations?: () => TelegramBridgeStatusThreadReservation[];
368
+ getTopicSyncObservations?: () => TelegramBridgeStatusSyncObservation[];
369
+ getSyncState?: () => Record<
370
+ string,
371
+ TelegramBridgeStatusSyncSlice | undefined
372
+ >;
373
+ getThreadReconciliationState?: () =>
374
+ TelegramBridgeThreadReconciliationState | undefined;
375
+ getInstanceSlot?: () => string | undefined;
376
+ getInstanceThreadName?: () => string | undefined;
377
+ getNowMs?: () => number;
378
+ }
379
+
380
+ export interface TelegramBridgeStatusLineOptions {
381
+ verbose?: boolean;
382
+ }
383
+
384
+ export interface TelegramStatusRuntime<
385
+ TContext extends TelegramStatusRuntimeContext,
386
+ > {
387
+ updateStatus: (ctx: TContext, error?: string) => void;
388
+ getStatusLines: (options?: TelegramBridgeStatusLineOptions) => string[];
389
+ getStatusState: () => TelegramBridgeStatusLineState;
390
+ }
391
+
392
+ function truncateTelegramRuntimeEventText(
393
+ text: string,
394
+ maxLength: number,
395
+ ): string {
396
+ if (text.length <= maxLength) return text;
397
+ return `${text.slice(0, maxLength).trimEnd()}… [truncated ${text.length - maxLength} chars]`;
398
+ }
399
+
400
+ export function redactTelegramRuntimeMessage(
401
+ message: string,
402
+ botToken: string | undefined,
403
+ ): string {
404
+ const redacted = botToken
405
+ ? message.split(botToken).join("<redacted-token>")
406
+ : message;
407
+ return truncateTelegramRuntimeEventText(
408
+ redacted,
409
+ MAX_TELEGRAM_RUNTIME_EVENT_MESSAGE_LENGTH,
410
+ );
411
+ }
412
+
413
+ function redactTelegramRuntimeDetail(
414
+ message: string,
415
+ botToken: string | undefined,
416
+ ): string {
417
+ const redacted = botToken
418
+ ? message.split(botToken).join("<redacted-token>")
419
+ : message;
420
+ return truncateTelegramRuntimeEventText(
421
+ redacted,
422
+ MAX_TELEGRAM_RUNTIME_EVENT_DETAIL_LENGTH,
423
+ );
424
+ }
425
+
426
+ function normalizeTelegramRuntimeEventDetails(
427
+ details: Record<string, unknown> | undefined,
428
+ botToken: string | undefined,
429
+ ): Record<string, TelegramRuntimeEventDetailValue> | undefined {
430
+ if (!details) return undefined;
431
+ const normalized: Record<string, TelegramRuntimeEventDetailValue> = {};
432
+ for (const [key, value] of Object.entries(details)) {
433
+ if (value === undefined) continue;
434
+ if (typeof value === "string") {
435
+ normalized[key] = redactTelegramRuntimeDetail(value, botToken);
436
+ continue;
437
+ }
438
+ if (typeof value === "number" || typeof value === "boolean") {
439
+ normalized[key] = value;
440
+ continue;
441
+ }
442
+ if (value === null) {
443
+ normalized[key] = null;
444
+ continue;
445
+ }
446
+ normalized[key] = redactTelegramRuntimeDetail(String(value), botToken);
447
+ }
448
+ return Object.keys(normalized).length > 0 ? normalized : undefined;
449
+ }
450
+
451
+ function getTelegramRuntimeEventMessage(
452
+ input: TelegramRuntimeEventInput,
453
+ ): string {
454
+ if (input.message !== undefined) return input.message;
455
+ if (input.error instanceof Error) return input.error.message;
456
+ return String(input.error);
457
+ }
458
+
459
+ export function recordStructuredTelegramRuntimeEvent(
460
+ events: TelegramRuntimeEvent[],
461
+ input: TelegramRuntimeEventInput,
462
+ options: { botToken?: string; maxEvents: number; now?: number },
463
+ ): void {
464
+ const details = normalizeTelegramRuntimeEventDetails(
465
+ input.details,
466
+ options.botToken,
467
+ );
468
+ events.push({
469
+ at: options.now ?? Date.now(),
470
+ category: input.category,
471
+ message: redactTelegramRuntimeMessage(
472
+ getTelegramRuntimeEventMessage(input),
473
+ options.botToken,
474
+ ),
475
+ ...(details ? { details } : {}),
476
+ });
477
+ while (events.length > options.maxEvents) {
478
+ events.shift();
479
+ }
480
+ }
481
+
482
+ function getOrCreateTelegramStatusLineProviderRegistry(): Map<
483
+ string,
484
+ TelegramStatusLineProvider
485
+ > {
486
+ const existing = (globalThis as Record<string, unknown>)[
487
+ TELEGRAM_STATUS_LINE_PROVIDER_REGISTRY_KEY
488
+ ];
489
+ if (existing instanceof Map)
490
+ return existing as Map<string, TelegramStatusLineProvider>;
491
+ const registry = new Map<string, TelegramStatusLineProvider>();
492
+ (globalThis as Record<string, unknown>)[
493
+ TELEGRAM_STATUS_LINE_PROVIDER_REGISTRY_KEY
494
+ ] = registry;
495
+ return registry;
496
+ }
497
+
498
+ /**
499
+ * Register a compact extension-provided line for the Telegram status menu.
500
+ *
501
+ * Providers are synchronous and should return undefined when their line is not
502
+ * relevant for the active model. Errors are isolated so optional extension
503
+ * status cannot break the core Telegram menu.
504
+ */
505
+ export function registerTelegramStatusLineProvider(
506
+ provider: TelegramStatusLineProvider,
507
+ options: { id: string },
508
+ ): () => void {
509
+ const registry = getOrCreateTelegramStatusLineProviderRegistry();
510
+ registry.set(options.id, provider);
511
+ return () => {
512
+ if (registry.get(options.id) === provider) registry.delete(options.id);
513
+ };
514
+ }
515
+
516
+ export function getTelegramStatusLineProviderResults(
517
+ ctx: TelegramStatusLineProviderContext,
518
+ ): TelegramStatusLineProviderResult[] {
519
+ const results: TelegramStatusLineProviderResult[] = [];
520
+ const registry = getOrCreateTelegramStatusLineProviderRegistry();
521
+ for (const provider of registry.values()) {
522
+ try {
523
+ const result = provider(ctx);
524
+ if (!result?.label || !result.value) continue;
525
+ results.push(result);
526
+ } catch {
527
+ continue;
528
+ }
529
+ }
530
+ return results;
531
+ }
532
+
533
+ export function clearTelegramStatusLineProviders(): void {
534
+ getOrCreateTelegramStatusLineProviderRegistry().clear();
535
+ }
536
+
537
+ export function createTelegramRuntimeEventRecorder(
538
+ options: TelegramRuntimeEventRecorderOptions,
539
+ ): TelegramRuntimeEventRecorder {
540
+ const events: TelegramRuntimeEvent[] = [];
541
+ return {
542
+ record: (category, error, details) => {
543
+ recordStructuredTelegramRuntimeEvent(
544
+ events,
545
+ { category, error, details },
546
+ {
547
+ botToken: options.getBotToken(),
548
+ maxEvents: options.maxEvents ?? MAX_RECENT_TELEGRAM_RUNTIME_EVENTS,
549
+ now: options.now?.(),
550
+ },
551
+ );
552
+ },
553
+ getEvents: () => events,
554
+ clear: () => {
555
+ events.length = 0;
556
+ },
557
+ };
558
+ }
559
+
560
+ function formatTelegramRuntimeEventCategory(
561
+ event: TelegramRuntimeEvent,
562
+ ): string {
563
+ const method = event.details?.method;
564
+ return typeof method === "string"
565
+ ? `${event.category}:${method}`
566
+ : event.category;
567
+ }
568
+
569
+ function formatTelegramRuntimeEventDetails(
570
+ event: TelegramRuntimeEvent,
571
+ ): string {
572
+ if (!event.details) return "";
573
+ const details = Object.entries(event.details)
574
+ .filter(([key]) => key !== "method")
575
+ .map(([key, value]) => `${key}=${JSON.stringify(value)}`);
576
+ return details.length > 0 ? ` (${details.join(", ")})` : "";
577
+ }
578
+
579
+ function formatTelegramRuntimeEventSummary(
580
+ event: TelegramRuntimeEvent,
581
+ ): string {
582
+ return `${formatTelegramRuntimeEventCategory(event)}: ${event.message}${formatTelegramRuntimeEventDetails(event)}`;
583
+ }
584
+
585
+ function formatTelegramRuntimeEvent(event: TelegramRuntimeEvent): string {
586
+ return `${new Date(event.at).toISOString()} ${formatTelegramRuntimeEventSummary(event)}`;
587
+ }
588
+
589
+ function buildTelegramRuntimeEventSummary(
590
+ events: TelegramRuntimeEvent[],
591
+ ): string {
592
+ const counts = new Map<string, number>();
593
+ for (const event of events) {
594
+ const category = formatTelegramRuntimeEventCategory(event);
595
+ counts.set(category, (counts.get(category) ?? 0) + 1);
596
+ }
597
+ return Array.from(counts.entries())
598
+ .sort(([left], [right]) => left.localeCompare(right))
599
+ .map(([category, count]) => `${category}=${count}`)
600
+ .join(", ");
601
+ }
602
+
603
+ export function buildTelegramRuntimeEventLines(
604
+ events: TelegramRuntimeEvent[],
605
+ ): string[] {
606
+ if (events.length === 0) return ["recent runtime events: none"];
607
+ return [
608
+ "recent runtime events:",
609
+ `- summary: ${buildTelegramRuntimeEventSummary(events)}`,
610
+ ...events
611
+ .slice()
612
+ .reverse()
613
+ .map((event) => `- ${formatTelegramRuntimeEvent(event)}`),
614
+ ];
615
+ }
616
+
617
+ export function createTelegramStatusHtmlBuilder<TContext>(deps: {
618
+ getActiveModel: (ctx: TContext) => TelegramStatusActiveModel | undefined;
619
+ isCompactionInProgress?: () => boolean;
620
+ getBridgeStatusLineState?: () => TelegramBridgeStatusLineState;
621
+ }): (ctx: TContext & TelegramStatusContext) => string {
622
+ return (ctx) =>
623
+ buildStatusHtml(
624
+ { ...ctx, isCompactionInProgress: deps.isCompactionInProgress },
625
+ deps.getActiveModel(ctx),
626
+ deps.getBridgeStatusLineState?.(),
627
+ );
628
+ }
629
+
630
+ export function createTelegramStatusRuntime<
631
+ TContext extends TelegramStatusRuntimeContext,
632
+ >(deps: TelegramStatusRuntimeDeps<TContext>): TelegramStatusRuntime<TContext> {
633
+ const statusKey = deps.statusKey ?? "telegram";
634
+ return {
635
+ updateStatus: (ctx, error) => {
636
+ ctx.ui.setStatus(
637
+ statusKey,
638
+ buildTelegramStatusBarText(
639
+ ctx.ui.theme,
640
+ deps.getStatusBarState(ctx, error),
641
+ ),
642
+ );
643
+ },
644
+ getStatusLines: (options) =>
645
+ buildTelegramBridgeStatusLines(deps.getBridgeStatusLineState(), options),
646
+ getStatusState: deps.getBridgeStatusLineState,
647
+ };
648
+ }
649
+
650
+ export function createTelegramBridgeStatusRuntime<
651
+ TContext extends TelegramStatusRuntimeContext,
652
+ TQueueItem extends { queueLane: TelegramStatusQueueLane },
653
+ >(
654
+ deps: TelegramBridgeStatusRuntimeDeps<TQueueItem>,
655
+ ): TelegramStatusRuntime<TContext> {
656
+ return createTelegramStatusRuntime({
657
+ statusKey: deps.statusKey,
658
+ getStatusBarState: (_ctx, error) => {
659
+ const config = deps.getConfig();
660
+ const queuedItems = deps.getQueuedItems();
661
+ const hasActiveTurn = deps.hasActiveTurn();
662
+ const hasPendingDispatch = deps.hasDispatchPending();
663
+ const hasPendingModelSwitch = deps.hasPendingModelSwitch();
664
+ const activeToolExecutions = deps.getActiveToolExecutions();
665
+ const compactionInProgress = deps.isCompactionInProgress();
666
+ return {
667
+ hasBotToken: !!config.botToken,
668
+ pollingActive: deps.isPollingActive(),
669
+ paired: !!config.allowedUserId,
670
+ busRole: deps.getBusRole?.(),
671
+ busLifecyclePhase: deps.getBusLifecyclePhase?.(),
672
+ instanceSlot: deps.getInstanceSlot?.(),
673
+ instanceThreadName: deps.getInstanceThreadName?.(),
674
+ compactionInProgress,
675
+ processing:
676
+ hasActiveTurn ||
677
+ hasPendingDispatch ||
678
+ hasPendingModelSwitch ||
679
+ activeToolExecutions > 0 ||
680
+ queuedItems.length > 0,
681
+ processingStatus: getTelegramStatusBarProcessingStatus({
682
+ hasActiveTurn,
683
+ hasPendingDispatch,
684
+ hasPendingModelSwitch,
685
+ activeToolExecutions,
686
+ queuedItems: queuedItems.length,
687
+ }),
688
+ queuedStatus: deps.formatQueuedStatus(queuedItems),
689
+ error,
690
+ };
691
+ },
692
+ getBridgeStatusLineState: () => {
693
+ const config = deps.getConfig();
694
+ const botThreadMode = deps.getBotThreadMode?.();
695
+ const activeProfileName = deps.getActiveProfileName
696
+ ? (deps.getActiveProfileName() ?? TELEGRAM_STATUS_DEFAULT_PROFILE_NAME)
697
+ : undefined;
698
+ return {
699
+ hasBotToken: Boolean(config.botToken),
700
+ botUsername: config.botUsername,
701
+ activeProfileName,
702
+ diagnosticPaths: deps.getDiagnosticPaths?.(activeProfileName),
703
+ allowedUserId: config.allowedUserId,
704
+ botThreadMode: botThreadMode?.threadMode,
705
+ botThreadModeUpdatedAtMs: botThreadMode?.updatedAtMs,
706
+ botThreadModeAction: botThreadMode?.lastReconcileAction,
707
+ busRole: deps.getBusRole?.(),
708
+ busProtocol: deps.getBusProtocol?.(),
709
+ busLifecyclePhase: deps.getBusLifecyclePhase?.(),
710
+ instanceSlot: deps.getInstanceSlot?.(),
711
+ instanceThreadName: deps.getInstanceThreadName?.(),
712
+ lockState: deps.getRuntimeLockState?.(),
713
+ pollingActive: deps.isPollingActive(),
714
+ ...(deps.getPollingState
715
+ ? { polling: deps.getPollingState() }
716
+ : {}),
717
+ ...(deps.getInboundWorkerState
718
+ ? { inboundWorker: deps.getInboundWorkerState() }
719
+ : {}),
720
+ lastUpdateId: config.lastUpdateId,
721
+ activeSourceMessageIds: deps.getActiveSourceMessageIds(),
722
+ pendingDispatch: deps.hasDispatchPending(),
723
+ compactionInProgress: deps.isCompactionInProgress(),
724
+ activeToolExecutions: deps.getActiveToolExecutions(),
725
+ pendingModelSwitch: deps.hasPendingModelSwitch(),
726
+ queuedItems: deps.getQueuedItems(),
727
+ busFollowers: deps.getBusFollowers?.(),
728
+ localBus: deps.getLocalBus?.(),
729
+ topicTargets: deps.getTopicTargets?.(),
730
+ threadReservations: deps.getThreadReservations?.(),
731
+ topicSyncObservations: deps.getTopicSyncObservations?.(),
732
+ syncState: deps.getSyncState?.(),
733
+ threadReconciliation: deps.getThreadReconciliationState?.(),
734
+ busNowMs: deps.getNowMs?.(),
735
+ recentRuntimeEvents: deps.getRecentRuntimeEvents(),
736
+ };
737
+ },
738
+ });
739
+ }
740
+
741
+ export interface TelegramRuntimeLogScope extends Record<string, unknown> {
742
+ instanceId: string;
743
+ role: string;
744
+ slot?: string;
745
+ threadName?: string;
746
+ lockState?: string;
747
+ }
748
+
749
+ export function createTelegramRuntimeLogScope(input: {
750
+ state: TelegramBridgeStatusLineState;
751
+ instanceId: string;
752
+ }): TelegramRuntimeLogScope {
753
+ return {
754
+ instanceId: input.instanceId,
755
+ role: input.state.busRole ?? "classic-or-disconnected",
756
+ slot: input.state.instanceSlot,
757
+ threadName: input.state.instanceThreadName,
758
+ lockState: input.state.lockState,
759
+ };
760
+ }
761
+
762
+ export function createTelegramStatusSnapshot(
763
+ state: TelegramBridgeStatusLineState,
764
+ ): {
765
+ runtime: Record<string, unknown>;
766
+ liveRoster: Record<string, unknown>;
767
+ diagnostics: Record<string, unknown>;
768
+ } {
769
+ return {
770
+ runtime: {
771
+ busRole: state.busRole,
772
+ ...(state.busLifecyclePhase
773
+ ? { busLifecyclePhase: state.busLifecyclePhase }
774
+ : {}),
775
+ botThreadMode: state.botThreadMode,
776
+ botThreadModeUpdatedAtMs: state.botThreadModeUpdatedAtMs,
777
+ botThreadModeAction: state.botThreadModeAction,
778
+ instanceSlot: state.instanceSlot,
779
+ instanceThreadName: state.instanceThreadName,
780
+ pollingActive: state.pollingActive,
781
+ ...(state.polling ? { polling: state.polling } : {}),
782
+ lockState: state.lockState,
783
+ },
784
+ liveRoster: {
785
+ busFollowers: state.busFollowers ?? [],
786
+ ...(state.localBus ? { localBus: state.localBus } : {}),
787
+ topicTargets: state.topicTargets ?? [],
788
+ reservations: state.threadReservations ?? [],
789
+ syncObservations: state.topicSyncObservations ?? [],
790
+ },
791
+ diagnostics: {
792
+ pendingDispatch: state.pendingDispatch,
793
+ compactionInProgress: state.compactionInProgress,
794
+ activeToolExecutions: state.activeToolExecutions,
795
+ pendingModelSwitch: state.pendingModelSwitch,
796
+ syncState: state.syncState,
797
+ threadReconciliation: state.threadReconciliation,
798
+ recentRuntimeEvents: state.recentRuntimeEvents,
799
+ },
800
+ };
801
+ }
802
+
803
+ const TELEGRAM_DIAGNOSTICS_SNAPSHOT_COALESCE_MS = 100;
804
+
805
+ export function createTelegramRuntimeDiagnosticsSnapshotScheduler(deps: {
806
+ persistSnapshot: () => Promise<void>;
807
+ recordError: (error: unknown) => void;
808
+ setTimer?: (callback: () => void, ms: number) => { unref?: () => void };
809
+ }): () => void {
810
+ const setTimer = deps.setTimer ?? setTimeout;
811
+ let timer: { unref?: () => void } | number | undefined;
812
+ let persistPromise: Promise<void> | undefined;
813
+ let pending = false;
814
+ const recordError = (error: unknown): void => {
815
+ try {
816
+ deps.recordError(error);
817
+ } catch {
818
+ // Snapshot diagnostics cannot create an unhandled scheduler rejection.
819
+ }
820
+ };
821
+ const request = (): void => {
822
+ if (timer || persistPromise) {
823
+ pending = true;
824
+ return;
825
+ }
826
+ timer = setTimer(() => {
827
+ timer = undefined;
828
+ let tracked: Promise<void>;
829
+ tracked = Promise.resolve()
830
+ .then(deps.persistSnapshot)
831
+ .catch(recordError)
832
+ .finally(() => {
833
+ if (persistPromise !== tracked) return;
834
+ persistPromise = undefined;
835
+ if (pending) {
836
+ pending = false;
837
+ request();
838
+ }
839
+ });
840
+ persistPromise = tracked;
841
+ }, TELEGRAM_DIAGNOSTICS_SNAPSHOT_COALESCE_MS);
842
+ if (typeof timer !== "number") timer?.unref?.();
843
+ };
844
+ return request;
845
+ }
846
+
847
+ export function getTelegramStatusBarProcessingStatus(state: {
848
+ hasActiveTurn: boolean;
849
+ hasPendingDispatch: boolean;
850
+ hasPendingModelSwitch: boolean;
851
+ activeToolExecutions: number;
852
+ queuedItems: number;
853
+ }): string | undefined {
854
+ if (state.hasPendingModelSwitch) return "model";
855
+ if (state.hasActiveTurn || state.activeToolExecutions > 0) return "active";
856
+ if (state.hasPendingDispatch) return "dispatching";
857
+ if (state.queuedItems > 0) return "queued";
858
+ return undefined;
859
+ }
860
+
861
+ function getTelegramStatusBarLabel(state: TelegramStatusBarState): string {
862
+ const threadName = state.instanceThreadName?.trim();
863
+ if (!threadName) return "telegram";
864
+ const genericLabels = new Set(["telegram", "leader", "follower"]);
865
+ if (genericLabels.has(threadName.toLowerCase())) return "telegram";
866
+ return threadName;
867
+ }
868
+
869
+ export function buildTelegramStatusBarText(
870
+ theme: TelegramStatusBarTheme,
871
+ state: TelegramStatusBarState,
872
+ ): string {
873
+ const label = theme.fg("accent", getTelegramStatusBarLabel(state));
874
+ if (state.error) {
875
+ return `${label} ${theme.fg("error", "error")}`;
876
+ }
877
+ const queued = state.queuedStatus
878
+ ? theme.fg("success", state.queuedStatus)
879
+ : "";
880
+ if (!state.hasBotToken)
881
+ return `${label} ${theme.fg("muted", "not configured")}${queued}`;
882
+ if (!state.paired)
883
+ return `${label} ${theme.fg("warning", "awaiting pairing")}${queued}`;
884
+ if (state.busLifecyclePhase === "electing")
885
+ return `${label} ${theme.fg("warning", "electing")}${queued}`;
886
+ if (!state.pollingActive && state.busRole !== "follower")
887
+ return `${theme.fg("accent", "telegram")} ${theme.fg("dim", "disconnected")}${queued}`;
888
+ if (state.processing) {
889
+ const processingStatus = state.queuedStatus
890
+ ? "active"
891
+ : (state.processingStatus ?? "processing");
892
+ const processingToken =
893
+ processingStatus === "active" ? "warning" : "accent";
894
+ return `${label} ${theme.fg(processingToken, processingStatus)}${queued}`;
895
+ }
896
+ if (state.busRole === "follower")
897
+ return `${label} ${theme.fg("success", "follower")}${queued}`;
898
+ if (state.busRole === "leader")
899
+ return `${label} ${theme.fg("success", "leader")}`;
900
+ return `${label} ${theme.fg("success", "connected")}`;
901
+ }
902
+
903
+ function formatTelegramBridgeBotStatus(
904
+ state: Pick<TelegramBridgeStatusLineState, "hasBotToken" | "botUsername">,
905
+ ): string {
906
+ if (state.botUsername) return `@${state.botUsername}`;
907
+ return state.hasBotToken ? "unknown" : "not configured";
908
+ }
909
+
910
+ function formatTelegramStatusTarget(
911
+ target: { chatId: number; threadId?: number } | undefined,
912
+ ): string {
913
+ if (!target) return "";
914
+ return target.threadId === undefined
915
+ ? ` target ${target.chatId}`
916
+ : ` target ${target.chatId}:${target.threadId}`;
917
+ }
918
+
919
+ function formatTelegramThreadStatusLabel(input: {
920
+ threadName?: string;
921
+ slot?: string;
922
+ }): string {
923
+ const threadName = input.threadName?.trim();
924
+ if (threadName) return threadName;
925
+ return input.slot ? `[${input.slot}]` : "";
926
+ }
927
+
928
+ function formatTelegramBusProtocolIdentity(
929
+ protocol:
930
+ | {
931
+ protocolVersion: number;
932
+ runtimeBuild: string;
933
+ capabilities: string[];
934
+ }
935
+ | undefined,
936
+ ): string {
937
+ if (!protocol) return "";
938
+ const capabilities =
939
+ protocol.capabilities.length > 0
940
+ ? ` capabilities=${protocol.capabilities.join(",")}`
941
+ : " capabilities=none";
942
+ return ` protocol=v${protocol.protocolVersion} build=${protocol.runtimeBuild}${capabilities}`;
943
+ }
944
+
945
+ function buildTelegramBusFollowerLines(
946
+ state: Pick<TelegramBridgeStatusLineState, "busFollowers" | "busNowMs">,
947
+ ): string[] {
948
+ const followers = state.busFollowers ?? [];
949
+ if (followers.length === 0) return [];
950
+ const nowMs = state.busNowMs ?? Date.now();
951
+ return [
952
+ "",
953
+ "bus:",
954
+ `- followers: ${followers.length}`,
955
+ ...followers.map((follower) => {
956
+ const ageSeconds = Math.max(
957
+ 0,
958
+ Math.round((nowMs - follower.lastHeartbeatMs) / 1000),
959
+ );
960
+ const label = formatTelegramThreadStatusLabel(follower);
961
+ const labelSuffix = label ? ` ${label}` : "";
962
+ const statusLabel = follower.status ? ` (${follower.status})` : "";
963
+ const cwd = follower.cwd ? ` ${follower.cwd}` : "";
964
+ const target = formatTelegramStatusTarget(follower.target);
965
+ const protocol = formatTelegramBusProtocolIdentity(follower.protocol);
966
+ return `- ${follower.instanceId}:${labelSuffix} heartbeat ${ageSeconds}s ago${statusLabel}${target}${cwd}${protocol}`;
967
+ }),
968
+ ];
969
+ }
970
+
971
+ function buildTelegramLocalBusLines(
972
+ state: Pick<TelegramBridgeStatusLineState, "localBus">,
973
+ options: { verbose?: boolean } = {},
974
+ ): string[] {
975
+ const localBus = state.localBus;
976
+ if (!localBus) return [];
977
+ const target = formatTelegramStatusTarget(localBus.followerTarget);
978
+ const label = formatTelegramThreadStatusLabel({
979
+ slot: localBus.followerSlot,
980
+ threadName: localBus.followerThreadName,
981
+ });
982
+ const protocol = formatTelegramBusProtocolIdentity(
983
+ localBus.leaderProtocol,
984
+ );
985
+ const followerLine = `- follower registered: ${localBus.followerRegistered ? "yes" : "no"}${label ? ` ${label}` : ""}${target}${protocol}`;
986
+ const lines = ["", "local bus:", followerLine];
987
+ if (options.verbose) {
988
+ if (localBus.leaderSocketPath) {
989
+ const transport = localBus.leaderTransport
990
+ ? ` [${localBus.leaderTransport}]`
991
+ : "";
992
+ lines.push(`- leader endpoint${transport}: ${localBus.leaderSocketPath}`);
993
+ }
994
+ if (localBus.followerSocketPath) {
995
+ const transport = localBus.followerTransport
996
+ ? ` [${localBus.followerTransport}]`
997
+ : "";
998
+ lines.push(
999
+ `- follower endpoint${transport}: ${localBus.followerSocketPath}`,
1000
+ );
1001
+ }
1002
+ }
1003
+ return lines;
1004
+ }
1005
+
1006
+ function buildTelegramSyncSliceLines(
1007
+ state: Pick<TelegramBridgeStatusLineState, "syncState">,
1008
+ ): string[] {
1009
+ const syncState = state.syncState;
1010
+ if (!syncState || Object.keys(syncState).length === 0) return [];
1011
+ return [
1012
+ "sync:",
1013
+ ...Object.entries(syncState).map(([slice, value]) => {
1014
+ const status = value?.status ?? "unknown";
1015
+ const action = value?.lastReconcileAction
1016
+ ? ` reconcile=${value.lastReconcileAction}`
1017
+ : "";
1018
+ const reason = value?.reason ? ` reason=${value.reason}` : "";
1019
+ return `- ${slice}: ${status}${action}${reason}`;
1020
+ }),
1021
+ ];
1022
+ }
1023
+
1024
+ function buildTelegramThreadReconciliationLines(
1025
+ state: Pick<TelegramBridgeStatusLineState, "threadReconciliation">,
1026
+ ): string[] {
1027
+ const reconciliation = state.threadReconciliation;
1028
+ if (!reconciliation) return [];
1029
+ const epoch =
1030
+ reconciliation.leaderEpoch !== undefined
1031
+ ? ` epoch=${reconciliation.leaderEpoch}`
1032
+ : "";
1033
+ return [
1034
+ "reconciliation:",
1035
+ `- phase: ${reconciliation.phase} event=${reconciliation.event}${epoch}`,
1036
+ `- counts: pending=${reconciliation.pendingProvisionCount}, sync=${reconciliation.syncActionCount}, cleanup=${reconciliation.cleanupActionCount}`,
1037
+ ];
1038
+ }
1039
+
1040
+ function buildTelegramTopicTargetDiagnosticLines(
1041
+ state: Pick<
1042
+ TelegramBridgeStatusLineState,
1043
+ "topicTargets" | "threadReservations" | "topicSyncObservations"
1044
+ >,
1045
+ ): string[] {
1046
+ const activeTargets = (state.topicTargets ?? []).filter(
1047
+ (record) =>
1048
+ !!record.instanceId &&
1049
+ (record.status === "active" || record.status === "starting"),
1050
+ );
1051
+ const reservations = state.threadReservations ?? [];
1052
+ const observations = state.topicSyncObservations ?? [];
1053
+ if (
1054
+ activeTargets.length === 0 &&
1055
+ reservations.length === 0 &&
1056
+ observations.length === 0
1057
+ )
1058
+ return [];
1059
+ const byInstance = new Map<string, TelegramBridgeStatusTopicTarget[]>();
1060
+ for (const record of activeTargets) {
1061
+ const key = record.instanceId;
1062
+ if (!key) continue;
1063
+ const records = byInstance.get(key) ?? [];
1064
+ records.push(record);
1065
+ byInstance.set(key, records);
1066
+ }
1067
+ const duplicateLines = Array.from(byInstance.entries())
1068
+ .filter(([, records]) => records.length > 1)
1069
+ .map(([instanceId, records]) => {
1070
+ const targets = records
1071
+ .map((record) => {
1072
+ const label = formatTelegramThreadStatusLabel(record);
1073
+ return `${label}${formatTelegramStatusTarget(record.target) || " unknown"}`.trim();
1074
+ })
1075
+ .join(", ");
1076
+ return `- duplicate ${instanceId}: ${records.length} active threads ${targets}`;
1077
+ });
1078
+ const twinLines = activeTargets.map((record) => {
1079
+ const label = formatTelegramThreadStatusLabel(record);
1080
+ const target = formatTelegramStatusTarget(record.target) || " unknown";
1081
+ const sync = record.syncStatus ? ` sync=${record.syncStatus}` : "";
1082
+ const observed = record.lastSyncObservedAtMs
1083
+ ? ` observed=${new Date(record.lastSyncObservedAtMs).toISOString()}`
1084
+ : "";
1085
+ const probe = record.lastSyncProbeAtMs
1086
+ ? ` probed=${new Date(record.lastSyncProbeAtMs).toISOString()}`
1087
+ : "";
1088
+ const error = record.lastSyncError
1089
+ ? ` syncError=${record.lastSyncError}`
1090
+ : "";
1091
+ const action = record.lastReconcileAction
1092
+ ? ` reconcile=${record.lastReconcileAction}`
1093
+ : "";
1094
+ return `- ${label}${target}${sync}${observed}${probe}${error}${action}`.trim();
1095
+ });
1096
+ const reservationLines = reservations.map((reservation) => {
1097
+ const slot = reservation.slot ? `[${reservation.slot}]` : "";
1098
+ const target = formatTelegramStatusTarget(reservation.target) || " unknown";
1099
+ const reason = reservation.reason ? ` reason=${reservation.reason}` : "";
1100
+ const instance = reservation.instanceId
1101
+ ? ` instance=${reservation.instanceId}`
1102
+ : "";
1103
+ const action = reservation.lastReconcileAction
1104
+ ? ` reconcile=${reservation.lastReconcileAction}`
1105
+ : "";
1106
+ return `- reservation ${slot}${target}${reason}${instance}${action}`.trim();
1107
+ });
1108
+ const observationLines = observations.map((observation) => {
1109
+ const slot = observation.slot ? `[${observation.slot}]` : "";
1110
+ const target = formatTelegramStatusTarget(observation.target) || " unknown";
1111
+ const observed = ` observed=${new Date(observation.observedAtMs).toISOString()}`;
1112
+ const instance = observation.instanceId
1113
+ ? ` instance=${observation.instanceId}`
1114
+ : "";
1115
+ const error = observation.lastSyncError
1116
+ ? ` syncError=${observation.lastSyncError}`
1117
+ : "";
1118
+ const action = observation.lastReconcileAction
1119
+ ? ` reconcile=${observation.lastReconcileAction}`
1120
+ : "";
1121
+ return `- sync ${slot}${target} sync=${observation.syncStatus}${observed}${instance}${error}${action}`.trim();
1122
+ });
1123
+ return [
1124
+ "topics:",
1125
+ `- active bindings: instances=${byInstance.size}, targets=${activeTargets.length}`,
1126
+ ...duplicateLines,
1127
+ ...twinLines,
1128
+ ...reservationLines,
1129
+ ...observationLines,
1130
+ ];
1131
+ }
1132
+
1133
+ function buildTelegramBridgeCompactThreadLines(
1134
+ state: Pick<
1135
+ TelegramBridgeStatusLineState,
1136
+ | "busFollowers"
1137
+ | "topicTargets"
1138
+ | "threadReservations"
1139
+ | "topicSyncObservations"
1140
+ >,
1141
+ ): string[] {
1142
+ const activeTargets = (state.topicTargets ?? []).filter(
1143
+ (record) =>
1144
+ !!record.instanceId &&
1145
+ (record.status === "active" || record.status === "starting"),
1146
+ );
1147
+ const activeLabels = activeTargets
1148
+ .map(formatTelegramThreadStatusLabel)
1149
+ .filter((label) => label.length > 0);
1150
+ const followers = state.busFollowers ?? [];
1151
+ const reservations = state.threadReservations ?? [];
1152
+ const observations = state.topicSyncObservations ?? [];
1153
+ if (
1154
+ activeLabels.length === 0 &&
1155
+ followers.length === 0 &&
1156
+ reservations.length === 0 &&
1157
+ observations.length === 0
1158
+ ) {
1159
+ return [];
1160
+ }
1161
+ const lines = ["threads:"];
1162
+ if (activeLabels.length > 0)
1163
+ lines.push(`- active: ${activeLabels.join(", ")}`);
1164
+ if (followers.length > 0) lines.push(`- followers: ${followers.length}`);
1165
+ if (reservations.length > 0) lines.push(`- reserved: ${reservations.length}`);
1166
+ const syncIssueCount = observations.filter(
1167
+ (observation) => observation.syncStatus !== "open",
1168
+ ).length;
1169
+ if (syncIssueCount > 0) lines.push(`- sync issues: ${syncIssueCount}`);
1170
+ return lines;
1171
+ }
1172
+
1173
+ function formatTelegramPollingLifecycle(
1174
+ state: Pick<TelegramBridgeStatusLineState, "pollingActive" | "polling">,
1175
+ ): string {
1176
+ const lifecycle = state.pollingActive ? "running" : "stopped";
1177
+ if (!state.polling) return lifecycle;
1178
+ if (state.pollingActive) return `${lifecycle} (${state.polling.phase})`;
1179
+ return state.polling.stopReason
1180
+ ? `${lifecycle} (${state.polling.stopReason})`
1181
+ : lifecycle;
1182
+ }
1183
+
1184
+ function buildTelegramPollingDiagnosticLines(
1185
+ polling: TelegramBridgePollingState | undefined,
1186
+ ): string[] {
1187
+ if (!polling) return [];
1188
+ return [
1189
+ `- phase: ${polling.phase}`,
1190
+ ...(polling.phaseStartedAtMs !== undefined
1191
+ ? [
1192
+ `- phase started: ${new Date(polling.phaseStartedAtMs).toISOString()}`,
1193
+ ]
1194
+ : []),
1195
+ ...(polling.currentUpdateId !== undefined
1196
+ ? [`- current update id: ${polling.currentUpdateId}`]
1197
+ : []),
1198
+ ...(polling.lastSuccessfulResponseAtMs !== undefined
1199
+ ? [
1200
+ `- last successful response: ${new Date(polling.lastSuccessfulResponseAtMs).toISOString()} (updates=${polling.lastSuccessfulResponseUpdateCount ?? "unknown"})`,
1201
+ ]
1202
+ : []),
1203
+ ...(polling.startedAtMs !== undefined
1204
+ ? [`- started: ${new Date(polling.startedAtMs).toISOString()}`]
1205
+ : []),
1206
+ ...(polling.stoppedAtMs !== undefined
1207
+ ? [`- stopped: ${new Date(polling.stoppedAtMs).toISOString()}`]
1208
+ : []),
1209
+ ...(polling.stopReason ? [`- stop reason: ${polling.stopReason}`] : []),
1210
+ ];
1211
+ }
1212
+
1213
+ function formatTelegramInboundWorkerState(
1214
+ worker: TelegramBridgeInboundWorkerState | undefined,
1215
+ ): string {
1216
+ if (!worker) return "not started";
1217
+ const depth = worker.journalEntryCount;
1218
+ return `${worker.phase} (depth=${depth}, queued=${worker.queuedClaimCount}, foreign=${worker.foreignQueuedCount}, deferred=${worker.deferredClaimCount}, retry=${worker.retryWaitCount}, failed=${worker.failedCount})`;
1219
+ }
1220
+
1221
+ function buildTelegramInboundWorkerDiagnosticLines(
1222
+ worker: TelegramBridgeInboundWorkerState | undefined,
1223
+ ): string[] {
1224
+ if (!worker) return ["- state: not started"];
1225
+ return [
1226
+ `- state: ${worker.phase}`,
1227
+ `- generation: ${worker.generation}`,
1228
+ ...(worker.phaseStartedAtMs !== undefined
1229
+ ? [`- phase started: ${new Date(worker.phaseStartedAtMs).toISOString()}`]
1230
+ : []),
1231
+ `- journal: entries=${worker.journalEntryCount}, bytes=${worker.journalSerializedBytes}`,
1232
+ `- claims: queued=${worker.queuedClaimCount}, foreign-queued=${worker.foreignQueuedCount}, deferred=${worker.deferredClaimCount}, unsettled=${worker.unsettledExecutionCount}`,
1233
+ ...(worker.foreignQueuedOwner
1234
+ ? [
1235
+ `- 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"}`,
1236
+ ]
1237
+ : []),
1238
+ `- failures: retry-wait=${worker.retryWaitCount}, terminal=${worker.failedCount}`,
1239
+ ...(worker.currentUpdateId !== undefined
1240
+ ? [`- current update id: ${worker.currentUpdateId}`]
1241
+ : []),
1242
+ ...(worker.nextRetryUpdateId !== undefined
1243
+ ? [
1244
+ `- next retry: update=${worker.nextRetryUpdateId}, attempt=${worker.nextRetryAttemptCount ?? "unknown"}, class=${worker.nextRetryFailureClass ?? "unknown"}${worker.nextRetryAtMs !== undefined ? ` at ${new Date(worker.nextRetryAtMs).toISOString()}` : ""}`,
1245
+ ]
1246
+ : []),
1247
+ ...(worker.failedUpdateId !== undefined
1248
+ ? [
1249
+ `- 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()}` : ""}`,
1250
+ ...(worker.failedSummary
1251
+ ? [`- terminal summary: ${worker.failedSummary}`]
1252
+ : []),
1253
+ ]
1254
+ : []),
1255
+ ...(worker.oldestAdmittedAtMs !== undefined
1256
+ ? [
1257
+ `- oldest admitted: ${new Date(worker.oldestAdmittedAtMs).toISOString()}`,
1258
+ ]
1259
+ : []),
1260
+ ...(worker.blockedReason
1261
+ ? [`- blocked reason: ${worker.blockedReason}`]
1262
+ : []),
1263
+ ...(worker.lastCompletedUpdateId !== undefined
1264
+ ? [
1265
+ `- last completed: ${worker.lastCompletedUpdateId}${worker.lastCompletedAtMs !== undefined ? ` at ${new Date(worker.lastCompletedAtMs).toISOString()}` : ""}`,
1266
+ ]
1267
+ : []),
1268
+ ...(worker.lastFailurePhase
1269
+ ? [
1270
+ `- last failure: ${worker.lastFailurePhase}${worker.lastFailureAtMs !== undefined ? ` at ${new Date(worker.lastFailureAtMs).toISOString()}` : ""}`,
1271
+ ]
1272
+ : []),
1273
+ ];
1274
+ }
1275
+
1276
+ function buildTelegramBridgeCompactStatusLines(
1277
+ state: TelegramBridgeStatusLineState,
1278
+ ): string[] {
1279
+ const controlQueueCount = state.queuedItems.filter(
1280
+ (item) => item.queueLane === "control",
1281
+ ).length;
1282
+ const priorityQueueCount = state.queuedItems.filter(
1283
+ (item) => item.queueLane === "priority",
1284
+ ).length;
1285
+ const defaultQueueCount = state.queuedItems.filter(
1286
+ (item) => item.queueLane === "default",
1287
+ ).length;
1288
+ const queueLine = `- queued turns: ${state.queuedItems.length}${
1289
+ state.queuedItems.length > 0
1290
+ ? ` (control=${controlQueueCount}, priority=${priorityQueueCount}, default=${defaultQueueCount})`
1291
+ : ""
1292
+ }`;
1293
+ const executionState = state.pendingDispatch
1294
+ ? "pending dispatch"
1295
+ : state.activeSourceMessageIds?.length
1296
+ ? "active"
1297
+ : "idle";
1298
+ const diagnosticsProfileName =
1299
+ state.activeProfileName === TELEGRAM_STATUS_DEFAULT_PROFILE_NAME
1300
+ ? undefined
1301
+ : state.activeProfileName;
1302
+ const profileSuffix = diagnosticsProfileName
1303
+ ? `.${diagnosticsProfileName.replace(/[^a-zA-Z0-9._-]+/g, "_")}`
1304
+ : "";
1305
+ const diagnosticsPaths = state.diagnosticPaths ?? {
1306
+ state: `~/.pi/agent/tmp/telegram/state${profileSuffix}.json`,
1307
+ logs: `~/.pi/agent/tmp/telegram/logs${profileSuffix}.jsonl`,
1308
+ };
1309
+ return [
1310
+ "connection:",
1311
+ `- bot: ${formatTelegramBridgeBotStatus(state)}`,
1312
+ ...(state.activeProfileName
1313
+ ? [`- profile: ${state.activeProfileName}`]
1314
+ : []),
1315
+ `- user: ${state.allowedUserId ?? "not paired"}`,
1316
+ ...(state.botThreadMode ? [`- thread mode: ${state.botThreadMode}`] : []),
1317
+ ...(state.busRole ? [`- role: ${state.busRole}`] : []),
1318
+ ...(state.busLifecyclePhase
1319
+ ? [`- lifecycle: ${state.busLifecyclePhase}`]
1320
+ : []),
1321
+ ...(state.instanceThreadName || state.instanceSlot
1322
+ ? [`- instance: ${state.instanceThreadName ?? state.instanceSlot}`]
1323
+ : []),
1324
+ ...(state.lockState ? [`- owner: ${state.lockState}`] : []),
1325
+ "",
1326
+ "health:",
1327
+ `- polling: ${formatTelegramPollingLifecycle(state)}`,
1328
+ ...(state.inboundWorker
1329
+ ? [
1330
+ `- inbound worker: ${formatTelegramInboundWorkerState(state.inboundWorker)}`,
1331
+ ]
1332
+ : []),
1333
+ `- state: ${executionState}`,
1334
+ queueLine,
1335
+ ...(state.activeToolExecutions > 0
1336
+ ? [`- active tools: ${state.activeToolExecutions}`]
1337
+ : []),
1338
+ ...(state.pendingModelSwitch ? ["- pending model switch: yes"] : []),
1339
+ ...buildTelegramBridgeCompactThreadLines(state),
1340
+ ...buildTelegramBusFollowerLines(state),
1341
+ ...buildTelegramLocalBusLines(state),
1342
+ ...buildTelegramThreadReconciliationLines(state),
1343
+ "",
1344
+ "diagnostics:",
1345
+ `- state: ${diagnosticsPaths.state}`,
1346
+ `- logs: ${diagnosticsPaths.logs}`,
1347
+ "- full dump: /telegram-status --debug",
1348
+ ];
1349
+ }
1350
+
1351
+ export function buildTelegramBridgeStatusLines(
1352
+ state: TelegramBridgeStatusLineState,
1353
+ options: TelegramBridgeStatusLineOptions = {},
1354
+ ): string[] {
1355
+ if (options.verbose) return buildTelegramBridgeDiagnosticStatusLines(state);
1356
+ return buildTelegramBridgeCompactStatusLines(state);
1357
+ }
1358
+
1359
+ export function buildTelegramBridgeDiagnosticStatusLines(
1360
+ state: TelegramBridgeStatusLineState,
1361
+ ): string[] {
1362
+ const controlQueueCount = state.queuedItems.filter(
1363
+ (item) => item.queueLane === "control",
1364
+ ).length;
1365
+ const priorityQueueCount = state.queuedItems.filter(
1366
+ (item) => item.queueLane === "priority",
1367
+ ).length;
1368
+ const defaultQueueCount = state.queuedItems.filter(
1369
+ (item) => item.queueLane === "default",
1370
+ ).length;
1371
+ return [
1372
+ "connection:",
1373
+ `- bot: ${formatTelegramBridgeBotStatus(state)}`,
1374
+ ...(state.activeProfileName
1375
+ ? [`- profile: ${state.activeProfileName}`]
1376
+ : []),
1377
+ `- allowed user: ${state.allowedUserId ?? "not paired"}`,
1378
+ ...(state.botThreadMode
1379
+ ? [
1380
+ `- thread mode: ${state.botThreadMode}${state.botThreadModeAction ? ` reconcile=${state.botThreadModeAction}` : ""}`,
1381
+ ]
1382
+ : []),
1383
+ ...(state.busRole ? [`- bus role: ${state.busRole}`] : []),
1384
+ ...(state.busProtocol
1385
+ ? [`- bus${formatTelegramBusProtocolIdentity(state.busProtocol)}`]
1386
+ : []),
1387
+ ...(state.busLifecyclePhase
1388
+ ? [`- bus lifecycle: ${state.busLifecyclePhase}`]
1389
+ : []),
1390
+ ...(state.instanceThreadName || state.instanceSlot
1391
+ ? [`- instance: ${state.instanceThreadName ?? state.instanceSlot}`]
1392
+ : []),
1393
+ ...(state.lockState ? [`- owner: ${state.lockState}`] : []),
1394
+ "",
1395
+ "polling:",
1396
+ `- state: ${formatTelegramPollingLifecycle(state)}`,
1397
+ ...buildTelegramPollingDiagnosticLines(state.polling),
1398
+ `- last update id: ${state.lastUpdateId ?? "none"}`,
1399
+ "",
1400
+ ...(state.inboundWorker
1401
+ ? [
1402
+ "inbound worker:",
1403
+ ...buildTelegramInboundWorkerDiagnosticLines(state.inboundWorker),
1404
+ "",
1405
+ ]
1406
+ : []),
1407
+ "execution:",
1408
+ `- active turn: ${state.activeSourceMessageIds?.join(",") || "no"}`,
1409
+ `- pending dispatch: ${state.pendingDispatch ? "yes" : "no"}`,
1410
+ `- compaction: ${state.compactionInProgress ? "running" : "idle"}`,
1411
+ `- active tools: ${state.activeToolExecutions}`,
1412
+ `- pending model switch: ${state.pendingModelSwitch ? "yes" : "no"}`,
1413
+ "",
1414
+ "queue:",
1415
+ `- queued turns: ${state.queuedItems.length}`,
1416
+ `- lanes: control=${controlQueueCount}, priority=${priorityQueueCount}, default=${defaultQueueCount}`,
1417
+ ...buildTelegramBusFollowerLines(state),
1418
+ ...buildTelegramLocalBusLines(state, { verbose: true }),
1419
+ ...buildTelegramTopicTargetDiagnosticLines(state),
1420
+ ...buildTelegramThreadReconciliationLines(state),
1421
+ ...buildTelegramSyncSliceLines(state),
1422
+ "",
1423
+ ...buildTelegramRuntimeEventLines(state.recentRuntimeEvents),
1424
+ ];
1425
+ }
1426
+
1427
+ function escapeHtml(text: string): string {
1428
+ return text
1429
+ .replace(/&/g, "&amp;")
1430
+ .replace(/</g, "&lt;")
1431
+ .replace(/>/g, "&gt;");
1432
+ }
1433
+
1434
+ function formatTokens(count: number): string {
1435
+ if (count < 1000) return count.toString();
1436
+ if (count < 10000) return `${(count / 1000).toFixed(1)}k`;
1437
+ if (count < 1000000) return `${Math.round(count / 1000)}k`;
1438
+ if (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;
1439
+ return `${Math.round(count / 1000000)}M`;
1440
+ }
1441
+
1442
+ function collectUsageStats(ctx: TelegramStatusContext): TelegramUsageStats {
1443
+ const stats: TelegramUsageStats = {
1444
+ totalInput: 0,
1445
+ totalOutput: 0,
1446
+ totalCacheRead: 0,
1447
+ totalCacheWrite: 0,
1448
+ totalCost: 0,
1449
+ };
1450
+ for (const entry of ctx.sessionManager.getEntries()) {
1451
+ const usage = entry.message?.usage;
1452
+ if (
1453
+ entry.type !== "message" ||
1454
+ entry.message?.role !== "assistant" ||
1455
+ !usage
1456
+ ) {
1457
+ continue;
1458
+ }
1459
+ stats.totalInput += usage.input;
1460
+ stats.totalOutput += usage.output;
1461
+ stats.totalCacheRead += usage.cacheRead;
1462
+ stats.totalCacheWrite += usage.cacheWrite;
1463
+ stats.totalCost += usage.cost.total;
1464
+ }
1465
+ return stats;
1466
+ }
1467
+
1468
+ function formatStatusRowLabel(label: string): string {
1469
+ if (!label) return label;
1470
+ return `${label[0]?.toUpperCase() ?? ""}${label.slice(1)}`;
1471
+ }
1472
+
1473
+ function buildStatusRow(label: string, value: string): string {
1474
+ return `<b>${escapeHtml(formatStatusRowLabel(label))}:</b> <code>${escapeHtml(value)}</code>`;
1475
+ }
1476
+
1477
+ function buildUsageSummary(stats: TelegramUsageStats): string | undefined {
1478
+ const tokenParts: string[] = [];
1479
+ if (stats.totalInput) tokenParts.push(`↑${formatTokens(stats.totalInput)}`);
1480
+ if (stats.totalOutput) tokenParts.push(`↓${formatTokens(stats.totalOutput)}`);
1481
+ if (stats.totalCacheRead)
1482
+ tokenParts.push(`R${formatTokens(stats.totalCacheRead)}`);
1483
+ if (stats.totalCacheWrite)
1484
+ tokenParts.push(`W${formatTokens(stats.totalCacheWrite)}`);
1485
+ return tokenParts.length > 0 ? tokenParts.join(" ") : undefined;
1486
+ }
1487
+
1488
+ function buildCostSummary(
1489
+ stats: TelegramUsageStats,
1490
+ usesSubscription: boolean,
1491
+ ): string | undefined {
1492
+ if (!stats.totalCost && !usesSubscription) return undefined;
1493
+ return `$${stats.totalCost.toFixed(3)}${usesSubscription ? " (sub)" : ""}`;
1494
+ }
1495
+
1496
+ function buildContextSummary(
1497
+ ctx: TelegramStatusContext,
1498
+ activeModel: TelegramStatusActiveModel | undefined,
1499
+ ): string {
1500
+ const usage = ctx.getContextUsage();
1501
+ if (!usage) return "unknown";
1502
+ const contextWindow = usage.contextWindow ?? activeModel?.contextWindow ?? 0;
1503
+ const percent = usage.percent !== null ? `${usage.percent.toFixed(1)}%` : "?";
1504
+ return `${percent}/${formatTokens(contextWindow)}`;
1505
+ }
1506
+
1507
+ function buildStatusSummary(ctx: TelegramStatusContext): string {
1508
+ if (ctx.isCompactionInProgress?.()) return "compacting";
1509
+ if (ctx.hasPendingMessages?.()) return "pending";
1510
+ if (ctx.isIdle?.() === false) return "active";
1511
+ if (ctx.isIdle?.() === true) return "idle";
1512
+ return "unknown";
1513
+ }
1514
+
1515
+ function buildTelegramStatusRoleSuffix(
1516
+ state: TelegramBridgeStatusLineState | undefined,
1517
+ ): string {
1518
+ if (state?.botThreadMode !== "enabled" || !state.busRole) return "";
1519
+ return ` @${state.busRole}`;
1520
+ }
1521
+
1522
+ export function buildStatusHtml(
1523
+ ctx: TelegramStatusContext,
1524
+ activeModel: TelegramStatusActiveModel | undefined,
1525
+ bridgeStatus?: TelegramBridgeStatusLineState,
1526
+ ): string {
1527
+ const stats = collectUsageStats(ctx);
1528
+ const usesSubscription = activeModel
1529
+ ? ctx.modelRegistry.isUsingOAuth(activeModel)
1530
+ : false;
1531
+ const lines: string[] = [
1532
+ buildStatusRow(
1533
+ "Status",
1534
+ `${buildStatusSummary(ctx)}${buildTelegramStatusRoleSuffix(bridgeStatus)}`,
1535
+ ),
1536
+ ];
1537
+ const usageSummary = buildUsageSummary(stats);
1538
+ const costSummary = buildCostSummary(stats, usesSubscription);
1539
+ if (usageSummary) {
1540
+ lines.push(buildStatusRow("Usage", usageSummary));
1541
+ }
1542
+ if (costSummary) {
1543
+ lines.push(buildStatusRow("Cost", costSummary));
1544
+ }
1545
+ lines.push(buildStatusRow("Context", buildContextSummary(ctx, activeModel)));
1546
+ for (const row of getTelegramStatusLineProviderResults({ activeModel })) {
1547
+ lines.push(buildStatusRow(row.label, row.value));
1548
+ }
1549
+ return lines.join("\n");
1550
+ }