switchroom 0.5.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 (718) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +447 -0
  3. package/bin/autoaccept.exp +81 -0
  4. package/bin/boot-self-test.sh +149 -0
  5. package/bin/bridge-watchdog.sh +967 -0
  6. package/bin/handoff-briefing.sh +206 -0
  7. package/bin/run-hook.sh +228 -0
  8. package/bin/switchroom.ts +4 -0
  9. package/bin/timezone-hook.sh +67 -0
  10. package/bin/user-profile-refresh-hook.sh +38 -0
  11. package/bin/workspace-dynamic-hook.sh +142 -0
  12. package/bin/workspace-stable-hook.sh +57 -0
  13. package/dist/cli/autoaccept-poll.js +118 -0
  14. package/dist/cli/switchroom.js +48557 -0
  15. package/package.json +95 -0
  16. package/profiles/_base/settings.json.hbs +15 -0
  17. package/profiles/_base/start.sh.hbs +383 -0
  18. package/profiles/_shared/telegram-style.md.hbs +140 -0
  19. package/profiles/coding/CLAUDE.md.hbs +57 -0
  20. package/profiles/coding/skills/architecture/SKILL.md +70 -0
  21. package/profiles/coding/skills/code-review/SKILL.md +58 -0
  22. package/profiles/coding/workspace/SOUL.md.hbs +25 -0
  23. package/profiles/default/CLAUDE.md +238 -0
  24. package/profiles/default/CLAUDE.md.hbs +113 -0
  25. package/profiles/default/workspace/CLAUDE.md.hbs +126 -0
  26. package/profiles/default/workspace/HEARTBEAT.md.hbs +40 -0
  27. package/profiles/default/workspace/IDENTITY.md.hbs +32 -0
  28. package/profiles/default/workspace/MEMORY.md.hbs +29 -0
  29. package/profiles/default/workspace/SOUL.md.hbs +61 -0
  30. package/profiles/default/workspace/TOOLS.md.hbs +29 -0
  31. package/profiles/default/workspace/USER.md.hbs +52 -0
  32. package/profiles/default/workspace/memory/.gitkeep +0 -0
  33. package/profiles/executive-assistant/CLAUDE.md.hbs +51 -0
  34. package/profiles/executive-assistant/skills/daily-briefing/SKILL.md +55 -0
  35. package/profiles/executive-assistant/skills/meeting-prep/SKILL.md +58 -0
  36. package/profiles/executive-assistant/workspace/SOUL.md.hbs +25 -0
  37. package/profiles/health-coach/CLAUDE.md.hbs +45 -0
  38. package/profiles/health-coach/skills/check-in/SKILL.md +41 -0
  39. package/profiles/health-coach/skills/weekly-review/SKILL.md +53 -0
  40. package/profiles/health-coach/workspace/SOUL.md.hbs +25 -0
  41. package/skills/buildkite-agent-infrastructure/SKILL.md +302 -0
  42. package/skills/buildkite-agent-infrastructure/agents/openai.yaml +6 -0
  43. package/skills/buildkite-agent-infrastructure/assets/buildkite-icon-large.png +0 -0
  44. package/skills/buildkite-agent-infrastructure/assets/buildkite-icon-small.png +0 -0
  45. package/skills/buildkite-agent-infrastructure/references/audit-logging.md +87 -0
  46. package/skills/buildkite-agent-infrastructure/references/graphql-mutations.md +690 -0
  47. package/skills/buildkite-agent-infrastructure/references/instance-shapes.md +38 -0
  48. package/skills/buildkite-agent-infrastructure/references/pipeline-templates.md +73 -0
  49. package/skills/buildkite-agent-infrastructure/references/self-hosted-agents.md +137 -0
  50. package/skills/buildkite-agent-infrastructure/references/sso-saml.md +92 -0
  51. package/skills/buildkite-agent-runtime/SKILL.md +476 -0
  52. package/skills/buildkite-agent-runtime/agents/openai.yaml +6 -0
  53. package/skills/buildkite-agent-runtime/assets/buildkite-icon-large.png +0 -0
  54. package/skills/buildkite-agent-runtime/assets/buildkite-icon-small.png +0 -0
  55. package/skills/buildkite-agent-runtime/references/flag-reference.md +417 -0
  56. package/skills/buildkite-agent-runtime/references/patterns-and-recipes.md +555 -0
  57. package/skills/buildkite-api/SKILL.md +285 -0
  58. package/skills/buildkite-api/agents/openai.yaml +6 -0
  59. package/skills/buildkite-api/assets/buildkite-icon-large.png +0 -0
  60. package/skills/buildkite-api/assets/buildkite-icon-small.png +0 -0
  61. package/skills/buildkite-api/references/graphql-reference.md +195 -0
  62. package/skills/buildkite-api/references/patterns.md +44 -0
  63. package/skills/buildkite-api/references/webhooks.md +161 -0
  64. package/skills/buildkite-cli/SKILL.md +379 -0
  65. package/skills/buildkite-cli/agents/openai.yaml +6 -0
  66. package/skills/buildkite-cli/assets/buildkite-icon-large.png +0 -0
  67. package/skills/buildkite-cli/assets/buildkite-icon-small.png +0 -0
  68. package/skills/buildkite-cli/references/command-reference.md +181 -0
  69. package/skills/buildkite-migration/SKILL.md +182 -0
  70. package/skills/buildkite-pipelines/SKILL.md +464 -0
  71. package/skills/buildkite-pipelines/agents/openai.yaml +6 -0
  72. package/skills/buildkite-pipelines/assets/buildkite-icon-large.png +0 -0
  73. package/skills/buildkite-pipelines/assets/buildkite-icon-small.png +0 -0
  74. package/skills/buildkite-pipelines/examples/basic-pipeline.yml +24 -0
  75. package/skills/buildkite-pipelines/examples/optimized-pipeline.yml +100 -0
  76. package/skills/buildkite-pipelines/references/advanced-patterns.md +286 -0
  77. package/skills/buildkite-pipelines/references/retry-and-error-codes.md +131 -0
  78. package/skills/buildkite-pipelines/references/step-types-reference.md +225 -0
  79. package/skills/buildkite-secure-delivery/SKILL.md +168 -0
  80. package/skills/buildkite-secure-delivery/agents/openai.yaml +6 -0
  81. package/skills/buildkite-secure-delivery/assets/buildkite-icon-large.png +0 -0
  82. package/skills/buildkite-secure-delivery/assets/buildkite-icon-small.png +0 -0
  83. package/skills/buildkite-secure-delivery/references/oidc-cloud-providers.md +83 -0
  84. package/skills/buildkite-secure-delivery/references/package-publishing.md +100 -0
  85. package/skills/buildkite-test-engine/SKILL.md +239 -0
  86. package/skills/buildkite-test-engine/agents/openai.yaml +6 -0
  87. package/skills/buildkite-test-engine/assets/buildkite-icon-large.png +0 -0
  88. package/skills/buildkite-test-engine/assets/buildkite-icon-small.png +0 -0
  89. package/skills/buildkite-test-engine/examples/bktec-splitting.yml +16 -0
  90. package/skills/buildkite-test-engine/examples/collector-pipeline.yml +11 -0
  91. package/skills/buildkite-test-engine/references/collectors.md +198 -0
  92. package/skills/buildkite-test-engine/references/splitting-examples.md +93 -0
  93. package/skills/docx/LICENSE.txt +30 -0
  94. package/skills/docx/SKILL.md +590 -0
  95. package/skills/docx/VENDORED.md +32 -0
  96. package/skills/docx/scripts/__init__.py +1 -0
  97. package/skills/docx/scripts/accept_changes.py +135 -0
  98. package/skills/docx/scripts/comment.py +318 -0
  99. package/skills/docx/scripts/office/helpers/__init__.py +0 -0
  100. package/skills/docx/scripts/office/helpers/merge_runs.py +199 -0
  101. package/skills/docx/scripts/office/helpers/simplify_redlines.py +197 -0
  102. package/skills/docx/scripts/office/pack.py +159 -0
  103. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  104. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  105. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  106. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  107. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  108. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  109. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  110. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  111. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  112. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  113. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  114. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  115. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  116. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  117. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  118. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  119. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  120. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  121. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  122. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  123. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  124. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  125. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  126. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  127. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  128. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  129. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  130. package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  131. package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  132. package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  133. package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  134. package/skills/docx/scripts/office/schemas/mce/mc.xsd +75 -0
  135. package/skills/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  136. package/skills/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  137. package/skills/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  138. package/skills/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  139. package/skills/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  140. package/skills/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  141. package/skills/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  142. package/skills/docx/scripts/office/soffice.py +183 -0
  143. package/skills/docx/scripts/office/unpack.py +132 -0
  144. package/skills/docx/scripts/office/validate.py +111 -0
  145. package/skills/docx/scripts/office/validators/__init__.py +15 -0
  146. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-313.pyc +0 -0
  147. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-313.pyc +0 -0
  148. package/skills/docx/scripts/office/validators/base.py +847 -0
  149. package/skills/docx/scripts/office/validators/docx.py +446 -0
  150. package/skills/docx/scripts/office/validators/pptx.py +275 -0
  151. package/skills/docx/scripts/office/validators/redlining.py +247 -0
  152. package/skills/docx/scripts/templates/comments.xml +3 -0
  153. package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  154. package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  155. package/skills/docx/scripts/templates/commentsIds.xml +3 -0
  156. package/skills/docx/scripts/templates/people.xml +3 -0
  157. package/skills/file-bug/SKILL.md +129 -0
  158. package/skills/humanizer/LICENSE +21 -0
  159. package/skills/humanizer/SKILL.md +559 -0
  160. package/skills/humanizer/VENDORED.md +38 -0
  161. package/skills/humanizer-calibrate/SKILL.md +144 -0
  162. package/skills/mcp-builder/LICENSE.txt +202 -0
  163. package/skills/mcp-builder/SKILL.md +236 -0
  164. package/skills/mcp-builder/VENDORED.md +32 -0
  165. package/skills/mcp-builder/reference/evaluation.md +602 -0
  166. package/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  167. package/skills/mcp-builder/reference/node_mcp_server.md +970 -0
  168. package/skills/mcp-builder/reference/python_mcp_server.md +719 -0
  169. package/skills/mcp-builder/scripts/connections.py +151 -0
  170. package/skills/mcp-builder/scripts/evaluation.py +373 -0
  171. package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  172. package/skills/mcp-builder/scripts/requirements.txt +2 -0
  173. package/skills/pdf/LICENSE.txt +30 -0
  174. package/skills/pdf/SKILL.md +314 -0
  175. package/skills/pdf/VENDORED.md +32 -0
  176. package/skills/pdf/forms.md +294 -0
  177. package/skills/pdf/reference.md +612 -0
  178. package/skills/pdf/scripts/check_bounding_boxes.py +65 -0
  179. package/skills/pdf/scripts/check_fillable_fields.py +11 -0
  180. package/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
  181. package/skills/pdf/scripts/create_validation_image.py +37 -0
  182. package/skills/pdf/scripts/extract_form_field_info.py +122 -0
  183. package/skills/pdf/scripts/extract_form_structure.py +115 -0
  184. package/skills/pdf/scripts/fill_fillable_fields.py +98 -0
  185. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  186. package/skills/pptx/LICENSE.txt +30 -0
  187. package/skills/pptx/SKILL.md +232 -0
  188. package/skills/pptx/VENDORED.md +32 -0
  189. package/skills/pptx/editing.md +205 -0
  190. package/skills/pptx/pptxgenjs.md +420 -0
  191. package/skills/pptx/scripts/__init__.py +0 -0
  192. package/skills/pptx/scripts/add_slide.py +195 -0
  193. package/skills/pptx/scripts/clean.py +286 -0
  194. package/skills/pptx/scripts/office/helpers/__init__.py +0 -0
  195. package/skills/pptx/scripts/office/helpers/merge_runs.py +199 -0
  196. package/skills/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
  197. package/skills/pptx/scripts/office/pack.py +159 -0
  198. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  199. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  200. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  201. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  202. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  203. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  204. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  205. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  206. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  207. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  208. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  209. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  210. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  211. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  212. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  213. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  214. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  215. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  216. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  217. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  218. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  219. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  220. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  221. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  222. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  223. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  224. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  225. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  226. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  227. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  228. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  229. package/skills/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
  230. package/skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  231. package/skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  232. package/skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  233. package/skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  234. package/skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  235. package/skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  236. package/skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  237. package/skills/pptx/scripts/office/soffice.py +183 -0
  238. package/skills/pptx/scripts/office/unpack.py +132 -0
  239. package/skills/pptx/scripts/office/validate.py +111 -0
  240. package/skills/pptx/scripts/office/validators/__init__.py +15 -0
  241. package/skills/pptx/scripts/office/validators/base.py +847 -0
  242. package/skills/pptx/scripts/office/validators/docx.py +446 -0
  243. package/skills/pptx/scripts/office/validators/pptx.py +275 -0
  244. package/skills/pptx/scripts/office/validators/redlining.py +247 -0
  245. package/skills/pptx/scripts/thumbnail.py +289 -0
  246. package/skills/skill-creator/LICENSE.txt +202 -0
  247. package/skills/skill-creator/SKILL.md +485 -0
  248. package/skills/skill-creator/VENDORED.md +32 -0
  249. package/skills/skill-creator/agents/analyzer.md +274 -0
  250. package/skills/skill-creator/agents/comparator.md +202 -0
  251. package/skills/skill-creator/agents/grader.md +223 -0
  252. package/skills/skill-creator/assets/eval_review.html +146 -0
  253. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  254. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  255. package/skills/skill-creator/references/schemas.md +430 -0
  256. package/skills/skill-creator/scripts/__init__.py +0 -0
  257. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  258. package/skills/skill-creator/scripts/generate_report.py +326 -0
  259. package/skills/skill-creator/scripts/improve_description.py +247 -0
  260. package/skills/skill-creator/scripts/package_skill.py +136 -0
  261. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  262. package/skills/skill-creator/scripts/run_eval.py +310 -0
  263. package/skills/skill-creator/scripts/run_loop.py +328 -0
  264. package/skills/skill-creator/scripts/utils.py +47 -0
  265. package/skills/switchroom-architecture/SKILL.md +60 -0
  266. package/skills/switchroom-architecture/cascade.md +112 -0
  267. package/skills/switchroom-architecture/sub-agents.md +87 -0
  268. package/skills/switchroom-architecture/telegram.md +94 -0
  269. package/skills/switchroom-cli/SKILL.md +274 -0
  270. package/skills/switchroom-health/SKILL.md +101 -0
  271. package/skills/switchroom-install/SKILL.md +116 -0
  272. package/skills/switchroom-manage/SKILL.md +90 -0
  273. package/skills/switchroom-status/SKILL.md +69 -0
  274. package/skills/switchroom-status/scripts/status.sh +69 -0
  275. package/skills/telegram-test-harness/SKILL.md +191 -0
  276. package/skills/token-helpers/SKILL.md +73 -0
  277. package/skills/token-helpers/scripts/google-cal-token.sh +62 -0
  278. package/skills/token-helpers/scripts/ms-graph-token.sh +70 -0
  279. package/skills/webapp-testing/LICENSE.txt +202 -0
  280. package/skills/webapp-testing/SKILL.md +96 -0
  281. package/skills/webapp-testing/VENDORED.md +32 -0
  282. package/skills/webapp-testing/examples/console_logging.py +35 -0
  283. package/skills/webapp-testing/examples/element_discovery.py +40 -0
  284. package/skills/webapp-testing/examples/static_html_automation.py +33 -0
  285. package/skills/webapp-testing/scripts/with_server.py +106 -0
  286. package/skills/xlsx/LICENSE.txt +30 -0
  287. package/skills/xlsx/SKILL.md +292 -0
  288. package/skills/xlsx/VENDORED.md +32 -0
  289. package/skills/xlsx/scripts/office/helpers/__init__.py +0 -0
  290. package/skills/xlsx/scripts/office/helpers/merge_runs.py +199 -0
  291. package/skills/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
  292. package/skills/xlsx/scripts/office/pack.py +159 -0
  293. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  294. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  295. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  296. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  297. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  298. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  299. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  300. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  301. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  302. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  303. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  304. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  305. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  306. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  307. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  308. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  309. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  310. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  311. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  312. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  313. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  314. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  315. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  316. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  317. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  318. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  319. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  320. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  321. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  322. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  323. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  324. package/skills/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
  325. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  326. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  327. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  328. package/skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  329. package/skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  330. package/skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  331. package/skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  332. package/skills/xlsx/scripts/office/soffice.py +183 -0
  333. package/skills/xlsx/scripts/office/unpack.py +132 -0
  334. package/skills/xlsx/scripts/office/validate.py +111 -0
  335. package/skills/xlsx/scripts/office/validators/__init__.py +15 -0
  336. package/skills/xlsx/scripts/office/validators/base.py +847 -0
  337. package/skills/xlsx/scripts/office/validators/docx.py +446 -0
  338. package/skills/xlsx/scripts/office/validators/pptx.py +275 -0
  339. package/skills/xlsx/scripts/office/validators/redlining.py +247 -0
  340. package/skills/xlsx/scripts/recalc.py +184 -0
  341. package/telegram-plugin/.claude-plugin/plugin.json +20 -0
  342. package/telegram-plugin/.mcp.json +14 -0
  343. package/telegram-plugin/LICENSE +21 -0
  344. package/telegram-plugin/README.md +352 -0
  345. package/telegram-plugin/active-pins-sweep.ts +204 -0
  346. package/telegram-plugin/active-pins.ts +146 -0
  347. package/telegram-plugin/active-reactions-sweep.ts +79 -0
  348. package/telegram-plugin/active-reactions.ts +134 -0
  349. package/telegram-plugin/admin-commands/dispatch.test.ts +149 -0
  350. package/telegram-plugin/admin-commands/index.ts +106 -0
  351. package/telegram-plugin/answer-stream.ts +565 -0
  352. package/telegram-plugin/ask-user.ts +179 -0
  353. package/telegram-plugin/attachment-path.ts +80 -0
  354. package/telegram-plugin/auth-code-redact.ts +83 -0
  355. package/telegram-plugin/auth-dashboard.ts +1104 -0
  356. package/telegram-plugin/auth-slot-parser.ts +497 -0
  357. package/telegram-plugin/auto-fallback-dispatcher.ts +68 -0
  358. package/telegram-plugin/auto-fallback.ts +348 -0
  359. package/telegram-plugin/bridge/bridge.ts +687 -0
  360. package/telegram-plugin/bridge/ipc-client.ts +326 -0
  361. package/telegram-plugin/bun.lock +218 -0
  362. package/telegram-plugin/card-format.ts +62 -0
  363. package/telegram-plugin/channel-envelope-safety.test.ts +56 -0
  364. package/telegram-plugin/channel-envelope-safety.ts +56 -0
  365. package/telegram-plugin/chat-lock.ts +65 -0
  366. package/telegram-plugin/context-exhaustion.ts +38 -0
  367. package/telegram-plugin/credits-watch.ts +220 -0
  368. package/telegram-plugin/dist/bridge/bridge.js +24758 -0
  369. package/telegram-plugin/dist/foreman/foreman.js +30723 -0
  370. package/telegram-plugin/dist/gateway/gateway.js +46497 -0
  371. package/telegram-plugin/dist/server.js +24551 -0
  372. package/telegram-plugin/dm-command-gate.ts +56 -0
  373. package/telegram-plugin/docs/gateway-server-split.md +133 -0
  374. package/telegram-plugin/docs/multi-agent-card-design.md +847 -0
  375. package/telegram-plugin/docs/pinned-progress-card-reliability.md +144 -0
  376. package/telegram-plugin/docs/stream-json-daemon-mode.md +477 -0
  377. package/telegram-plugin/docs/waiting-ux-spec.md +233 -0
  378. package/telegram-plugin/draft-stream.ts +442 -0
  379. package/telegram-plugin/draft-transport.ts +72 -0
  380. package/telegram-plugin/first-paint.ts +246 -0
  381. package/telegram-plugin/fleet-state.ts +246 -0
  382. package/telegram-plugin/foreman/foreman-create-flow.ts +202 -0
  383. package/telegram-plugin/foreman/foreman-handlers.ts +493 -0
  384. package/telegram-plugin/foreman/foreman.ts +1130 -0
  385. package/telegram-plugin/foreman/setup-flow.ts +345 -0
  386. package/telegram-plugin/foreman/setup-state.ts +239 -0
  387. package/telegram-plugin/foreman/state.ts +203 -0
  388. package/telegram-plugin/format.ts +685 -0
  389. package/telegram-plugin/gateway/access-validator.test.ts +95 -0
  390. package/telegram-plugin/gateway/access-validator.ts +37 -0
  391. package/telegram-plugin/gateway/boot-card.ts +582 -0
  392. package/telegram-plugin/gateway/boot-probes.ts +863 -0
  393. package/telegram-plugin/gateway/boot-reason.ts +51 -0
  394. package/telegram-plugin/gateway/boot-sweep-filter.test.ts +54 -0
  395. package/telegram-plugin/gateway/boot-sweep-filter.ts +32 -0
  396. package/telegram-plugin/gateway/clean-shutdown-marker.ts +183 -0
  397. package/telegram-plugin/gateway/disconnect-flush.ts +109 -0
  398. package/telegram-plugin/gateway/gateway.ts +10202 -0
  399. package/telegram-plugin/gateway/inbound-coalesce.ts +147 -0
  400. package/telegram-plugin/gateway/inject-handler.test.ts +221 -0
  401. package/telegram-plugin/gateway/inject-handler.ts +190 -0
  402. package/telegram-plugin/gateway/ipc-protocol.ts +151 -0
  403. package/telegram-plugin/gateway/ipc-server.ts +494 -0
  404. package/telegram-plugin/gateway/pid-file.ts +103 -0
  405. package/telegram-plugin/gateway/poll-health.ts +156 -0
  406. package/telegram-plugin/gateway/preamble-suppressor.ts +154 -0
  407. package/telegram-plugin/gateway/quota-cache.ts +125 -0
  408. package/telegram-plugin/gateway/resolve-calling-subagent.ts +78 -0
  409. package/telegram-plugin/gateway/restart-watchdog.ts +200 -0
  410. package/telegram-plugin/gateway/session-marker.ts +83 -0
  411. package/telegram-plugin/gateway/shutdown-drain.ts +162 -0
  412. package/telegram-plugin/gateway/startup-mutex.ts +285 -0
  413. package/telegram-plugin/gateway/startup-network-retry.ts +142 -0
  414. package/telegram-plugin/gateway/turn-active-marker.ts +176 -0
  415. package/telegram-plugin/gateway/unhandled-rejection-policy.ts +78 -0
  416. package/telegram-plugin/handoff-continuity.ts +200 -0
  417. package/telegram-plugin/history.ts +468 -0
  418. package/telegram-plugin/hooks/hooks.json +58 -0
  419. package/telegram-plugin/hooks/secret-guard-pretool.mjs +208 -0
  420. package/telegram-plugin/hooks/secret-scrub-stop.mjs +98 -0
  421. package/telegram-plugin/hooks/silent-end-interrupt-stop.mjs +111 -0
  422. package/telegram-plugin/hooks/subagent-tracker-posttool.mjs +296 -0
  423. package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +261 -0
  424. package/telegram-plugin/html-sanitize.ts +244 -0
  425. package/telegram-plugin/idle-footer.ts +65 -0
  426. package/telegram-plugin/inline-keyboard-callbacks.ts +166 -0
  427. package/telegram-plugin/interrupt-marker.ts +66 -0
  428. package/telegram-plugin/issues-card.ts +371 -0
  429. package/telegram-plugin/issues-watcher.ts +125 -0
  430. package/telegram-plugin/model-unavailable.ts +325 -0
  431. package/telegram-plugin/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  432. package/telegram-plugin/operator-events-history.ts +94 -0
  433. package/telegram-plugin/operator-events.fixtures.json +161 -0
  434. package/telegram-plugin/operator-events.ts +421 -0
  435. package/telegram-plugin/package.json +55 -0
  436. package/telegram-plugin/permission-rule.ts +133 -0
  437. package/telegram-plugin/permission-title.ts +117 -0
  438. package/telegram-plugin/pin-event-log.ts +76 -0
  439. package/telegram-plugin/plugin-logger.ts +136 -0
  440. package/telegram-plugin/progress-card-driver.ts +2697 -0
  441. package/telegram-plugin/progress-card-pin-manager.ts +589 -0
  442. package/telegram-plugin/progress-card-pin-watchdog.ts +98 -0
  443. package/telegram-plugin/progress-card.ts +1409 -0
  444. package/telegram-plugin/pty-partial-handler.ts +247 -0
  445. package/telegram-plugin/pty-tail.ts +730 -0
  446. package/telegram-plugin/quota-check.ts +474 -0
  447. package/telegram-plugin/recent-outbound-dedup.ts +169 -0
  448. package/telegram-plugin/registry/api-registry.test.ts +201 -0
  449. package/telegram-plugin/registry/subagents-bugs.test.ts +454 -0
  450. package/telegram-plugin/registry/subagents-schema.ts +509 -0
  451. package/telegram-plugin/registry/subagents.test.ts +476 -0
  452. package/telegram-plugin/registry/turns-schema.test.ts +101 -0
  453. package/telegram-plugin/registry/turns-schema.ts +417 -0
  454. package/telegram-plugin/retry-api-call.ts +172 -0
  455. package/telegram-plugin/scripts/build.mjs +78 -0
  456. package/telegram-plugin/secret-detect/audit.ts +66 -0
  457. package/telegram-plugin/secret-detect/chunker.ts +37 -0
  458. package/telegram-plugin/secret-detect/entropy.ts +20 -0
  459. package/telegram-plugin/secret-detect/gitleaks-loader.ts +74 -0
  460. package/telegram-plugin/secret-detect/gitleaks.toml +27 -0
  461. package/telegram-plugin/secret-detect/index.ts +218 -0
  462. package/telegram-plugin/secret-detect/kv-scanner.ts +60 -0
  463. package/telegram-plugin/secret-detect/mask.ts +13 -0
  464. package/telegram-plugin/secret-detect/patterns.ts +115 -0
  465. package/telegram-plugin/secret-detect/pipeline.ts +144 -0
  466. package/telegram-plugin/secret-detect/rewrite.ts +26 -0
  467. package/telegram-plugin/secret-detect/secretlint-source.ts +95 -0
  468. package/telegram-plugin/secret-detect/slug.ts +44 -0
  469. package/telegram-plugin/secret-detect/staging.ts +85 -0
  470. package/telegram-plugin/secret-detect/suppressor.ts +34 -0
  471. package/telegram-plugin/secret-detect/url-redact.ts +60 -0
  472. package/telegram-plugin/secret-detect/vault-write.ts +56 -0
  473. package/telegram-plugin/server.js +41795 -0
  474. package/telegram-plugin/server.ts +171 -0
  475. package/telegram-plugin/session-tail.ts +884 -0
  476. package/telegram-plugin/shared/bot-runtime.ts +324 -0
  477. package/telegram-plugin/silent-reply.ts +58 -0
  478. package/telegram-plugin/slot-banner-driver.ts +147 -0
  479. package/telegram-plugin/slot-banner.ts +86 -0
  480. package/telegram-plugin/start.js +26 -0
  481. package/telegram-plugin/startup-reset.ts +45 -0
  482. package/telegram-plugin/status-reactions.ts +332 -0
  483. package/telegram-plugin/steering.ts +155 -0
  484. package/telegram-plugin/sticker-aliases.ts +249 -0
  485. package/telegram-plugin/stream-controller.ts +311 -0
  486. package/telegram-plugin/stream-reply-handler.ts +664 -0
  487. package/telegram-plugin/streaming-metrics.ts +134 -0
  488. package/telegram-plugin/streaming-report.ts +204 -0
  489. package/telegram-plugin/subagent-watcher.ts +880 -0
  490. package/telegram-plugin/telegram-button-constraints.ts +191 -0
  491. package/telegram-plugin/telegraph.ts +381 -0
  492. package/telegram-plugin/tests/HARNESS.md +340 -0
  493. package/telegram-plugin/tests/_progress-card-harness.ts +105 -0
  494. package/telegram-plugin/tests/active-pins-boot-reaper.test.ts +211 -0
  495. package/telegram-plugin/tests/active-pins-sweep.test.ts +309 -0
  496. package/telegram-plugin/tests/active-pins.test.ts +187 -0
  497. package/telegram-plugin/tests/active-reactions-sweep.test.ts +116 -0
  498. package/telegram-plugin/tests/active-reactions.test.ts +198 -0
  499. package/telegram-plugin/tests/answer-stream-dedup.test.ts +352 -0
  500. package/telegram-plugin/tests/answer-stream-silent-markers.test.ts +236 -0
  501. package/telegram-plugin/tests/answer-stream.test.ts +878 -0
  502. package/telegram-plugin/tests/ask-user.test.ts +203 -0
  503. package/telegram-plugin/tests/attachment-path.test.ts +199 -0
  504. package/telegram-plugin/tests/auth-account-identity-surface.test.ts +118 -0
  505. package/telegram-plugin/tests/auth-code-auto-capture.test.ts +144 -0
  506. package/telegram-plugin/tests/auth-code-redact.test.ts +248 -0
  507. package/telegram-plugin/tests/auth-dashboard-edge-cases.test.ts +260 -0
  508. package/telegram-plugin/tests/auth-dashboard-restart-flow.test.ts +140 -0
  509. package/telegram-plugin/tests/auth-dashboard-v3b.test.ts +559 -0
  510. package/telegram-plugin/tests/auth-dashboard.test.ts +1045 -0
  511. package/telegram-plugin/tests/auth-login-url-button.test.ts +122 -0
  512. package/telegram-plugin/tests/auth-slot-commands.test.ts +640 -0
  513. package/telegram-plugin/tests/auto-fallback-dispatcher.e2e.test.ts +183 -0
  514. package/telegram-plugin/tests/auto-fallback.test.ts +381 -0
  515. package/telegram-plugin/tests/boot-card-account-quota.test.ts +137 -0
  516. package/telegram-plugin/tests/boot-card-dedupe.test.ts +154 -0
  517. package/telegram-plugin/tests/boot-card-probe-target.test.ts +194 -0
  518. package/telegram-plugin/tests/boot-card-reason.test.ts +103 -0
  519. package/telegram-plugin/tests/boot-card-render.test.ts +219 -0
  520. package/telegram-plugin/tests/boot-probes.test.ts +451 -0
  521. package/telegram-plugin/tests/bot-api.harness.ts +116 -0
  522. package/telegram-plugin/tests/bot-runtime.test.ts +190 -0
  523. package/telegram-plugin/tests/bridge-anonymous-refuse.test.ts +60 -0
  524. package/telegram-plugin/tests/context-exhaustion.test.ts +114 -0
  525. package/telegram-plugin/tests/credits-watch.test.ts +221 -0
  526. package/telegram-plugin/tests/dm-command-gate.test.ts +176 -0
  527. package/telegram-plugin/tests/draft-stream.test.ts +752 -0
  528. package/telegram-plugin/tests/draft-transport.test.ts +141 -0
  529. package/telegram-plugin/tests/e2e.test.ts +436 -0
  530. package/telegram-plugin/tests/fake-bot-api.test.ts +213 -0
  531. package/telegram-plugin/tests/fake-bot-api.ts +617 -0
  532. package/telegram-plugin/tests/false-restart-banner.test.ts +253 -0
  533. package/telegram-plugin/tests/first-paint.test.ts +257 -0
  534. package/telegram-plugin/tests/fixtures/pty-tail-tmux-fragment.bin +6 -0
  535. package/telegram-plugin/tests/fixtures/service-log-current-claude-code.bin +3624 -0
  536. package/telegram-plugin/tests/fleet-state-watcher.test.ts +101 -0
  537. package/telegram-plugin/tests/fleet-state.test.ts +185 -0
  538. package/telegram-plugin/tests/foreman-create-flow.test.ts +359 -0
  539. package/telegram-plugin/tests/foreman-handlers.test.ts +347 -0
  540. package/telegram-plugin/tests/foreman-state.test.ts +164 -0
  541. package/telegram-plugin/tests/foreman-write-ops.test.ts +214 -0
  542. package/telegram-plugin/tests/gateway-409-retry-banner.test.ts +173 -0
  543. package/telegram-plugin/tests/gateway-boot-marker-clear.test.ts +72 -0
  544. package/telegram-plugin/tests/gateway-bridge.test.ts +811 -0
  545. package/telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts +414 -0
  546. package/telegram-plugin/tests/gateway-disconnect-flush.test.ts +144 -0
  547. package/telegram-plugin/tests/gateway-message-validator.test.ts +133 -0
  548. package/telegram-plugin/tests/gateway-no-reply-single-emit.test.ts +103 -0
  549. package/telegram-plugin/tests/gateway-secret-detect.test.ts +127 -0
  550. package/telegram-plugin/tests/gateway-startup-mutex.test.ts +284 -0
  551. package/telegram-plugin/tests/gateway-startup-network-retry.test.ts +185 -0
  552. package/telegram-plugin/tests/gateway-startup-reset.test.ts +72 -0
  553. package/telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts +125 -0
  554. package/telegram-plugin/tests/handoff-continuity.test.ts +249 -0
  555. package/telegram-plugin/tests/harness-ordering-invariants.test.ts +243 -0
  556. package/telegram-plugin/tests/harness-parse-mode-validation.test.ts +114 -0
  557. package/telegram-plugin/tests/history.test.ts +364 -0
  558. package/telegram-plugin/tests/html-balanced.ts +63 -0
  559. package/telegram-plugin/tests/html-sanitize.test.ts +146 -0
  560. package/telegram-plugin/tests/idle-footer-wiring.test.ts +88 -0
  561. package/telegram-plugin/tests/idle-footer.test.ts +66 -0
  562. package/telegram-plugin/tests/inbound-coalesce.test.ts +127 -0
  563. package/telegram-plugin/tests/inline-keyboard-callbacks.test.ts +150 -0
  564. package/telegram-plugin/tests/interrupt-marker.test.ts +126 -0
  565. package/telegram-plugin/tests/ipc-protocol.test.ts +218 -0
  566. package/telegram-plugin/tests/ipc-server-anonymous-refuse.test.ts +82 -0
  567. package/telegram-plugin/tests/ipc-server-client.test.ts +323 -0
  568. package/telegram-plugin/tests/ipc-server-race.test.ts +183 -0
  569. package/telegram-plugin/tests/ipc-server-validate-operator.test.ts +91 -0
  570. package/telegram-plugin/tests/ipc-server-validate-pty-partial.test.ts +64 -0
  571. package/telegram-plugin/tests/ipc-server-validate-update-placeholder.test.ts +77 -0
  572. package/telegram-plugin/tests/ipc-validator.test.ts +274 -0
  573. package/telegram-plugin/tests/issues-card.test.ts +495 -0
  574. package/telegram-plugin/tests/issues-watcher.test.ts +165 -0
  575. package/telegram-plugin/tests/model-unavailable.test.ts +303 -0
  576. package/telegram-plugin/tests/multi-turn-continuity.test.ts +159 -0
  577. package/telegram-plugin/tests/operator-events-history.test.ts +125 -0
  578. package/telegram-plugin/tests/operator-events-session-tail.test.ts +192 -0
  579. package/telegram-plugin/tests/operator-events.test.ts +331 -0
  580. package/telegram-plugin/tests/outbound-ordering.test.ts +293 -0
  581. package/telegram-plugin/tests/parse-mode-rotation.test.ts +164 -0
  582. package/telegram-plugin/tests/permission-rule.test.ts +121 -0
  583. package/telegram-plugin/tests/permission-title.test.ts +106 -0
  584. package/telegram-plugin/tests/pin-event-log.test.ts +124 -0
  585. package/telegram-plugin/tests/plugin-logger.test.ts +97 -0
  586. package/telegram-plugin/tests/poll-health.test.ts +86 -0
  587. package/telegram-plugin/tests/preamble-suppressor.test.ts +285 -0
  588. package/telegram-plugin/tests/progress-card-api-failure-during-deferred.test.ts +73 -0
  589. package/telegram-plugin/tests/progress-card-close-paths-converge.test.ts +272 -0
  590. package/telegram-plugin/tests/progress-card-cross-turn.test.ts +258 -0
  591. package/telegram-plugin/tests/progress-card-dispose-preservepending.test.ts +81 -0
  592. package/telegram-plugin/tests/progress-card-draft-flag.test.ts +80 -0
  593. package/telegram-plugin/tests/progress-card-driver-eviction.test.ts +215 -0
  594. package/telegram-plugin/tests/progress-card-driver-fleet-shadow.test.ts +123 -0
  595. package/telegram-plugin/tests/progress-card-driver-force-complete-parent-done.test.ts +76 -0
  596. package/telegram-plugin/tests/progress-card-edit-timestamps-budget.test.ts +62 -0
  597. package/telegram-plugin/tests/progress-card-memory-bounds.test.ts +84 -0
  598. package/telegram-plugin/tests/progress-card-pin-failure-paths.test.ts +139 -0
  599. package/telegram-plugin/tests/progress-card-pin-manager.test.ts +773 -0
  600. package/telegram-plugin/tests/progress-card-pin-race-fast-turn.test.ts +66 -0
  601. package/telegram-plugin/tests/progress-card-pin-sidecar-partial-write.test.ts +64 -0
  602. package/telegram-plugin/tests/progress-card-pin-watchdog.test.ts +190 -0
  603. package/telegram-plugin/tests/progress-card-sigterm-pin-flush.test.ts +146 -0
  604. package/telegram-plugin/tests/progress-update.test.ts +236 -0
  605. package/telegram-plugin/tests/protocol-fixtures.test.ts +59 -0
  606. package/telegram-plugin/tests/protocol-fixtures.ts +198 -0
  607. package/telegram-plugin/tests/pty-partial-handler.test.ts +326 -0
  608. package/telegram-plugin/tests/pty-tail-real-fixture.test.ts +114 -0
  609. package/telegram-plugin/tests/pty-tail-tmux-fragment.test.ts +71 -0
  610. package/telegram-plugin/tests/pty-tail.test.ts +525 -0
  611. package/telegram-plugin/tests/quota-cache.test.ts +187 -0
  612. package/telegram-plugin/tests/quota-check.test.ts +622 -0
  613. package/telegram-plugin/tests/races.test.ts +842 -0
  614. package/telegram-plugin/tests/real-gateway-f1-ladder-integrity.test.ts +123 -0
  615. package/telegram-plugin/tests/real-gateway-f2-instant-draft.test.ts +82 -0
  616. package/telegram-plugin/tests/real-gateway-f3-late-card.test.ts +114 -0
  617. package/telegram-plugin/tests/real-gateway-harness.ts +699 -0
  618. package/telegram-plugin/tests/real-gateway-i6-turn-flush-replay-dedup.test.ts +313 -0
  619. package/telegram-plugin/tests/real-gateway-ipc-lifecycle.test.ts +299 -0
  620. package/telegram-plugin/tests/real-gateway-spec.test.ts +487 -0
  621. package/telegram-plugin/tests/real-gateway.smoke.test.ts +101 -0
  622. package/telegram-plugin/tests/recent-outbound-dedup.test.ts +192 -0
  623. package/telegram-plugin/tests/registry-turns.test.ts +432 -0
  624. package/telegram-plugin/tests/reply-terminal-reaction.test.ts +149 -0
  625. package/telegram-plugin/tests/resolve-calling-subagent.test.ts +269 -0
  626. package/telegram-plugin/tests/restart-watchdog.test.ts +224 -0
  627. package/telegram-plugin/tests/retry-api-call.test.ts +287 -0
  628. package/telegram-plugin/tests/secret-detect-audit.test.ts +58 -0
  629. package/telegram-plugin/tests/secret-detect-fail-closed.test.ts +83 -0
  630. package/telegram-plugin/tests/secret-detect-gitleaks.test.ts +32 -0
  631. package/telegram-plugin/tests/secret-detect-oauth-code.test.ts +308 -0
  632. package/telegram-plugin/tests/secret-detect-pipeline.test.ts +123 -0
  633. package/telegram-plugin/tests/secret-detect-secretlint.test.ts +101 -0
  634. package/telegram-plugin/tests/secret-detect-staging.test.ts +45 -0
  635. package/telegram-plugin/tests/secret-detect-suppressor-no-silent-allow.test.ts +67 -0
  636. package/telegram-plugin/tests/secret-detect.test.ts +223 -0
  637. package/telegram-plugin/tests/secret-guard-pretool.test.ts +194 -0
  638. package/telegram-plugin/tests/send-typing-action-validation.test.ts +61 -0
  639. package/telegram-plugin/tests/session-tail-capped.test.ts +285 -0
  640. package/telegram-plugin/tests/session-tail.test.ts +524 -0
  641. package/telegram-plugin/tests/setup-flow.test.ts +510 -0
  642. package/telegram-plugin/tests/setup-state.test.ts +146 -0
  643. package/telegram-plugin/tests/silent-reply-guard.test.ts +122 -0
  644. package/telegram-plugin/tests/slot-banner-driver.e2e.test.ts +350 -0
  645. package/telegram-plugin/tests/slot-banner.test.ts +74 -0
  646. package/telegram-plugin/tests/snapshot-serializer.ts +79 -0
  647. package/telegram-plugin/tests/spawn-detached-cgroup-escape.test.ts +51 -0
  648. package/telegram-plugin/tests/status-accent.test.ts +186 -0
  649. package/telegram-plugin/tests/status-reactions-allowed-filter.test.ts +132 -0
  650. package/telegram-plugin/tests/status-reactions.test.ts +314 -0
  651. package/telegram-plugin/tests/steering.test.ts +282 -0
  652. package/telegram-plugin/tests/sticker-aliases.test.ts +232 -0
  653. package/telegram-plugin/tests/stream-controller-html-fallback.test.ts +127 -0
  654. package/telegram-plugin/tests/stream-controller.test.ts +262 -0
  655. package/telegram-plugin/tests/stream-reply-error-paths.test.ts +208 -0
  656. package/telegram-plugin/tests/stream-reply-handler.test.ts +1292 -0
  657. package/telegram-plugin/tests/streaming-e2e.test.ts +389 -0
  658. package/telegram-plugin/tests/streaming-metrics.test.ts +201 -0
  659. package/telegram-plugin/tests/streaming-orchestration.test.ts +756 -0
  660. package/telegram-plugin/tests/subagent-registry-bugs.test.ts +725 -0
  661. package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +213 -0
  662. package/telegram-plugin/tests/subagent-watcher-parent-marker.test.ts +274 -0
  663. package/telegram-plugin/tests/subagent-watcher-stall-notification.test.ts +243 -0
  664. package/telegram-plugin/tests/subagent-watcher.test.ts +877 -0
  665. package/telegram-plugin/tests/subagents-schema-init-order.test.ts +109 -0
  666. package/telegram-plugin/tests/sync-chat-running-subagents.test.ts +116 -0
  667. package/telegram-plugin/tests/telegram-button-constraints.test.ts +194 -0
  668. package/telegram-plugin/tests/telegram-format.test.ts +1093 -0
  669. package/telegram-plugin/tests/telegraph.test.ts +246 -0
  670. package/telegram-plugin/tests/tool-labels.test.ts +383 -0
  671. package/telegram-plugin/tests/turn-active-marker.test.ts +195 -0
  672. package/telegram-plugin/tests/turn-end-regressions.test.ts +489 -0
  673. package/telegram-plugin/tests/turn-flush-card-takeover.test.ts +218 -0
  674. package/telegram-plugin/tests/turn-flush-dedup-controller.test.ts +144 -0
  675. package/telegram-plugin/tests/turn-flush-prose-recovery.test.ts +78 -0
  676. package/telegram-plugin/tests/turn-flush-safety.test.ts +189 -0
  677. package/telegram-plugin/tests/turn-signal-tracker.test.ts +107 -0
  678. package/telegram-plugin/tests/turns-writer.test.ts +323 -0
  679. package/telegram-plugin/tests/two-zone-bg-carry-full-lifecycle.test.ts +131 -0
  680. package/telegram-plugin/tests/two-zone-bg-detection.test.ts +120 -0
  681. package/telegram-plugin/tests/two-zone-bg-done-when-all-terminal.test.ts +114 -0
  682. package/telegram-plugin/tests/two-zone-bg-early-turn-end.test.ts +87 -0
  683. package/telegram-plugin/tests/two-zone-bg-survives-next-turn.test.ts +211 -0
  684. package/telegram-plugin/tests/two-zone-card-cap.test.ts +62 -0
  685. package/telegram-plugin/tests/two-zone-card-fleet-row.test.ts +101 -0
  686. package/telegram-plugin/tests/two-zone-card-header-phases.test.ts +68 -0
  687. package/telegram-plugin/tests/two-zone-card-html-balance.test.ts +110 -0
  688. package/telegram-plugin/tests/two-zone-card-lifecycle.test.ts +128 -0
  689. package/telegram-plugin/tests/two-zone-card-sanitise.test.ts +58 -0
  690. package/telegram-plugin/tests/two-zone-card-snapshot.test.ts +133 -0
  691. package/telegram-plugin/tests/two-zone-concurrent-turns-isolation.test.ts +155 -0
  692. package/telegram-plugin/tests/two-zone-phasefor-precedence.test.ts +117 -0
  693. package/telegram-plugin/tests/two-zone-snapshot-extras.test.ts +143 -0
  694. package/telegram-plugin/tests/two-zone-stuck-edit-throttle.test.ts +149 -0
  695. package/telegram-plugin/tests/two-zone-stuck-header-escalation.test.ts +101 -0
  696. package/telegram-plugin/tests/two-zone-stuck-per-member.test.ts +114 -0
  697. package/telegram-plugin/tests/two-zone-stuck-recovery.test.ts +105 -0
  698. package/telegram-plugin/tests/typing-wrap.test.ts +141 -0
  699. package/telegram-plugin/tests/unhandled-rejection-policy.test.ts +147 -0
  700. package/telegram-plugin/tests/update-factory-edited-and-reactions.test.ts +108 -0
  701. package/telegram-plugin/tests/update-factory.ts +305 -0
  702. package/telegram-plugin/tests/vault-grant-wizard.test.ts +84 -0
  703. package/telegram-plugin/tests/vault-grants-revoke.test.ts +265 -0
  704. package/telegram-plugin/tests/vault-subcommands.test.ts +234 -0
  705. package/telegram-plugin/tests/voice-transcribe.test.ts +196 -0
  706. package/telegram-plugin/tests/waiting-ux-harness.ts +381 -0
  707. package/telegram-plugin/tests/waiting-ux.e2e.test.ts +233 -0
  708. package/telegram-plugin/tests/welcome-text.test.ts +407 -0
  709. package/telegram-plugin/tool-error-filter.ts +89 -0
  710. package/telegram-plugin/tool-labels.ts +330 -0
  711. package/telegram-plugin/tool-names.ts +53 -0
  712. package/telegram-plugin/turn-flush-prose-recovery.ts +40 -0
  713. package/telegram-plugin/turn-flush-safety.ts +109 -0
  714. package/telegram-plugin/turn-signal-tracker.ts +79 -0
  715. package/telegram-plugin/two-zone-card.ts +249 -0
  716. package/telegram-plugin/typing-wrap.ts +92 -0
  717. package/telegram-plugin/voice-transcribe.ts +166 -0
  718. package/telegram-plugin/welcome-text.ts +359 -0
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Human-readable labels for tool_use events on the progress card.
3
+ *
4
+ * Each function takes the tool's `input` object (as Claude Code records it
5
+ * in the session JSONL) and returns a short suffix to append to the tool
6
+ * name, e.g. `toolLabel('Read', { file_path: '/abs/foo.ts' })` → `'foo.ts'`.
7
+ *
8
+ * Goals:
9
+ * - Short enough to fit on one Telegram line without wrapping on mobile
10
+ * - Recognisable — paths shown as basename only; commands truncated at
11
+ * ~40 chars / first newline; queries quoted; hostnames for URLs
12
+ * - Safe: all outputs pass through the renderer's HTML escape, and
13
+ * inputs that look malformed fall back to empty string
14
+ *
15
+ * Keep this file tiny and dependency-free — it's in the hot path of
16
+ * every render.
17
+ */
18
+
19
+ const MAX_LABEL_CHARS = 60
20
+ const MAX_BASH_CHARS = 40
21
+ /**
22
+ * Cap for human-readable `description` fields (Bash, fallback). Set
23
+ * larger than MAX_BASH_CHARS because descriptions are agent-authored
24
+ * English prose intended for humans — letting them wrap a couple of
25
+ * mobile lines is fine; aggressive truncation hides intent.
26
+ */
27
+ const MAX_DESCRIPTION_CHARS = 160
28
+
29
+ /**
30
+ * Basename of a path — just the trailing segment. `/a/b/c.ts` → `c.ts`.
31
+ * We used to shorten to "project/last-two-segments" but user feedback
32
+ * asked for a cleaner look in the checklist; the path's directory rarely
33
+ * adds useful information when the user is watching tool calls scroll by.
34
+ */
35
+ function basename(p: string): string {
36
+ if (!p) return ''
37
+ const parts = p.split('/').filter(Boolean)
38
+ return parts.length > 0 ? parts[parts.length - 1] : p
39
+ }
40
+
41
+ /**
42
+ * Shorten a Grep `path` argument. Prefer "<parent>/<dir>/" form for
43
+ * directories so the hint is recognisable (e.g. "src/" rather than just
44
+ * "src" is ambiguous vs. a file). Returns the basename for files.
45
+ */
46
+ function shortenGrepPath(p: string): string {
47
+ if (!p) return 'repo'
48
+ const hadTrailingSlash = /\/+$/.test(p)
49
+ const trimmed = p.replace(/\/+$/, '')
50
+ const parts = trimmed.split('/').filter(Boolean)
51
+ if (parts.length === 0) return 'repo'
52
+ const last = parts[parts.length - 1]
53
+ if (hadTrailingSlash) return `${last}/`
54
+ // Dotfiles like `.env`, `.gitignore`, `.npmrc` — a leading dot with no
55
+ // further dot — are files, not directories. The old heuristic ("no dot
56
+ // → dir") mislabeled them as directories.
57
+ if (last.startsWith('.') && !last.slice(1).includes('.')) return last
58
+ // Otherwise: no extension → treat as a directory hint.
59
+ if (!last.includes('.')) return `${last}/`
60
+ return last
61
+ }
62
+
63
+ /**
64
+ * Extract a hostname from a URL. Falls back to the original string on
65
+ * malformed input.
66
+ */
67
+ function hostFromUrl(u: string): string {
68
+ if (!u) return ''
69
+ try {
70
+ return new URL(u).host
71
+ } catch {
72
+ // Not a valid URL — just return the raw input, truncated.
73
+ return truncate(u)
74
+ }
75
+ }
76
+
77
+ function truncate(s: string, n = MAX_LABEL_CHARS): string {
78
+ if (s.length <= n) return s
79
+ return s.slice(0, n - 1) + '…'
80
+ }
81
+
82
+ /**
83
+ * Strip HTML tags from a preview string. MCP tools like `stream_reply`
84
+ * accept Telegram-HTML text as input; when we use that text as a label
85
+ * preview, the raw `<b>`/`<i>`/etc. markers would pass through
86
+ * `escapeHtml` in the renderer and show up as visible `<b>` on screen.
87
+ * Dropping tags here keeps the preview human-readable.
88
+ *
89
+ * Requires an ASCII letter (or `/`) immediately after `<` so comparison
90
+ * operators in plain-text queries (`"find x < 5 and y > 3"`) survive
91
+ * unmolested. A naive `/<[^>]+>/g` would otherwise eat everything
92
+ * between the two brackets.
93
+ */
94
+ function stripHtml(s: string): string {
95
+ return s.replace(/<\/?[a-zA-Z][^>]*>/g, '')
96
+ }
97
+
98
+ function firstLine(s: string): string {
99
+ const idx = s.indexOf('\n')
100
+ return idx === -1 ? s : s.slice(0, idx)
101
+ }
102
+
103
+ /**
104
+ * Return true when the label produced by `toolLabel(tool, input)` came
105
+ * from a human-authored `description` field rather than a raw fallback
106
+ * (filename, command string, hostname, etc.). The progress card uses this
107
+ * flag to suppress the tool-name prefix — "Check commit state" reads
108
+ * better than "Bash Check commit state".
109
+ *
110
+ * Rules:
111
+ * - Bash / BashOutput → true when `input.description` is a non-empty string
112
+ * - Task / Agent → true when `input.description` is a non-empty string
113
+ * - All other tools → false (keep the "ToolName label" concat)
114
+ *
115
+ * WebFetch and WebSearch are intentionally left as false because the
116
+ * tool name provides important context ("WebFetch example.com" makes more
117
+ * sense than just "example.com").
118
+ */
119
+ export function isHumanDescription(
120
+ tool: string,
121
+ input?: Record<string, unknown>,
122
+ ): boolean {
123
+ if (!input || typeof input !== 'object') return false
124
+ const description =
125
+ typeof input['description'] === 'string' ? input['description'] : undefined
126
+ switch (tool) {
127
+ case 'Bash':
128
+ case 'BashOutput':
129
+ case 'Task':
130
+ case 'Agent':
131
+ return typeof description === 'string' && description.trim().length > 0
132
+ default:
133
+ return false
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Return a display suffix for `tool` given its `input`, without the tool
139
+ * name itself. Caller renders `${tool} ${suffix}` (space-separated; no
140
+ * colon) — the checklist format the progress card uses.
141
+ *
142
+ * The optional `preamble` is the most recent short `text` content block
143
+ * the model emitted just before this `tool_use` in the same assistant
144
+ * message — the model's natural "I'll check foo.ts" narration. For the
145
+ * file/search tools (Read/Write/Edit/Grep/Glob/NotebookEdit) we prefer
146
+ * that prose over the filename/pattern fallback when it's short enough
147
+ * to fit on one mobile line (single-line, ≤160 chars). Multi-line or
148
+ * longer text is treated as a narrative step, not a per-tool preamble,
149
+ * and the fallback label wins. Bash/BashOutput prefer their own
150
+ * `input.description` first but fall back to preamble when it's absent
151
+ * (then the raw command). Task/Agent ignore preamble entirely — their
152
+ * `input.description` / `subagent_type` is always set by the harness.
153
+ */
154
+ export function toolLabel(
155
+ tool: string,
156
+ input?: Record<string, unknown>,
157
+ preamble?: string,
158
+ ): string {
159
+ if (!input || typeof input !== 'object') return ''
160
+ const str = (k: string): string | undefined =>
161
+ typeof input[k] === 'string' ? (input[k] as string) : undefined
162
+
163
+ const preambleLabel = (): string | null => {
164
+ if (!preamble) return null
165
+ if (preamble.includes('\n')) return null
166
+ const trimmed = preamble.trim()
167
+ if (!trimmed) return null
168
+ if (trimmed.length > MAX_DESCRIPTION_CHARS) return null
169
+ return trimmed
170
+ }
171
+
172
+ switch (tool) {
173
+ case 'Read':
174
+ case 'Write':
175
+ case 'NotebookEdit':
176
+ case 'Edit': {
177
+ const pre = preambleLabel()
178
+ if (pre) return pre
179
+ return truncate(basename(str('file_path') ?? ''))
180
+ }
181
+
182
+ case 'Bash':
183
+ case 'BashOutput': {
184
+ // Priority order (highest to lowest):
185
+ // 1. input.description — agent-authored, human-readable phrase
186
+ // 2. preamble — model's preceding text narration ("Checking the logs")
187
+ // (same single-line + length gate as file tools)
188
+ // 3. raw command, truncated to MAX_BASH_CHARS
189
+ const description = str('description')
190
+ if (description) return truncate(firstLine(description), MAX_DESCRIPTION_CHARS)
191
+ const pre = preambleLabel()
192
+ if (pre) return pre
193
+ const cmd = str('command') ?? str('bash_id') ?? ''
194
+ return truncate(firstLine(cmd), MAX_BASH_CHARS)
195
+ }
196
+
197
+ case 'KillShell':
198
+ return truncate(str('shell_id') ?? '')
199
+
200
+ case 'Glob': {
201
+ const pre = preambleLabel()
202
+ if (pre) return pre
203
+ return truncate(str('pattern') ?? '')
204
+ }
205
+
206
+ case 'Grep': {
207
+ const pre = preambleLabel()
208
+ if (pre) return pre
209
+ const pat = str('pattern') ?? ''
210
+ if (!pat) return ''
211
+ const path = str('path')
212
+ const where = shortenGrepPath(path ?? '')
213
+ return truncate(`"${pat}" (in ${where})`)
214
+ }
215
+
216
+ case 'WebFetch':
217
+ return truncate(hostFromUrl(str('url') ?? ''))
218
+
219
+ case 'WebSearch': {
220
+ const q = str('query') ?? ''
221
+ return q ? truncate(`"${q}"`) : ''
222
+ }
223
+
224
+ case 'Task':
225
+ case 'Agent': {
226
+ const desc = str('description') ?? str('subagent_type') ?? ''
227
+ return truncate(desc)
228
+ }
229
+
230
+ case 'TodoWrite':
231
+ case 'TaskCreate':
232
+ case 'TaskUpdate':
233
+ case 'TaskList':
234
+ case 'TaskGet':
235
+ case 'TaskStop':
236
+ case 'TaskOutput':
237
+ return ''
238
+
239
+ case 'Skill':
240
+ return truncate(str('skill') ?? '')
241
+
242
+ case 'SlashCommand':
243
+ return truncate(str('command') ?? '')
244
+
245
+ case 'ToolSearch': {
246
+ const q = str('query') ?? ''
247
+ if (!q) return ''
248
+ // "select:Foo,Bar" — the model is loading schemas for named tools.
249
+ // Strip the prefix and show just the names so the checklist reads
250
+ // "ToolSearch Loading schema: Foo, Bar" rather than echoing the raw
251
+ // colon-delimited string.
252
+ const selectMatch = q.match(/^\s*select\s*:\s*(.+)$/i)
253
+ if (selectMatch) {
254
+ const names = selectMatch[1]
255
+ .split(',')
256
+ .map((n) => n.trim())
257
+ .filter((n) => n.length > 0)
258
+ .join(', ')
259
+ return truncate(`Loading schema: ${names}`)
260
+ }
261
+ return truncate(`Searching tools: ${q}`)
262
+ }
263
+
264
+ default:
265
+ // MCP tools (`mcp__<server>__<action>`) share a single prefix and a
266
+ // handful of common shapes. Dispatch them here before the generic
267
+ // key-sweep fallback, which would otherwise echo raw query strings.
268
+ if (tool.startsWith('mcp__')) {
269
+ const description = str('description')
270
+ if (description) return truncate(firstLine(stripHtml(description)), MAX_DESCRIPTION_CHARS)
271
+ const label = mcpBaseLabel(tool)
272
+ const query = str('query') ?? str('text') ?? str('name')
273
+ if (label && query) {
274
+ // Reserve room for the " (…)" wrapping so the total label stays
275
+ // under MAX_LABEL_CHARS. 4 chars of framing: " (" + "…" + ")".
276
+ const budget = Math.max(8, MAX_LABEL_CHARS - label.length - 4)
277
+ const preview = truncate(firstLine(stripHtml(query)), budget)
278
+ return `${label} (${preview})`
279
+ }
280
+ if (label) return truncate(label)
281
+ // No derivable base label — fall through to the generic sweep.
282
+ }
283
+
284
+ // Unknown tool — try common keys in priority order. `description`
285
+ // is checked first because it's the agent's human-readable summary
286
+ // (when present) and beats raw command/path strings.
287
+ for (const k of ['description', 'file_path', 'path', 'url', 'query', 'pattern', 'command']) {
288
+ const v = str(k)
289
+ if (v != null && v.length > 0) {
290
+ if (k === 'file_path' || k === 'path') return truncate(basename(v))
291
+ if (k === 'url') return truncate(hostFromUrl(v))
292
+ if (k === 'description') return truncate(firstLine(v), MAX_DESCRIPTION_CHARS)
293
+ return truncate(firstLine(v))
294
+ }
295
+ }
296
+ return ''
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Derive a "<Server>: <action>" label from an `mcp__<server>__<action>`
302
+ * tool name. Returns the empty string when the name doesn't match the
303
+ * expected shape so callers can fall back to the generic sweep.
304
+ *
305
+ * Servers sometimes ship with noisy machine names (e.g.
306
+ * `switchroom-telegram`) — we map a small allowlist to friendlier
307
+ * labels, and otherwise capitalise the first letter and keep the rest
308
+ * verbatim so unknown servers still render cleanly.
309
+ */
310
+ function mcpBaseLabel(tool: string): string {
311
+ if (!tool.startsWith('mcp__')) return ''
312
+ const parts = tool.slice('mcp__'.length).split('__')
313
+ if (parts.length < 2) return ''
314
+ const rawServer = parts[0]
315
+ // Action may itself contain `__` in theory; preserve anything after
316
+ // the first separator verbatim. In practice actions are single tokens
317
+ // like `recall` or `stream_reply`.
318
+ const action = parts.slice(1).join('__')
319
+ if (!rawServer || !action) return ''
320
+ return `${prettifyServer(rawServer)}: ${action}`
321
+ }
322
+
323
+ function prettifyServer(name: string): string {
324
+ const LABELS: Record<string, string> = {
325
+ 'switchroom-telegram': 'Telegram',
326
+ }
327
+ if (LABELS[name]) return LABELS[name]
328
+ if (!name) return name
329
+ return name.charAt(0).toUpperCase() + name.slice(1)
330
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * MCP tool-name classification helpers.
3
+ *
4
+ * Claude Code prefixes every MCP tool name with `mcp__<server-key>__` where
5
+ * `<server-key>` is whatever name the host's `.mcp.json` used to register
6
+ * this plugin. The key is user-chosen and historical agents still use
7
+ * `clerk-telegram` while new installs use `switchroom-telegram` (and forks
8
+ * may pick yet other names). Matching a single hardcoded prefix would
9
+ * silently break the orphaned-reply backstop and status-reaction
10
+ * suppression for anyone whose config didn't match — which is how bug
11
+ * #TG-IDLE-LEAK regressed on 2026-04-14.
12
+ *
13
+ * Extracted from server.ts so the classification can be unit-tested
14
+ * without importing the whole MCP-server module (which executes
15
+ * side-effects at import: Bot creation, env-var validation, etc).
16
+ */
17
+
18
+ const TELEGRAM_TOOL_PREFIX_RE = /^mcp__[^_].*?telegram__/
19
+
20
+ function stripPrefix(toolName: string): string | null {
21
+ if (!TELEGRAM_TOOL_PREFIX_RE.test(toolName)) return null
22
+ return toolName.replace(TELEGRAM_TOOL_PREFIX_RE, '')
23
+ }
24
+
25
+ /**
26
+ * True if `toolName` is this plugin's `reply` or `stream_reply` tool
27
+ * published under ANY registration key (`clerk-telegram`,
28
+ * `switchroom-telegram`, a custom fork, …). Used by the session-tail
29
+ * handler to set `currentTurnReplyCalled` — when this returns false for
30
+ * a real reply call, turn_end mistakenly runs the orphaned-reply
31
+ * backstop and duplicates the message.
32
+ */
33
+ export function isTelegramReplyTool(toolName: string): boolean {
34
+ const suffix = stripPrefix(toolName)
35
+ return suffix === 'reply' || suffix === 'stream_reply'
36
+ }
37
+
38
+ /**
39
+ * True if `toolName` is any Telegram surface tool whose own handler
40
+ * owns the status-reaction lifecycle for the turn (reply, stream_reply,
41
+ * edit_message, react). The session-tail skips driving a tool reaction
42
+ * for these — the handler itself will fire `setDone()` when the API
43
+ * call completes.
44
+ */
45
+ export function isTelegramSurfaceTool(toolName: string): boolean {
46
+ const suffix = stripPrefix(toolName)
47
+ return (
48
+ suffix === 'reply'
49
+ || suffix === 'stream_reply'
50
+ || suffix === 'edit_message'
51
+ || suffix === 'react'
52
+ )
53
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Turn-flush prose recovery for #51.
3
+ *
4
+ * The gateway's `currentTurnCapturedText` accumulator gates on
5
+ * `currentSessionChatId != null`, while the progress-card driver's
6
+ * `ingest` uses the `chatId` from the IPC envelope (chatHint). When those
7
+ * two views of "is this turn one we're tracking" disagree — e.g., text
8
+ * arrives before enqueue's chatId is captured, or after a mid-turn reset
9
+ * — the progress card renders the assistant prose as narrative steps but
10
+ * `capturedText` stays empty, so `decideTurnFlush` returns `'empty-text'`
11
+ * and the turn-flush backstop never sends the prose to Telegram. The
12
+ * user sees a step bullet on the card and nothing in their chat.
13
+ *
14
+ * This helper bridges the gap: at turn_end, if the gateway has no
15
+ * captured text, peek the progress-card state and recover the assistant
16
+ * prose from the narrative steps. Pure for testability — the gateway
17
+ * is responsible for actually wiring the recovered text into the flush
18
+ * decision.
19
+ */
20
+
21
+ import type { ProgressCardState } from './progress-card.js'
22
+
23
+ /**
24
+ * Returns the joined assistant prose recorded as narrative steps in the
25
+ * progress-card state, trimmed. Empty string when the state has no
26
+ * narratives (or is undefined).
27
+ */
28
+ export function recoverProseFromProgressCard(
29
+ state: ProgressCardState | undefined,
30
+ ): string {
31
+ if (state == null) return ''
32
+ // Defensive: older state shapes (e.g. partial persisted state, mocks
33
+ // in tests) may lack the `narratives` field. Don't throw.
34
+ if (!Array.isArray(state.narratives)) return ''
35
+ const parts: string[] = []
36
+ for (const n of state.narratives) {
37
+ if (typeof n.text === 'string' && n.text.length > 0) parts.push(n.text)
38
+ }
39
+ return parts.join('\n').trim()
40
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Turn-end flush safety net.
3
+ *
4
+ * Purpose: if a Claude turn ends without the model calling the `reply` or
5
+ * `stream_reply` tool, we still want the user to see the model's final
6
+ * assistant text in Telegram. The live Telegram-plugin gateway tracks the
7
+ * current turn's state (chatId, whether the reply tool was called, and the
8
+ * captured assistant text). At turn_end we call `decideTurnFlush` to decide
9
+ * whether to deterministically flush that captured text via the normal
10
+ * outbound send path.
11
+ *
12
+ * The decision is pure — the caller is responsible for actually sending.
13
+ * Keeping the policy in one unit-testable function is the whole point:
14
+ * the suppress cases (silent-reply markers, empty text, sub-agent turns,
15
+ * system-initiated turns with no inbound user message, the feature flag)
16
+ * are easy to audit and extend.
17
+ *
18
+ * The feature flag `SWITCHROOM_TG_TURN_FLUSH_SAFETY` is enabled by default
19
+ * and can be set to `0` / `false` / `off` to disable without a rebuild.
20
+ */
21
+
22
+ const SILENT_MARKERS = new Set(['NO_REPLY', 'HEARTBEAT_OK'])
23
+ // Small buffer so `NO_REPLY.` with a stray period still counts as silent.
24
+ const SILENT_MARKER_MAX_LEN = Math.max(
25
+ ...Array.from(SILENT_MARKERS, m => m.length),
26
+ ) + 2
27
+
28
+ /**
29
+ * Exact-match (case-insensitive, whitespace-trimmed) check for the silent
30
+ * reply sentinels NO_REPLY and HEARTBEAT_OK. Mirrors server.ts
31
+ * `isSilentReplyMarker` intentionally — keeping a local copy avoids a
32
+ * circular-import dependency on server.ts (which has heavy top-level
33
+ * side effects).
34
+ *
35
+ * Trailing-punctuation tolerance: a single trailing non-alphanumeric character
36
+ * (e.g. `NO_REPLY.`) is stripped before matching so accidental punctuation
37
+ * from model output doesn't prevent suppression. Substring matches (e.g.
38
+ * `the agent suggested NO_REPLY earlier`) are still rejected because the
39
+ * length guard rejects anything longer than SILENT_MARKER_MAX_LEN.
40
+ */
41
+ export function isSilentFlushMarker(text: string | undefined): boolean {
42
+ if (typeof text !== 'string') return false
43
+ let trimmed = text.trim()
44
+ if (trimmed.length === 0) return false
45
+ if (trimmed.length > SILENT_MARKER_MAX_LEN) return false
46
+ // Strip a single trailing non-word character to handle "NO_REPLY." etc.
47
+ if (trimmed.length > 0 && /\W$/.test(trimmed)) {
48
+ trimmed = trimmed.slice(0, -1)
49
+ }
50
+ return SILENT_MARKERS.has(trimmed.toUpperCase())
51
+ }
52
+
53
+ export type FlushDecision =
54
+ | { kind: 'flush'; text: string }
55
+ | { kind: 'skip'; reason: FlushSkipReason }
56
+
57
+ export type FlushSkipReason =
58
+ | 'flag-disabled'
59
+ | 'reply-called'
60
+ | 'no-inbound-chat'
61
+ | 'empty-text'
62
+ | 'silent-marker'
63
+
64
+ export interface FlushDecisionInput {
65
+ /** Inbound chat the turn was servicing. `null` means system-initiated /
66
+ * sub-agent — never flush those, they have their own outbound lifecycle. */
67
+ chatId: string | null
68
+ /** True when the model called `reply` / `stream_reply` at least once for
69
+ * this turn. */
70
+ replyCalled: boolean
71
+ /** Raw text content blocks accumulated from assistant events across the
72
+ * turn. Joined + trimmed internally. */
73
+ capturedText: string[]
74
+ /** Feature flag — defaults to true. Pass `false` to force skip everywhere. */
75
+ flushEnabled?: boolean
76
+ }
77
+
78
+ /**
79
+ * Pure decision: should the gateway deterministically send the model's
80
+ * captured assistant text at turn_end? Returns `{kind: 'flush', text}` with
81
+ * the joined text when yes, otherwise `{kind: 'skip', reason}`.
82
+ *
83
+ * Ordering of checks is deliberate: cheapest/strongest first so logs
84
+ * attribute a skip to the most specific cause.
85
+ */
86
+ export function decideTurnFlush(input: FlushDecisionInput): FlushDecision {
87
+ const flushEnabled = input.flushEnabled !== false
88
+ if (!flushEnabled) return { kind: 'skip', reason: 'flag-disabled' }
89
+ if (input.replyCalled) return { kind: 'skip', reason: 'reply-called' }
90
+ if (input.chatId == null) return { kind: 'skip', reason: 'no-inbound-chat' }
91
+ const joined = input.capturedText.join('\n').trim()
92
+ if (joined.length === 0) return { kind: 'skip', reason: 'empty-text' }
93
+ if (isSilentFlushMarker(joined)) return { kind: 'skip', reason: 'silent-marker' }
94
+ return { kind: 'flush', text: joined }
95
+ }
96
+
97
+ /**
98
+ * Resolve the feature-flag env var. Default: enabled. Set
99
+ * SWITCHROOM_TG_TURN_FLUSH_SAFETY to `0`, `false`, `off`, or `no` to disable.
100
+ */
101
+ export function isTurnFlushSafetyEnabled(
102
+ env: Record<string, string | undefined> = process.env,
103
+ ): boolean {
104
+ const raw = env.SWITCHROOM_TG_TURN_FLUSH_SAFETY
105
+ if (raw == null) return true
106
+ const v = raw.trim().toLowerCase()
107
+ if (v === '0' || v === 'false' || v === 'off' || v === 'no') return false
108
+ return true
109
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Per-turn silent-gap tracker for streaming observability.
3
+ *
4
+ * Tracks the longest contiguous interval within a turn where no user-visible
5
+ * signal was sent. Signals include: progress-card edits, status-reaction
6
+ * transitions, answer-lane updates, and fresh sendMessage calls.
7
+ *
8
+ * Keyed by chatId+threadId so concurrent turns in different chats don't
9
+ * collide. Designed to be fully standalone (no grammy/bot dependency) so
10
+ * it's testable with deterministic time injection via vi.useFakeTimers().
11
+ *
12
+ * Usage:
13
+ * signalTracker.reset(key, now) // at turn start
14
+ * signalTracker.noteSignal(key, now) // on every user-visible signal
15
+ * signalTracker.getLongestGap(key) // at turn_end
16
+ * signalTracker.clear(key) // after emitting (cleanup)
17
+ */
18
+
19
+ export interface TurnSignalState {
20
+ /** The time the current gap started (i.e., the last signal time). */
21
+ lastSignalAt: number
22
+ /** The longest gap observed so far (ms). */
23
+ longestGapMs: number
24
+ }
25
+
26
+ /**
27
+ * Module-scoped map: `"chatId:threadId"` → state. Using a module-level map
28
+ * keeps the tracker lightweight and avoids passing state through every
29
+ * call-site while remaining mockable in tests via the exported functions.
30
+ */
31
+ const state = new Map<string, TurnSignalState>()
32
+
33
+ /**
34
+ * Begin tracking a new turn. Records `now` as the initial signal time and
35
+ * resets the gap accumulator. Call at the start of each fresh turn.
36
+ */
37
+ export function reset(key: string, now: number): void {
38
+ state.set(key, { lastSignalAt: now, longestGapMs: 0 })
39
+ }
40
+
41
+ /**
42
+ * Record a user-visible signal. Measures the gap since the last signal and
43
+ * updates `longestGapMs` if this gap is larger.
44
+ */
45
+ export function noteSignal(key: string, now: number): void {
46
+ const entry = state.get(key)
47
+ if (entry == null) return
48
+ const gap = now - entry.lastSignalAt
49
+ if (gap > entry.longestGapMs) entry.longestGapMs = gap
50
+ entry.lastSignalAt = now
51
+ }
52
+
53
+ /**
54
+ * Returns the longest gap observed during the current turn (ms).
55
+ * Returns 0 if no tracking state exists for this key.
56
+ */
57
+ export function getLongestGap(key: string): number {
58
+ return state.get(key)?.longestGapMs ?? 0
59
+ }
60
+
61
+ /**
62
+ * Returns the last signal time for this key, or undefined if not tracked.
63
+ * Useful for computing a trailing gap at turn_end before calling clear().
64
+ */
65
+ export function getLastSignalAt(key: string): number | undefined {
66
+ return state.get(key)?.lastSignalAt
67
+ }
68
+
69
+ /**
70
+ * Remove state for this key. Call after emitting the turn_signal_gap metric.
71
+ */
72
+ export function clear(key: string): void {
73
+ state.delete(key)
74
+ }
75
+
76
+ /** Exposed for tests — clears all tracked state. */
77
+ export function __resetAllForTests(): void {
78
+ state.clear()
79
+ }