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,417 @@
1
+ /**
2
+ * Turn-tracking schema for the per-agent registry.
3
+ *
4
+ * Phase 0 of #250 (the SQLite event registry). This module ships only what
5
+ * subsequent stages of the simplify-restart plan need to detect "this turn
6
+ * was orphaned by a restart" — a minimal, strictly-subset design so later
7
+ * registry work can extend without breaking changes.
8
+ *
9
+ * The DB file lives at `<agentDir>/telegram/registry.db`. Storage is
10
+ * `bun:sqlite` (Bun's bundled SQLite, no extra dep), same as history.ts.
11
+ *
12
+ * Schema (one table):
13
+ *
14
+ * turns
15
+ * turn_key TEXT PK -- e.g. "8248703757:11"
16
+ * chat_id TEXT NOT NULL
17
+ * thread_id TEXT -- nullable: forum topics only
18
+ * started_at INTEGER NOT NULL -- unix ms
19
+ * ended_at INTEGER -- nullable until turn ends
20
+ * ended_via TEXT -- 'stop' | 'sigterm' | 'restart' | 'timeout' | 'unknown'
21
+ * last_assistant_msg_id TEXT -- last outbound message_id in this turn
22
+ * last_assistant_done INTEGER -- 0|1; 1 = stream_reply done=true sent
23
+ * last_user_msg_id TEXT -- inbound message_id that started the turn
24
+ * user_prompt_preview TEXT -- first ~200 chars of user message (Phase 1)
25
+ * assistant_reply_preview TEXT -- first ~200 chars of bot's terminal message (Phase 1)
26
+ * tool_call_count INTEGER -- count of tool_use events in the turn (Phase 1)
27
+ * created_at INTEGER NOT NULL
28
+ * updated_at INTEGER NOT NULL
29
+ *
30
+ * Boot-time usage:
31
+ * On every gateway boot, call `markOrphanedAsRestarted(db)` immediately
32
+ * after opening the DB. Any turn with `ended_at IS NULL` was killed
33
+ * mid-flight (SIGKILL, OOM, power loss) — it never got a chance to write
34
+ * a clean-shutdown marker. Stage 3 of simplify-restart will wire this up
35
+ * from the gateway entry point.
36
+ */
37
+
38
+ import { chmodSync, mkdirSync } from 'fs'
39
+ import { join } from 'path'
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // bun:sqlite lazy-loader (same pattern as history.ts)
43
+ // ---------------------------------------------------------------------------
44
+
45
+ /**
46
+ * `bun:sqlite` is a Bun built-in — Vite/Node loaders can't resolve it
47
+ * statically, which would crash any vitest test that transitively imports
48
+ * this module. Hide the require behind `import.meta.require` so static
49
+ * analysis passes; runtime resolution is per-Bun and works fine.
50
+ */
51
+ type SqliteDatabase = {
52
+ exec(sql: string): void
53
+ prepare(sql: string): {
54
+ run(...params: unknown[]): unknown
55
+ all(...params: unknown[]): unknown[]
56
+ get(...params: unknown[]): unknown
57
+ }
58
+ transaction(fn: (...args: unknown[]) => unknown): (...args: unknown[]) => unknown
59
+ close(): void
60
+ }
61
+ type SqliteDatabaseConstructor = new (path: string, opts?: { create?: boolean }) => SqliteDatabase
62
+
63
+ let DatabaseClass: SqliteDatabaseConstructor | null = null
64
+ function loadDatabaseClass(): SqliteDatabaseConstructor {
65
+ if (DatabaseClass != null) return DatabaseClass
66
+ try {
67
+ const metaRequire = (import.meta as { require?: (id: string) => unknown }).require
68
+ if (typeof metaRequire !== 'function') {
69
+ throw new Error('import.meta.require not available — Bun runtime required')
70
+ }
71
+ const mod = metaRequire('bun:sqlite') as { Database?: SqliteDatabaseConstructor }
72
+ if (!mod.Database) throw new Error('bun:sqlite did not export Database')
73
+ DatabaseClass = mod.Database
74
+ return DatabaseClass
75
+ } catch (err) {
76
+ throw new Error(
77
+ `turns-schema.ts requires Bun runtime (bun:sqlite). Caller: ${(err as Error).message}`,
78
+ )
79
+ }
80
+ }
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // Types
84
+ // ---------------------------------------------------------------------------
85
+
86
+ export type TurnEndedVia = 'stop' | 'sigterm' | 'restart' | 'timeout' | 'unknown'
87
+
88
+ export interface Turn {
89
+ turn_key: string
90
+ chat_id: string
91
+ thread_id: string | null
92
+ started_at: number
93
+ ended_at: number | null
94
+ ended_via: TurnEndedVia | null
95
+ last_assistant_msg_id: string | null
96
+ last_assistant_done: boolean | null
97
+ last_user_msg_id: string | null
98
+ user_prompt_preview: string | null
99
+ assistant_reply_preview: string | null
100
+ tool_call_count: number | null
101
+ created_at: number
102
+ updated_at: number
103
+ }
104
+
105
+ export interface RecordTurnStartArgs {
106
+ turnKey: string
107
+ chatId: string
108
+ threadId?: string | null
109
+ lastUserMsgId?: string | null
110
+ userPromptPreview?: string | null
111
+ }
112
+
113
+ export interface RecordTurnEndArgs {
114
+ turnKey: string
115
+ endedVia: TurnEndedVia
116
+ lastAssistantMsgId?: string | null
117
+ lastAssistantDone?: boolean
118
+ assistantReplyPreview?: string | null
119
+ toolCallCount?: number
120
+ }
121
+
122
+ // ---------------------------------------------------------------------------
123
+ // Schema
124
+ // ---------------------------------------------------------------------------
125
+
126
+ const SCHEMA_SQL = `
127
+ CREATE TABLE IF NOT EXISTS turns (
128
+ turn_key TEXT PRIMARY KEY,
129
+ chat_id TEXT NOT NULL,
130
+ thread_id TEXT,
131
+ started_at INTEGER NOT NULL,
132
+ ended_at INTEGER,
133
+ ended_via TEXT,
134
+ last_assistant_msg_id TEXT,
135
+ last_assistant_done INTEGER,
136
+ last_user_msg_id TEXT,
137
+ user_prompt_preview TEXT,
138
+ assistant_reply_preview TEXT,
139
+ tool_call_count INTEGER,
140
+ created_at INTEGER NOT NULL,
141
+ updated_at INTEGER NOT NULL
142
+ );
143
+ CREATE INDEX IF NOT EXISTS idx_turns_chat_ended ON turns(chat_id, ended_at);
144
+ `
145
+
146
+ // Columns added in Phase 1 of #332. Applied via ALTER TABLE so existing
147
+ // registry.db files on disk are migrated non-destructively on first open.
148
+ const PHASE1_MIGRATIONS = [
149
+ `ALTER TABLE turns ADD COLUMN user_prompt_preview TEXT`,
150
+ `ALTER TABLE turns ADD COLUMN assistant_reply_preview TEXT`,
151
+ `ALTER TABLE turns ADD COLUMN tool_call_count INTEGER`,
152
+ ]
153
+
154
+ function applySchema(db: SqliteDatabase): void {
155
+ db.exec('PRAGMA journal_mode = WAL')
156
+ db.exec('PRAGMA synchronous = NORMAL')
157
+ db.exec(SCHEMA_SQL)
158
+ // Run migrations for Phase 1 columns. SQLite doesn't support
159
+ // "ADD COLUMN IF NOT EXISTS", so we swallow the "duplicate column" error.
160
+ for (const sql of PHASE1_MIGRATIONS) {
161
+ try {
162
+ db.exec(sql)
163
+ } catch (err) {
164
+ const msg = (err as Error).message ?? ''
165
+ if (!msg.includes('duplicate column')) throw err
166
+ }
167
+ }
168
+ }
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // openTurnsDb
172
+ // ---------------------------------------------------------------------------
173
+
174
+ /**
175
+ * Open (or create) the per-agent registry DB at
176
+ * `<agentDir>/telegram/registry.db`.
177
+ *
178
+ * Returns the raw Database instance — callers hold it and pass it to the
179
+ * helpers below. This is intentionally NOT a singleton so tests can use
180
+ * in-memory or temp-file DBs without global state pollution.
181
+ *
182
+ * Callers that need a singleton can wrap this themselves. The gateway will
183
+ * hold one instance for the lifetime of the process (Stage 3).
184
+ */
185
+ export function openTurnsDb(agentDir: string): SqliteDatabase {
186
+ const Database = loadDatabaseClass()
187
+ const dir = join(agentDir, 'telegram')
188
+ mkdirSync(dir, { recursive: true, mode: 0o700 })
189
+ const path = join(dir, 'registry.db')
190
+ const db = new Database(path, { create: true })
191
+ applySchema(db)
192
+ try {
193
+ chmodSync(path, 0o600)
194
+ } catch {
195
+ /* ignore — chmod not supported on some FUSE mounts */
196
+ }
197
+ return db
198
+ }
199
+
200
+ /**
201
+ * Open an in-memory DB with the turns schema applied.
202
+ * Useful for tests without touching the filesystem.
203
+ */
204
+ export function openTurnsDbInMemory(): SqliteDatabase {
205
+ const Database = loadDatabaseClass()
206
+ const db = new Database(':memory:')
207
+ applySchema(db)
208
+ return db
209
+ }
210
+
211
+ // ---------------------------------------------------------------------------
212
+ // Row mapper
213
+ // ---------------------------------------------------------------------------
214
+
215
+ interface RawTurnRow {
216
+ turn_key: string
217
+ chat_id: string
218
+ thread_id: string | null
219
+ started_at: number
220
+ ended_at: number | null
221
+ ended_via: string | null
222
+ last_assistant_msg_id: string | null
223
+ last_assistant_done: number | null
224
+ last_user_msg_id: string | null
225
+ user_prompt_preview: string | null
226
+ assistant_reply_preview: string | null
227
+ tool_call_count: number | null
228
+ created_at: number
229
+ updated_at: number
230
+ }
231
+
232
+ function mapRow(row: RawTurnRow): Turn {
233
+ return {
234
+ turn_key: row.turn_key,
235
+ chat_id: row.chat_id,
236
+ thread_id: row.thread_id,
237
+ started_at: row.started_at,
238
+ ended_at: row.ended_at,
239
+ ended_via: (row.ended_via as TurnEndedVia | null) ?? null,
240
+ last_assistant_msg_id: row.last_assistant_msg_id,
241
+ last_assistant_done:
242
+ row.last_assistant_done === null ? null : row.last_assistant_done !== 0,
243
+ last_user_msg_id: row.last_user_msg_id,
244
+ user_prompt_preview: row.user_prompt_preview,
245
+ assistant_reply_preview: row.assistant_reply_preview,
246
+ tool_call_count: row.tool_call_count,
247
+ created_at: row.created_at,
248
+ updated_at: row.updated_at,
249
+ }
250
+ }
251
+
252
+ // ---------------------------------------------------------------------------
253
+ // Helpers
254
+ // ---------------------------------------------------------------------------
255
+
256
+ /**
257
+ * Record that a new turn has started. Inserts a row with `ended_at = NULL`.
258
+ * If a row with the same `turnKey` already exists it is left unchanged
259
+ * (INSERT OR IGNORE) — callers should generate unique keys.
260
+ */
261
+ export function recordTurnStart(db: SqliteDatabase, args: RecordTurnStartArgs): void {
262
+ const now = Date.now()
263
+ db.prepare(`
264
+ INSERT OR IGNORE INTO turns
265
+ (turn_key, chat_id, thread_id, started_at, last_user_msg_id,
266
+ user_prompt_preview, created_at, updated_at)
267
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
268
+ `).run(
269
+ args.turnKey,
270
+ args.chatId,
271
+ args.threadId ?? null,
272
+ now,
273
+ args.lastUserMsgId ?? null,
274
+ args.userPromptPreview ?? null,
275
+ now,
276
+ now,
277
+ )
278
+ }
279
+
280
+ /**
281
+ * Record that a turn has ended cleanly. Updates `ended_at`, `ended_via`,
282
+ * and optionally the last outbound message fields, reply preview, and
283
+ * tool-call count.
284
+ *
285
+ * No-ops gracefully if `turnKey` is not found (turn may have already been
286
+ * swept by `markOrphanedAsRestarted` on a prior boot).
287
+ */
288
+ export function recordTurnEnd(db: SqliteDatabase, args: RecordTurnEndArgs): void {
289
+ const now = Date.now()
290
+ db.prepare(`
291
+ UPDATE turns
292
+ SET
293
+ ended_at = ?,
294
+ ended_via = ?,
295
+ last_assistant_msg_id = COALESCE(?, last_assistant_msg_id),
296
+ last_assistant_done = COALESCE(?, last_assistant_done),
297
+ assistant_reply_preview = COALESCE(?, assistant_reply_preview),
298
+ tool_call_count = COALESCE(?, tool_call_count),
299
+ updated_at = ?
300
+ WHERE turn_key = ?
301
+ `).run(
302
+ now,
303
+ args.endedVia,
304
+ args.lastAssistantMsgId ?? null,
305
+ args.lastAssistantDone !== undefined ? (args.lastAssistantDone ? 1 : 0) : null,
306
+ args.assistantReplyPreview ?? null,
307
+ args.toolCallCount !== undefined ? args.toolCallCount : null,
308
+ now,
309
+ args.turnKey,
310
+ )
311
+ }
312
+
313
+ /**
314
+ * Return all turns for `chatId` where `ended_at IS NULL` — these are
315
+ * candidates for "killed mid-turn" (the gateway crashed before the turn
316
+ * completed and wrote its end record).
317
+ *
318
+ * Results are ordered by `started_at ASC` so callers can process
319
+ * oldest-first if they need to replay or report them.
320
+ */
321
+ export function findOrphanedTurns(db: SqliteDatabase, chatId: string): Turn[] {
322
+ const rows = db.prepare(`
323
+ SELECT * FROM turns
324
+ WHERE chat_id = ? AND ended_at IS NULL
325
+ ORDER BY started_at ASC
326
+ `).all(chatId) as RawTurnRow[]
327
+ return rows.map(mapRow)
328
+ }
329
+
330
+ /**
331
+ * Boot-time reaper. Sweeps ALL turns (across all chats) that have
332
+ * `ended_at IS NULL` and stamps them with `ended_via = 'restart'` and
333
+ * `ended_at = now()`.
334
+ *
335
+ * Call this once, immediately after `openTurnsDb`, before any new turns
336
+ * are recorded for the current boot. That way the current boot's turns
337
+ * are cleanly separable from orphans inherited from the prior process.
338
+ *
339
+ * Returns the number of rows updated.
340
+ */
341
+ export function markOrphanedAsRestarted(db: SqliteDatabase): number {
342
+ const now = Date.now()
343
+ const result = db.prepare(`
344
+ UPDATE turns
345
+ SET ended_at = ?,
346
+ ended_via = 'restart',
347
+ updated_at = ?
348
+ WHERE ended_at IS NULL
349
+ `).run(now, now) as { changes: number }
350
+ return result.changes
351
+ }
352
+
353
+ /**
354
+ * Return the most recent N turns for `chatId` (any state — running or ended),
355
+ * ordered by started_at DESC. Used by the idle-footer renderer to decide
356
+ * whether to render "working since" vs "idle · last reply".
357
+ *
358
+ * `limit` defaults to 1 because the renderer only inspects the top row, but
359
+ * callers can pass more if they need backfill.
360
+ */
361
+ export function findRecentTurnsForChat(
362
+ db: SqliteDatabase,
363
+ chatId: string,
364
+ limit = 1,
365
+ ): Turn[] {
366
+ const rows = db.prepare(`
367
+ SELECT * FROM turns
368
+ WHERE chat_id = ?
369
+ ORDER BY started_at DESC
370
+ LIMIT ?
371
+ `).all(chatId, limit) as RawTurnRow[]
372
+ return rows.map(mapRow)
373
+ }
374
+
375
+ /**
376
+ * Return the most recent N turns across all chats for an agent, ordered by
377
+ * started_at DESC. Intended for the REST API endpoint
378
+ * `GET /api/agents/:name/turns?limit=20`.
379
+ *
380
+ * `limit` defaults to 20, max 200.
381
+ */
382
+ export function listTurnsForAgent(
383
+ db: SqliteDatabase,
384
+ opts: { limit?: number } = {},
385
+ ): Turn[] {
386
+ const limit = Math.min(Math.max(1, opts.limit ?? 20), 200)
387
+ const rows = db.prepare(`
388
+ SELECT * FROM turns
389
+ ORDER BY started_at DESC
390
+ LIMIT ?
391
+ `).all(limit) as RawTurnRow[]
392
+ return rows.map(mapRow)
393
+ }
394
+
395
+ /**
396
+ * Find the single most-recently-started turn that ended via an interrupt
397
+ * (`'restart'` | `'sigterm'` | `'timeout'`) OR is still open
398
+ * (`ended_at IS NULL`). Used by Stage 4 to surface "you had pending work"
399
+ * to the agent on cold start.
400
+ *
401
+ * Returns null if no such turn exists (clean boot — last turn ended 'stop').
402
+ *
403
+ * Note on ordering: we use `started_at DESC` (not `updated_at`) so the
404
+ * boot-time reaper (which mass-stamps orphans with the SAME `ended_at` /
405
+ * `updated_at`) doesn't reorder them; the temporal "last turn" is what
406
+ * the user remembers, and that's `started_at`.
407
+ */
408
+ export function findMostRecentInterruptedTurn(db: SqliteDatabase): Turn | null {
409
+ const row = db.prepare(`
410
+ SELECT * FROM turns
411
+ WHERE ended_at IS NULL
412
+ OR ended_via IN ('restart', 'sigterm', 'timeout')
413
+ ORDER BY started_at DESC
414
+ LIMIT 1
415
+ `).get() as RawTurnRow | undefined
416
+ return row ? mapRow(row) : null
417
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Retry wrapper for Telegram Bot API calls — the single policy the rest
3
+ * of the plugin relies on for flood-wait handling, benign 400 swallowing,
4
+ * and thread-not-found fallback.
5
+ *
6
+ * Extracted from gateway.ts so that:
7
+ * - it's unit-testable (the previous in-gateway definition couldn't be
8
+ * exercised without spinning up the whole bot runner)
9
+ * - stream-reply-handler / server.ts can share one implementation
10
+ * instead of each threading a `retry` dep through every callsite
11
+ * - callers can install an observer (`onRetry`, `onGiveUp`) for tests
12
+ * and production logging without reaching into the function body.
13
+ *
14
+ * Behaviour contract — each case is independently tested in
15
+ * `tests/retry-api-call.test.ts`:
16
+ *
17
+ * | Thrown error | This wrapper does |
18
+ * |-----------------------------------------------|--------------------------------------------|
19
+ * | GrammyError 429 | sleep retry_after seconds, retry |
20
+ * | GrammyError 400 "message is not modified" | swallow, return undefined |
21
+ * | GrammyError 400 "message to edit not found" | swallow, return undefined |
22
+ * | GrammyError 400 "message to delete not found" | swallow, return undefined |
23
+ * | GrammyError 400 "thread not found" (w/ opts) | throw `THREAD_NOT_FOUND` wrapper |
24
+ * | Network error (fetch failed / ECONN…) | exponential backoff retry, 3 attempts |
25
+ * | Anything else | rethrow immediately |
26
+ */
27
+
28
+ import { GrammyError } from 'grammy'
29
+
30
+ export interface RetryCallOpts {
31
+ /**
32
+ * The forum-topic thread id, used only to decide whether the
33
+ * "thread not found" 400 is retryable for a fallback path. If both
34
+ * `threadId` and `chat_id` are set, a thread-not-found 400 is rethrown
35
+ * as `THREAD_NOT_FOUND` so callers can drop the thread and retry on
36
+ * the main chat.
37
+ */
38
+ threadId?: number
39
+ chat_id?: string
40
+ /**
41
+ * Optional caller-supplied label for the API call (e.g. "sendMessage",
42
+ * "editMessageText"). Currently informational only — accepted to allow
43
+ * call sites to self-document. Future: surface in retry logs / metrics.
44
+ */
45
+ verb?: string
46
+ }
47
+
48
+ export interface RetryObserver {
49
+ /** Fires just before sleeping for a retry. */
50
+ onRetry?(info: { attempt: number; reason: 'flood_wait' | 'network'; delayMs: number }): void
51
+ /** Fires when max retries is reached and the wrapper gives up. */
52
+ onGiveUp?(info: { attempts: number; error: unknown }): void
53
+ /** Fires for each benign error we swallowed (not-modified, not-found). */
54
+ onBenign?(info: { kind: 'not_modified' | 'message_not_found' | 'delete_not_found' }): void
55
+ }
56
+
57
+ export interface RetryApiCallConfig {
58
+ /** Max retries before giving up. Defaults to 3. */
59
+ maxRetries?: number
60
+ /** Sleep helper — injected so tests can use fake timers. */
61
+ sleep?: (ms: number) => Promise<void>
62
+ /** Optional observer hooks. */
63
+ observer?: RetryObserver
64
+ /** Optional log sink for flood-wait / network lines. */
65
+ log?: (line: string) => void
66
+ }
67
+
68
+ const DEFAULT_SLEEP = (ms: number) => new Promise<void>((r) => setTimeout(r, ms))
69
+
70
+ /**
71
+ * Wrap a Telegram API call with the standard retry policy.
72
+ *
73
+ * Returns `fn`'s resolved value on success. Returns `undefined` for the
74
+ * swallowed-400 cases (caller must tolerate this — the typical caller is
75
+ * a `bot.api.editMessageText` which returns `true` on success, so
76
+ * `undefined` cleanly flags "no-op, target gone or identical"). Throws
77
+ * on 3rd network-error attempt or on any non-retryable error.
78
+ */
79
+ export function createRetryApiCall(
80
+ config: RetryApiCallConfig = {},
81
+ ): <T>(fn: () => Promise<T>, opts?: RetryCallOpts) => Promise<T> {
82
+ const maxRetries = config.maxRetries ?? 3
83
+ const sleep = config.sleep ?? DEFAULT_SLEEP
84
+ const observer = config.observer
85
+ const log = config.log
86
+
87
+ return async function retryApiCall<T>(
88
+ fn: () => Promise<T>,
89
+ opts?: RetryCallOpts,
90
+ ): Promise<T> {
91
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
92
+ try {
93
+ return await fn()
94
+ } catch (err) {
95
+ const isGrammyErr = err instanceof GrammyError
96
+ const msg = err instanceof Error ? err.message : String(err)
97
+ const desc = isGrammyErr ? (err as GrammyError).description : msg
98
+
99
+ // Flood-wait — sleep retry_after and try again.
100
+ if (isGrammyErr && (err as GrammyError).error_code === 429) {
101
+ const retryAfter = Number(
102
+ (err as GrammyError).parameters?.retry_after ?? 5,
103
+ )
104
+ const delayMs = retryAfter * 1000
105
+ log?.(`telegram gateway: 429 rate limited, waiting ${retryAfter}s\n`)
106
+ observer?.onRetry?.({ attempt, reason: 'flood_wait', delayMs })
107
+ await sleep(delayMs)
108
+ continue
109
+ }
110
+
111
+ // Swallow "message is not modified" — Telegram's no-op-on-equal-text.
112
+ if (
113
+ isGrammyErr &&
114
+ (err as GrammyError).error_code === 400 &&
115
+ desc.includes('not modified')
116
+ ) {
117
+ observer?.onBenign?.({ kind: 'not_modified' })
118
+ return undefined as unknown as T
119
+ }
120
+
121
+ // Swallow "message to edit/delete not found" — target vanished.
122
+ if (
123
+ isGrammyErr &&
124
+ (err as GrammyError).error_code === 400 &&
125
+ (desc.includes('message to edit not found') ||
126
+ desc.includes('message to delete not found'))
127
+ ) {
128
+ observer?.onBenign?.({
129
+ kind: desc.includes('edit') ? 'message_not_found' : 'delete_not_found',
130
+ })
131
+ return undefined as unknown as T
132
+ }
133
+
134
+ // Stale forum-thread — caller may want to fall back to main chat.
135
+ if (
136
+ isGrammyErr &&
137
+ (err as GrammyError).error_code === 400 &&
138
+ desc.includes('thread not found') &&
139
+ opts?.threadId &&
140
+ opts?.chat_id
141
+ ) {
142
+ throw Object.assign(new Error('THREAD_NOT_FOUND'), { original: err })
143
+ }
144
+
145
+ // Network-level transient errors — exponential backoff, bounded.
146
+ if (
147
+ !isGrammyErr &&
148
+ (msg.includes('ECONNRESET') ||
149
+ msg.includes('ETIMEDOUT') ||
150
+ msg.includes('fetch failed') ||
151
+ msg.includes('ENOTFOUND'))
152
+ ) {
153
+ if (attempt < maxRetries - 1) {
154
+ const delayMs = Math.pow(2, attempt) * 1000
155
+ log?.(
156
+ `telegram gateway: network error, retrying in ${delayMs / 1000}s: ${msg}\n`,
157
+ )
158
+ observer?.onRetry?.({ attempt, reason: 'network', delayMs })
159
+ await sleep(delayMs)
160
+ continue
161
+ }
162
+ }
163
+
164
+ observer?.onGiveUp?.({ attempts: attempt + 1, error: err })
165
+ throw err
166
+ }
167
+ }
168
+ const giveUpErr = new Error('retryApiCall: max retries exceeded')
169
+ observer?.onGiveUp?.({ attempts: maxRetries, error: giveUpErr })
170
+ throw giveUpErr
171
+ }
172
+ }
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ // Build script for @switchroom-ai/telegram-plugin npm publish.
3
+ import { execSync } from "node:child_process";
4
+ import { readFileSync, writeFileSync, chmodSync, mkdirSync, rmSync } from "node:fs";
5
+ import { resolve, dirname } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { escapeBundleNonAscii } from "../../scripts/escape-bundle-non-ascii.mjs";
8
+
9
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
10
+ const outDir = resolve(root, "dist");
11
+
12
+ console.log("[build] cleaning dist/");
13
+ rmSync(outDir, { recursive: true, force: true });
14
+ mkdirSync(outDir, { recursive: true });
15
+
16
+ try {
17
+ execSync("bun --version", { stdio: "ignore" });
18
+ } catch {
19
+ console.error("[build] bun is required to build. Install from https://bun.sh");
20
+ process.exit(1);
21
+ }
22
+
23
+ const entries = [
24
+ { src: "server.ts", out: "server.js", label: "server (legacy + dual-mode shim)" },
25
+ { src: "gateway/gateway.ts", out: "gateway/gateway.js", label: "gateway (persistent service)" },
26
+ { src: "bridge/bridge.ts", out: "bridge/bridge.js", label: "bridge (MCP proxy)" },
27
+ { src: "foreman/foreman.ts", out: "foreman/foreman.js", label: "foreman (admin bot)" },
28
+ ];
29
+
30
+ for (const { src, out, label } of entries) {
31
+ const srcPath = resolve(root, src);
32
+ const outPath = resolve(outDir, out);
33
+ const outDirForEntry = dirname(outPath);
34
+ mkdirSync(outDirForEntry, { recursive: true });
35
+
36
+ console.log(`[build] bundling ${src} -> dist/${out}`);
37
+ // `--external node-fetch`: grammy depends on node-fetch@2 which is a
38
+ // CJS package using node's `http`/`stream` directly. When bundled with
39
+ // `--target node`, bun's bundler INLINES node-fetch as the fetch
40
+ // implementation. Under bun runtime that inlined node-fetch breaks
41
+ // grammy's API calls with a generic "Network request failed!" — the
42
+ // gateway boot then loops 8x retrying getMe and exits, rendering the
43
+ // entire fleet unresponsive (every reply path fails, agent thumbs-up
44
+ // works but no message lands).
45
+ //
46
+ // Externalizing node-fetch keeps the bundle target-node compatible
47
+ // for npm-i-g users on a node runtime (grammy declares node-fetch as
48
+ // a dep so it'll be present in node_modules) AND lets bun's native
49
+ // fetch shim take over when the bundle runs under bun (the actual
50
+ // production deployment via `systemd ExecStart=bun gateway.js`).
51
+ //
52
+ // Verified: the un-externalized bundle reproducibly fails under bun
53
+ // with "HttpError: Network request for 'getMe' failed!" within 1s of
54
+ // boot. The externalized bundle boots cleanly and polls successfully.
55
+ execSync(
56
+ `bun build ${JSON.stringify(srcPath)} --outdir ${JSON.stringify(outDirForEntry)} --target node --external node-fetch`,
57
+ { stdio: "inherit", cwd: root }
58
+ );
59
+
60
+ let content = readFileSync(outPath, "utf8");
61
+ if (content.startsWith("#!/usr/bin/env bun")) {
62
+ content = content.replace(/^#!\/usr\/bin\/env bun/, "#!/usr/bin/env node");
63
+ writeFileSync(outPath, content);
64
+ }
65
+ chmodSync(outPath, 0o755);
66
+
67
+ // Bun parser bug workaround — see scripts/escape-bundle-non-ascii.mjs.
68
+ // Required for the gateway bundle: without it, the boot card's `✅`
69
+ // and the inline `·` separator in the ack-line template literal get
70
+ // double-UTF-8 encoded on the wire (#642 follow-up; mojibake reported
71
+ // as `â LawGPT back up · v0.6.3`).
72
+ const escResult = escapeBundleNonAscii(outPath);
73
+ if (escResult.changed) {
74
+ console.log(`[build] ASCII-escaped ${escResult.nonAsciiCount} non-ASCII code units in dist/${out}`);
75
+ }
76
+ }
77
+
78
+ console.log("[build] done");