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
package/package.json ADDED
@@ -0,0 +1,95 @@
1
+ {
2
+ "name": "switchroom",
3
+ "version": "0.5.0",
4
+ "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys, no Docker.",
5
+ "type": "module",
6
+ "bin": {
7
+ "switchroom": "./dist/cli/switchroom.js"
8
+ },
9
+ "main": "./dist/cli/switchroom.js",
10
+ "files": [
11
+ "dist",
12
+ "profiles",
13
+ "skills",
14
+ "telegram-plugin",
15
+ "bin",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "dev": "bun bin/switchroom.ts",
21
+ "build": "node scripts/build.mjs",
22
+ "test": "vitest run && bun test telegram-plugin/tests/history.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/foreman-state.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/registry/api-registry.test.ts telegram-plugin/registry/turns-schema.test.ts telegram-plugin/tests/idle-footer-wiring.test.ts telegram-plugin/tests/subagent-tracker-hooks.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts",
23
+ "test:vitest": "vitest run",
24
+ "test:bun": "bun test src/vault/grants.test.ts src/vault/broker/server-grants.test.ts src/vault/broker/client-token.test.ts src/vault/broker/server-unlock.test.ts src/vault/broker/auto-unlock.test.ts tests/vault-broker-passphrase.test.ts src/cli/vault-get-broker.test.ts src/vault/resolver-via-broker.test.ts src/vault/broker/scope.test.ts src/vault/broker/server.test.ts telegram-plugin/tests/boot-probes.test.ts telegram-plugin/tests/setup-state.test.ts telegram-plugin/tests/history.test.ts telegram-plugin/tests/ipc-server-client.test.ts telegram-plugin/tests/ipc-server-race.test.ts telegram-plugin/tests/gateway-bridge.test.ts telegram-plugin/tests/gateway-startup-mutex.test.ts telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts telegram-plugin/tests/foreman-state.test.ts telegram-plugin/tests/boot-card-dedupe.test.ts telegram-plugin/tests/boot-card-reason.test.ts telegram-plugin/tests/progress-update.test.ts telegram-plugin/tests/quota-cache.test.ts telegram-plugin/tests/silent-reply-guard.test.ts telegram-plugin/tests/unhandled-rejection-policy.test.ts telegram-plugin/tests/registry-turns.test.ts telegram-plugin/registry/subagents.test.ts telegram-plugin/tests/turns-writer.test.ts telegram-plugin/tests/resolve-calling-subagent.test.ts telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts",
25
+ "test:watch": "vitest",
26
+ "lint": "tsc --noEmit && node scripts/check-plugin-references.mjs",
27
+ "lint:tsc": "tsc --noEmit",
28
+ "lint:plugin-references": "node scripts/check-plugin-references.mjs",
29
+ "prepublishOnly": "npm run build && npm run lint && npm test"
30
+ },
31
+ "dependencies": {
32
+ "@grammyjs/runner": "^2.0.3",
33
+ "@modelcontextprotocol/sdk": "^1.0.0",
34
+ "@secretlint/core": "^12.2.0",
35
+ "@secretlint/secretlint-rule-preset-recommend": "^12.2.0",
36
+ "@secretlint/types": "^12.2.0",
37
+ "@xterm/headless": "^6.0.0",
38
+ "bcryptjs": "^3.0.3",
39
+ "chalk": "^5.4.0",
40
+ "commander": "^13.1.0",
41
+ "grammy": "^1.21.0",
42
+ "handlebars": "^4.7.8",
43
+ "posthog-node": "^5.29.2",
44
+ "yaml": "^2.7.0",
45
+ "zod": "^3.24.0"
46
+ },
47
+ "devDependencies": {
48
+ "@changesets/cli": "^2.30.0",
49
+ "@types/bun": "^1.3.11",
50
+ "@types/node": "^22.0.0",
51
+ "@vitest/coverage-v8": "3.2.4",
52
+ "buildkite-test-collector": "^1.9.5",
53
+ "typescript": "^5.7.0",
54
+ "vitest": "^3.2.4"
55
+ },
56
+ "engines": {
57
+ "node": ">=20.11.0"
58
+ },
59
+ "license": "MIT",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/switchroom/switchroom.git"
63
+ },
64
+ "homepage": "https://github.com/switchroom/switchroom#readme",
65
+ "bugs": {
66
+ "url": "https://github.com/switchroom/switchroom/issues"
67
+ },
68
+ "publishConfig": {
69
+ "access": "public"
70
+ },
71
+ "workspaces": [
72
+ "telegram-plugin"
73
+ ],
74
+ "keywords": [
75
+ "claude-code",
76
+ "claude-pro",
77
+ "claude-max",
78
+ "claude-subscription",
79
+ "anthropic",
80
+ "openclaw-alternative",
81
+ "nanoclaw-alternative",
82
+ "opencode-alternative",
83
+ "multi-agent",
84
+ "telegram",
85
+ "telegram-bot",
86
+ "orchestrator",
87
+ "ai-agent",
88
+ "self-hosted",
89
+ "oauth",
90
+ "24-7"
91
+ ],
92
+ "optionalDependencies": {
93
+ "@rollup/rollup-win32-x64-msvc": "^4.60.1"
94
+ }
95
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "permissions": {
3
+ "allow": {{{json permissionAllow}}},
4
+ "deny": {{{json toolsDeny}}}{{#if defaultModeAcceptEdits}},
5
+ "defaultMode": "acceptEdits"{{/if}}
6
+ },
7
+ "enabledPlugins": {
8
+ "telegram@claude-plugins-official": {{#if useSwitchroomPlugin}}false{{else}}true{{/if}}
9
+ }{{#if hindsightEnabled}},
10
+ "autoMemoryEnabled": false{{/if}}{{#if mcpServers}},
11
+ "mcpServers": {{{json mcpServers}}}
12
+ {{/if}}{{#if skipPermissionPrompt}},
13
+ "skipDangerousModePermissionPrompt": true
14
+ {{/if}}
15
+ }
@@ -0,0 +1,383 @@
1
+ #!/bin/bash
2
+ export NVM_DIR="$HOME/.nvm"
3
+ [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
4
+ export PATH="$HOME/.bun/bin:$PATH"
5
+ export CLAUDE_CONFIG_DIR="{{agentDir}}/.claude"
6
+ unset CLAUDE_CODE_OAUTH_TOKEN
7
+ if [ -f "$CLAUDE_CONFIG_DIR/.oauth-token" ]; then
8
+ export CLAUDE_CODE_OAUTH_TOKEN="$(tr -d '\r\n' < "$CLAUDE_CONFIG_DIR/.oauth-token")"
9
+ fi
10
+ export TELEGRAM_STATE_DIR="{{agentDir}}/telegram"
11
+ # SWITCHROOM_AGENT_NAME is the canonical "which agent am I" identifier the
12
+ # telegram-plugin reads to detect self-restart commands. We can't rely on
13
+ # basename(process.cwd()) inside the plugin because Claude Code spawns
14
+ # MCP servers with cwd = $HOME regardless of the parent's cwd.
15
+ export SWITCHROOM_AGENT_NAME="{{name}}"
16
+ {{#if switchroomConfigPathQ}}
17
+ # SWITCHROOM_CONFIG lets the agent's own shell tool invoke `switchroom`
18
+ # without passing `--config` every time. The telegram-plugin MCP server
19
+ # already gets this via .mcp.json env, but the Claude Code process
20
+ # doesn't inherit that — so without this export, `switchroom auth status`
21
+ # from Bash inside the agent fails with "No switchroom.yaml found".
22
+ export SWITCHROOM_CONFIG={{{switchroomConfigPathQ}}}
23
+ {{/if}}
24
+ {{#if hindsightEnabled}}
25
+ # Hindsight memory plugin (vendored at .claude/plugins/hindsight-memory/).
26
+ # Reads env vars at hook startup; settings.json autoMemoryEnabled: false
27
+ # disables Claude Code's built-in file-based auto-memory so we don't run
28
+ # two memory systems against each other.
29
+ # Values are POSIX-single-quoted in scaffold.ts for shell safety.
30
+ export HINDSIGHT_API_URL={{{hindsightApiBaseUrlQ}}}
31
+ export HINDSIGHT_BANK_ID={{{hindsightBankIdQ}}}
32
+ export HINDSIGHT_AUTO_RECALL=true
33
+ export HINDSIGHT_AUTO_RETAIN=true
34
+ export HINDSIGHT_AGENT_NAME="{{name}}"
35
+ {{#if (isNumber hindsightRecallMaxMemories)}}
36
+ # Cap on memories injected per turn (memory.recall.max_memories cascade).
37
+ # Plugin's settings.json default is 12; export only when the operator
38
+ # overrode it via switchroom.yaml. 0 disables the cap entirely.
39
+ export HINDSIGHT_RECALL_MAX_MEMORIES={{hindsightRecallMaxMemories}}
40
+ {{/if}}
41
+ # Per-session recall cache (#424 phase 4.1). Identical (prompt, bank)
42
+ # within a session reuses the prior recall result instead of round-
43
+ # tripping to Hindsight. Defaults to 600s (10 min); operators can
44
+ # override via memory.recall.cache_ttl_secs in switchroom.yaml.
45
+ # Setting it to 0 disables caching for that agent.
46
+ {{#if (isNumber hindsightRecallCacheTtlSecs)}}
47
+ export HINDSIGHT_RECALL_CACHE_TTL_SECS={{hindsightRecallCacheTtlSecs}}
48
+ {{else}}
49
+ export HINDSIGHT_RECALL_CACHE_TTL_SECS=600
50
+ {{/if}}
51
+ # Lexical-overlap relevance gate (#475). Drops memories whose Jaccard
52
+ # overlap with the user's query is below this threshold (range 0.0–1.0).
53
+ # Plugin default is 0.0 (gate disabled); export only when the operator
54
+ # overrode it via memory.recall.min_overlap in switchroom.yaml. Try
55
+ # 0.10–0.20 to start; observe `overlap_dropped` via
56
+ # `switchroom memory recall-log <agent>`.
57
+ {{#if (isNumber hindsightRecallMinOverlap)}}
58
+ export HINDSIGHT_RECALL_MIN_OVERLAP={{hindsightRecallMinOverlap}}
59
+ {{/if}}
60
+ # Wait for Hindsight API to be reachable before launching Claude, otherwise
61
+ # the MCP server connection fails at startup with "1 MCP server failed".
62
+ HINDSIGHT_WAIT=0
63
+ while [ $HINDSIGHT_WAIT -lt 30 ]; do
64
+ if curl -sf -o /dev/null --max-time 2 {{{hindsightApiBaseUrlQ}}}/mcp/; then
65
+ break
66
+ fi
67
+ sleep 1
68
+ HINDSIGHT_WAIT=$((HINDSIGHT_WAIT + 1))
69
+ done
70
+ {{/if}}
71
+ {{#if userEnvQuoted}}
72
+ # User-declared env vars from switchroom.yaml (agent + defaults merged).
73
+ # Values are POSIX-single-quoted in scaffold.ts so arbitrary bytes
74
+ # (including &, $, backtick, newline, embedded quotes) survive shell
75
+ # parsing. Triple braces skip Handlebars HTML-escape of the quoted form.
76
+ {{#each userEnvQuoted}}export {{@key}}={{{this}}}
77
+ {{/each}}
78
+ {{/if}}
79
+ cd "{{agentDir}}"
80
+
81
+ # Portable stat wrappers. Switchroom runs on Linux in production (GNU stat)
82
+ # but developers sometimes run `switchroom agent start` ad-hoc on macOS
83
+ # (BSD stat). Detect once and route through helpers.
84
+ if stat -c %s "$0" >/dev/null 2>&1; then
85
+ _stat_size() { stat -c %s "$1" 2>/dev/null || echo 0; }
86
+ _stat_mtime() { stat -c %Y "$1" 2>/dev/null || echo 0; }
87
+ else
88
+ _stat_size() { stat -f %z "$1" 2>/dev/null || echo 0; }
89
+ _stat_mtime() { stat -f %m "$1" 2>/dev/null || echo 0; }
90
+ fi
91
+
92
+ # Portable most-recent JSONL transcript lookup. `find -printf` is a GNU
93
+ # extension (unsupported on BSD/macOS), and unquoted globs like
94
+ # `ls -t *.jsonl` fall through when empty. Instead, iterate `find`
95
+ # output and use the portable _stat_mtime helper above to order by mtime.
96
+ # Each switchroom agent pins CLAUDE_CONFIG_DIR={{agentDir}}/.claude and
97
+ # cwd={{agentDir}}, so there's one project dir per agent in practice —
98
+ # the newest-across-project-dirs match is what `--continue` will resume.
99
+ _find_latest_jsonl() {
100
+ local dir="$1"
101
+ [ -d "$dir" ] || return 0
102
+ find "$dir" -type f -name '*.jsonl' 2>/dev/null | while IFS= read -r f; do
103
+ printf '%s %s\n' "$(_stat_mtime "$f")" "$f"
104
+ done | sort -nr | head -1 | cut -d' ' -f2-
105
+ }
106
+
107
+ # Session resume policy. The mode is set at scaffold time from
108
+ # session_continuity.resume_mode (default 'handoff' as of #362). Effective
109
+ # behaviors:
110
+ #
111
+ # handoff (default): never pass --continue. Claude starts fresh every
112
+ # restart and reads a briefing assembled from recent Telegram messages,
113
+ # Hindsight recall, and today's daily memory file. Prevents stale MCP
114
+ # servers / settings from being carried over across restarts.
115
+ # auto: if the latest JSONL transcript under
116
+ # $CLAUDE_CONFIG_DIR/projects/ is smaller than
117
+ # SWITCHROOM_RESUME_MAX_BYTES and newer than 7 days, pass
118
+ # --continue. Otherwise start fresh and let the handoff briefing
119
+ # inject a summary.
120
+ # continue: always pass --continue. Flaky for large transcripts;
121
+ # use only if you know your sessions stay small.
122
+ # none: never resume. Start completely fresh every launch, no briefing.
123
+ #
124
+ # In every mode, Hindsight auto-recall still surfaces long-term memories
125
+ # on each UserPromptSubmit so recent context isn't lost.
126
+ SWITCHROOM_RESUME_MODE="{{#if resumeMode}}{{{resumeMode}}}{{else}}handoff{{/if}}"
127
+ SWITCHROOM_RESUME_MAX_BYTES="{{#if resumeMaxBytes}}{{{resumeMaxBytes}}}{{else}}2000000{{/if}}"
128
+ {{#if sessionMaxIdleSecs}}# When session.max_idle is configured, auto-mode resume uses it as the
129
+ # freshness window instead of the 7-day default. Lets chat-cadence
130
+ # agents (e.g. health-coach) demand a fresher session — see #218.
131
+ SWITCHROOM_SESSION_MAX_IDLE_SECS="{{{sessionMaxIdleSecs}}}"
132
+ {{/if}}CONTINUE_FLAG=""
133
+
134
+ {{#if resumeModeHasContinuePath}}_RESUME_LATEST_JSONL="$(_find_latest_jsonl "$CLAUDE_CONFIG_DIR/projects")"
135
+ case "$SWITCHROOM_RESUME_MODE" in
136
+ continue)
137
+ if [ -n "$_RESUME_LATEST_JSONL" ]; then
138
+ CONTINUE_FLAG="--continue"
139
+ fi
140
+ ;;
141
+ auto)
142
+ if [ -n "$_RESUME_LATEST_JSONL" ]; then
143
+ _RESUME_SIZE="$(_stat_size "$_RESUME_LATEST_JSONL")"
144
+ _RESUME_MTIME="$(_stat_mtime "$_RESUME_LATEST_JSONL")"
145
+ _RESUME_AGE=$(( $(date +%s) - _RESUME_MTIME ))
146
+ _RESUME_MAX_AGE="${SWITCHROOM_SESSION_MAX_IDLE_SECS:-604800}"
147
+ if [ "$_RESUME_SIZE" -gt 0 ] && [ "$_RESUME_SIZE" -lt "$SWITCHROOM_RESUME_MAX_BYTES" ] && [ "$_RESUME_AGE" -lt "$_RESUME_MAX_AGE" ]; then
148
+ CONTINUE_FLAG="--continue"
149
+ fi
150
+ fi
151
+ ;;
152
+ handoff|none)
153
+ : # CONTINUE_FLAG stays empty
154
+ ;;
155
+ *)
156
+ : # Unknown mode, stay empty
157
+ ;;
158
+ esac
159
+ {{/if}}
160
+
161
+ # --- /reset and /new override: force fresh session ---
162
+ #
163
+ # When the user runs /reset or /new in Telegram the gateway writes a
164
+ # marker file here to signal "this boot must start a fresh Claude session
165
+ # even if --continue would otherwise resume." Without this, auto-resume
166
+ # picks up the just-closed JSONL and the SessionStart hook never fires,
167
+ # which means no session-greeting panel and no feeling of "fresh start"
168
+ # from the user side. Consume the marker so it only applies to one boot.
169
+ _FORCE_FRESH=0
170
+ if [ -f "{{agentDir}}/.force-fresh-session" ]; then
171
+ CONTINUE_FLAG=""
172
+ rm -f "{{agentDir}}/.force-fresh-session"
173
+ _FORCE_FRESH=1
174
+ fi
175
+
176
+ # --- Session-mode signal for the session-greeting panel ---
177
+ #
178
+ # Tells the SessionStart hook (session-greeting.sh) what kind of session
179
+ # this is so it can render an appropriate "Session" row in the panel:
180
+ # continue — resumed an in-flight JSONL via --continue (tool state kept)
181
+ # handoff — fresh claude session BUT a prior handoff briefing exists
182
+ # fresh — fresh by /reset or /new (force-fresh marker consumed)
183
+ # cold — first boot or no prior state at all
184
+ # Epoch of most recent prior session (from JSONL mtime) is exported too so
185
+ # the greeting can show a "2h ago" time-ago hint.
186
+ if [ "$_FORCE_FRESH" = "1" ]; then
187
+ SWITCHROOM_SESSION_MODE="fresh"
188
+ elif [ -n "$CONTINUE_FLAG" ]; then
189
+ SWITCHROOM_SESSION_MODE="continue"
190
+ elif [ -s "{{agentDir}}/.handoff.md" ]; then
191
+ SWITCHROOM_SESSION_MODE="handoff"
192
+ else
193
+ SWITCHROOM_SESSION_MODE="cold"
194
+ fi
195
+ export SWITCHROOM_SESSION_MODE
196
+
197
+ SWITCHROOM_PRIOR_SESSION_EPOCH=""
198
+ if [ -n "$_RESUME_LATEST_JSONL" ]; then
199
+ SWITCHROOM_PRIOR_SESSION_EPOCH="$(_stat_mtime "$_RESUME_LATEST_JSONL")"
200
+ fi
201
+ export SWITCHROOM_PRIOR_SESSION_EPOCH
202
+
203
+ # --- Pending-turn signal (Stage 4 of simplify-restart, see #250) ---
204
+ #
205
+ # The gateway writes <agentDir>/.pending-turn.env on boot if the previous
206
+ # shutdown left an interrupted turn (ended_via='restart' / 'sigterm' /
207
+ # 'timeout' or never closed at all). Source it here so the agent process
208
+ # inherits SWITCHROOM_PENDING_TURN=true plus chat/thread/last-user-msg
209
+ # context. The agent's resume protocol (per-agent CLAUDE.md) reads these
210
+ # and decides whether to ack the interruption + ask for direction or
211
+ # silently continue.
212
+ #
213
+ # Consume the file (rm) so it only applies to ONE boot — multi-restart
214
+ # scenarios shouldn't re-fire the resume prompt repeatedly.
215
+ SWITCHROOM_PENDING_TURN_ENV="{{agentDir}}/.pending-turn.env"
216
+ if [ -f "$SWITCHROOM_PENDING_TURN_ENV" ]; then
217
+ # shellcheck disable=SC1090
218
+ . "$SWITCHROOM_PENDING_TURN_ENV"
219
+ rm -f "$SWITCHROOM_PENDING_TURN_ENV"
220
+ export SWITCHROOM_PENDING_TURN \
221
+ SWITCHROOM_PENDING_TURN_KEY \
222
+ SWITCHROOM_PENDING_CHAT_ID \
223
+ SWITCHROOM_PENDING_THREAD_ID \
224
+ SWITCHROOM_PENDING_USER_MSG_ID \
225
+ SWITCHROOM_PENDING_ENDED_VIA \
226
+ SWITCHROOM_PENDING_STARTED_AT
227
+ fi
228
+
229
+ # --- Wake audit sentinel ---
230
+ #
231
+ # Every boot drops a `.wake-audit-pending` sentinel into the telegram
232
+ # state dir. The agent's CLAUDE.md (`telegram-style.md.hbs` "Wake
233
+ # audit" section) instructs it to detect this file at the start of
234
+ # its first turn after boot, run a three-signal check (owed reply /
235
+ # orphan sub-agents / open todos), surface findings to the user, and
236
+ # `rm -f` the file. This complements the SWITCHROOM_PENDING_TURN env
237
+ # (which only fires when a turn was in flight at SIGTERM) by also
238
+ # catching: long silent restarts after a "I'll come back to you"
239
+ # promise, sub-agent jobs killed by the watchdog, dropped stop-hook
240
+ # state, and any user message that landed while the gateway was down.
241
+ #
242
+ # Sentinel-file approach (rather than env var) keeps the signal
243
+ # durable across the entire process lifetime: even if the agent
244
+ # defers the audit by N turns, the file remains until handled.
245
+ #
246
+ # We unconditionally re-write the sentinel on every boot — including
247
+ # `--continue` respawns from watchdog/bridge restarts. Conversation-
248
+ # level dedup (so the agent doesn't re-fire the same "owed reply"
249
+ # audit twice on the same user message after a respawn) lives in the
250
+ # agent's audit logic via `.wake-audit-last-completed`, not here. See
251
+ # the "Conversation-aware dedup" block in telegram-style.md.hbs.
252
+ mkdir -p "$TELEGRAM_STATE_DIR" 2>/dev/null || true
253
+ : > "$TELEGRAM_STATE_DIR/.wake-audit-pending" 2>/dev/null || true
254
+
255
+ {{#if handoffEnabled}}
256
+ # --- Session handoff briefing ---
257
+ # On a normal shutdown the Stop hook writes .handoff.md (compact
258
+ # summary of the prior session) into the agent dir. Here we merge that
259
+ # briefing into --append-system-prompt so the fresh session wakes up
260
+ # already knowing what was going on. If the prior session crashed
261
+ # without firing the Stop hook, we fall back to a synchronous
262
+ # summarization capped at 2s — if that doesn't finish, skip gracefully
263
+ # and rely on Hindsight's per-turn auto-recall.
264
+ #
265
+ # In 'handoff' mode (the default as of #362), when no .handoff.md is
266
+ # available from the Stop hook, we also run handoff-briefing.sh which
267
+ # assembles a context briefing from recent Telegram messages, Hindsight
268
+ # recall, and today's daily memory file. This briefing is stored at
269
+ # .handoff-briefing.md and merged alongside (or instead of) .handoff.md.
270
+ HANDOFF_FILE="{{agentDir}}/.handoff.md"
271
+ HANDOFF_BRIEFING_FILE="{{agentDir}}/.handoff-briefing.md"
272
+ if [ ! -s "$HANDOFF_FILE" ]; then
273
+ _LATEST_JSONL=$(_find_latest_jsonl "$CLAUDE_CONFIG_DIR/projects")
274
+ if [ -n "$_LATEST_JSONL" ]; then
275
+ _LAST_MOD=$(_stat_mtime "$_LATEST_JSONL")
276
+ _NOW=$(date +%s)
277
+ if [ $((_NOW - _LAST_MOD)) -lt 600 ]; then
278
+ timeout 2 switchroom handoff "{{name}}" 2>/dev/null || true
279
+ fi
280
+ fi
281
+ # In handoff mode, run the briefing assembler as a fallback / supplement.
282
+ # It combines recent Telegram messages, Hindsight recall, and today's
283
+ # daily memory into a compact context brief. Requires python3 (stdlib
284
+ # sqlite3) for the Telegram history section; other sections only need
285
+ # curl + jq (both optional — each source degrades gracefully).
286
+ if [ "$SWITCHROOM_RESUME_MODE" = "handoff" ] && command -v handoff-briefing.sh >/dev/null 2>&1; then
287
+ export AGENT_DIR="{{agentDir}}"
288
+ timeout 5 handoff-briefing.sh 2>/dev/null || true
289
+ fi
290
+ fi
291
+ # Telegram plugin reads this to decide whether to prepend the visible
292
+ # "↩️ Picked up where we left off — <topic>" line on the first reply.
293
+ export SWITCHROOM_HANDOFF_SHOW_LINE={{#if handoffShowLine}}true{{else}}false{{/if}}
294
+ APPEND_PROMPT={{#if systemPromptAppendShellQuoted}}{{{systemPromptAppendShellQuoted}}}{{else}}""{{/if}}
295
+ # Inject .handoff-briefing.md first (assembled from live sources), then
296
+ # .handoff.md (LLM-generated session summary from Stop hook). If both
297
+ # exist, separate them with a divider so the agent sees both.
298
+ if [ -s "$HANDOFF_BRIEFING_FILE" ]; then
299
+ _BRIEFING_CONTENT=$(cat "$HANDOFF_BRIEFING_FILE")
300
+ if [ -n "$APPEND_PROMPT" ]; then
301
+ APPEND_PROMPT="$APPEND_PROMPT
302
+
303
+ ---
304
+
305
+ $_BRIEFING_CONTENT"
306
+ else
307
+ APPEND_PROMPT="$_BRIEFING_CONTENT"
308
+ fi
309
+ fi
310
+ if [ -s "$HANDOFF_FILE" ]; then
311
+ _HANDOFF_CONTENT=$(cat "$HANDOFF_FILE")
312
+ if [ -n "$APPEND_PROMPT" ]; then
313
+ APPEND_PROMPT="$APPEND_PROMPT
314
+
315
+ ---
316
+
317
+ $_HANDOFF_CONTENT"
318
+ else
319
+ APPEND_PROMPT="$_HANDOFF_CONTENT"
320
+ fi
321
+ fi
322
+ {{else}}
323
+ APPEND_PROMPT={{#if systemPromptAppendShellQuoted}}{{{systemPromptAppendShellQuoted}}}{{else}}""{{/if}}
324
+ {{/if}}
325
+
326
+ {{#unless useHotReloadStable}}
327
+ # --- Workspace bootstrap (stable) ---
328
+ # Inject AGENTS.md / SOUL.md / IDENTITY.md / USER.md / TOOLS.md /
329
+ # BOOTSTRAP.md from the agent's workspace/ dir into --append-system-prompt.
330
+ # These files are stable across a session, so baking them into the system
331
+ # prompt is cache-friendly. Dynamic files (MEMORY.md, today's daily,
332
+ # HEARTBEAT.md) are injected via the UserPromptSubmit hook, not here.
333
+ #
334
+ # When channels.telegram.hotReloadStable is true, this injection moves to
335
+ # a UserPromptSubmit hook instead (see workspace-stable-hook.sh).
336
+ #
337
+ # CACHE BOUNDARY ORDERING: The stable workspace render (_WS_STABLE) is
338
+ # prepended BEFORE the handoff briefing in APPEND_PROMPT. This ensures the
339
+ # prefix cache boundary is deterministic: stable parts (workspace + progress
340
+ # guidance) come first and cache hot across sessions, while per-session
341
+ # parts (handoff briefing) come after and only invalidate the cache at
342
+ # session boundaries. If we reversed the order, every new session would
343
+ # invalidate the entire prefix including the stable workspace content.
344
+ if [ -d "{{agentDir}}/workspace" ] && command -v switchroom >/dev/null 2>&1; then
345
+ _WS_STABLE=$(timeout 5 switchroom workspace render "{{name}}" --stable --warning-mode off 2>/dev/null || true)
346
+ if [ -n "$_WS_STABLE" ]; then
347
+ if [ -n "$APPEND_PROMPT" ]; then
348
+ APPEND_PROMPT="$_WS_STABLE
349
+
350
+ ---
351
+
352
+ $APPEND_PROMPT"
353
+ else
354
+ APPEND_PROMPT="$_WS_STABLE"
355
+ fi
356
+ fi
357
+ fi
358
+ {{/unless}}
359
+
360
+ # --- Boot self-test (#427) ---
361
+ # Pre-flights .credentials.json + claude-p auth in a hook-shaped env so
362
+ # any auth break shows up on the Telegram issues card (#428) the day
363
+ # it starts, not three weeks later. Async + best-effort: never blocks
364
+ # boot and never fails it.
365
+ {{#if repoRoot}}
366
+ if [ -x "{{repoRoot}}/bin/boot-self-test.sh" ]; then
367
+ ( "{{repoRoot}}/bin/boot-self-test.sh" >/dev/null 2>&1 ) &
368
+ fi
369
+ {{/if}}
370
+
371
+ {{#if useSwitchroomPlugin}}
372
+ if [ -n "$APPEND_PROMPT" ]; then
373
+ exec claude $CONTINUE_FLAG --dangerously-load-development-channels server:switchroom-telegram{{#if hindsightEnabled}} --plugin-dir "{{agentDir}}/.claude/plugins/hindsight-memory"{{/if}}{{#if modelQ}} --model {{{modelQ}}}{{/if}}{{#if thinkingEffort}} --effort {{thinkingEffort}}{{/if}}{{#if permissionMode}} --permission-mode {{permissionMode}}{{/if}}{{#if fallbackModelQ}} --fallback-model {{{fallbackModelQ}}}{{/if}} --append-system-prompt "$APPEND_PROMPT"{{#if dangerousMode}} --dangerously-skip-permissions{{/if}}{{#if extraCliArgs}}{{{extraCliArgs}}}{{/if}}
374
+ else
375
+ exec claude $CONTINUE_FLAG --dangerously-load-development-channels server:switchroom-telegram{{#if hindsightEnabled}} --plugin-dir "{{agentDir}}/.claude/plugins/hindsight-memory"{{/if}}{{#if modelQ}} --model {{{modelQ}}}{{/if}}{{#if thinkingEffort}} --effort {{thinkingEffort}}{{/if}}{{#if permissionMode}} --permission-mode {{permissionMode}}{{/if}}{{#if fallbackModelQ}} --fallback-model {{{fallbackModelQ}}}{{/if}}{{#if dangerousMode}} --dangerously-skip-permissions{{/if}}{{#if extraCliArgs}}{{{extraCliArgs}}}{{/if}}
376
+ fi
377
+ {{else}}
378
+ if [ -n "$APPEND_PROMPT" ]; then
379
+ exec claude $CONTINUE_FLAG --channels plugin:telegram@claude-plugins-official{{#if hindsightEnabled}} --plugin-dir "{{agentDir}}/.claude/plugins/hindsight-memory"{{/if}}{{#if modelQ}} --model {{{modelQ}}}{{/if}}{{#if thinkingEffort}} --effort {{thinkingEffort}}{{/if}}{{#if permissionMode}} --permission-mode {{permissionMode}}{{/if}}{{#if fallbackModelQ}} --fallback-model {{{fallbackModelQ}}}{{/if}} --append-system-prompt "$APPEND_PROMPT"{{#if dangerousMode}} --dangerously-skip-permissions{{/if}}{{#if extraCliArgs}}{{{extraCliArgs}}}{{/if}}
380
+ else
381
+ exec claude $CONTINUE_FLAG --channels plugin:telegram@claude-plugins-official{{#if hindsightEnabled}} --plugin-dir "{{agentDir}}/.claude/plugins/hindsight-memory"{{/if}}{{#if modelQ}} --model {{{modelQ}}}{{/if}}{{#if thinkingEffort}} --effort {{thinkingEffort}}{{/if}}{{#if permissionMode}} --permission-mode {{permissionMode}}{{/if}}{{#if fallbackModelQ}} --fallback-model {{{fallbackModelQ}}}{{/if}}{{#if dangerousMode}} --dangerously-skip-permissions{{/if}}{{#if extraCliArgs}}{{{extraCliArgs}}}{{/if}}
382
+ fi
383
+ {{/if}}
@@ -0,0 +1,140 @@
1
+ ## Telegram interaction style
2
+
3
+ You are talking to the user through Telegram. Telegram is a chat interface — your responses should feel like a chat, not a terminal dump.
4
+
5
+ **When to use `stream_reply` vs `reply`:**
6
+
7
+ Default to `stream_reply` for any response that requires tool calls before you can finalize the answer. This includes: reading files, running commands, calling any MCP tool, searching memory, or any multi-step reasoning where the user would otherwise see silence followed by a final blob. Streaming shows progress; `reply` alone feels dead until the final message arrives.
8
+
9
+ Pattern for `stream_reply`:
10
+
11
+ 1. **First call** (immediate, right after receiving the user's message): `stream_reply(chat_id, "Reading the file...", done=false)` — sends a fresh message. The user sees something within ~1 second of sending.
12
+ 2. **Interim calls** (after each tool result or meaningful step): `stream_reply(chat_id, "<full current text so far>", done=false)` — pass the FULL current text, not a delta. The plugin throttles edits to ~1/sec automatically.
13
+ 3. **Final call**: `stream_reply(chat_id, "<full final answer>", done=true)` — locks the message. This is the canonical reply for the turn.
14
+
15
+ Use `reply` **only** for instant one-shot answers that require zero tool calls — e.g., answering a pure factual question you already know, acknowledging a simple instruction, or a one-line clarification. If you are unsure which to pick, use `stream_reply`.
16
+
17
+ The status-reaction lifecycle (👀 → 🤔 → 🔥 → 👍) on the user's inbound message signals "working" automatically; you don't need to send a typing message.
18
+
19
+ **Follow-ups while a turn is in flight.** Claude Code's native FIFO queue means a follow-up Telegram message arrives AFTER your current turn ends, not during it — you can't interrupt your own turn. Every follow-up becomes the next prompt you see. The plugin enriches the `<channel>` meta so you can classify correctly:
20
+
21
+ - `steering="true"` — prior turn was in progress and the user did NOT use `/queue`. Treat as a course-correction or addendum on the next action. Continue the original task, incorporating the new guidance.
22
+ - `queued="true"` — the user typed `/queue ` or `/q ` (the prefix is stripped from the body you see). Treat as a new, independent task. Do NOT reference the in-flight work — start fresh.
23
+ - `prior_turn_in_progress="true"`, `seconds_since_turn_start="N"`, `prior_assistant_preview="..."` — auxiliary context on the prior turn so you can decide which of the above applies when ambiguous. `prior_assistant_preview` is the first ~200 chars of your most recent reply in this chat, HTML tags stripped.
24
+
25
+ If both `queued` and `steering` are somehow present, `queued` wins (explicit beats inferred). If `prior_turn_in_progress="true"` is set without either flag (shouldn't happen but defensive), treat the message as a follow-up related to your last reply.
26
+
27
+ **Self-narrate the classification.** At the top of your reply for any `steering` or `queued` message, include a brief italic one-liner so the user can correct you — e.g. `_↪️ treating as steer on the prior task_` or `_📥 queued as a new task_`.
28
+
29
+ **Formatting** (Telegram HTML — `reply` and `stream_reply` default to `format: "html"` and convert markdown for you):
30
+ - Use **bold** sparingly for emphasis on key facts only
31
+ - Use `inline code` for filenames, commands, identifiers
32
+ - Use ```fenced code blocks``` for multi-line code
33
+ - Lists are fine; nested lists are not (Telegram flattens them awkwardly)
34
+ - Don't use markdown headings (`##`) in replies — Telegram has no `<h1>` and they render as plain bold lines
35
+ - Keep lines short — long unwrapped lines are hard to read on mobile
36
+ - One idea per message when possible; the user can always ask for more
37
+
38
+ **Sound human, not AI.** Before you call `reply` or `stream_reply`, scan your draft for AI-writing tells — em-dash overuse, "powerful/compelling/significant" promotional adjectives, three-item lists for everything, "It's not just X, it's Y" rule-of-three constructions, hedging filler like "it's important to note that", excessive bolding for emphasis. The bundled `humanizer` skill catalogues 29 of these patterns; treat its rules as guidance you apply to every outbound message, not a tool you only invoke on long-form. For meaningful drafts (more than a couple of sentences), explicitly invoke `/humanizer` and run a humanize pass before sending. If the env var `HUMANIZER_VOICE_FILE` is set and readable, treat its content as the user's personal voice template — match length, tone, vocabulary, and formatting habits described there. If not set, the user can generate one any time with `/humanizer-calibrate`.
39
+
40
+ **Status accent headers** — `reply` and `stream_reply` both accept an optional `accent` parameter that prepends a status indicator line above the message body. Use it to communicate state without burying the signal in prose:
41
+
42
+ - `accent: 'in-progress'` — renders `🔵 In progress…` above the body. Use for interim updates during long-running work, replacing explicit "still working on X" preambles.
43
+ - `accent: 'done'` — renders `✅ Done` above the body. Use for completion announcements that mark a real milestone the user can act on.
44
+ - `accent: 'issue'` — renders `⚠️ Issue` above the body. Use when surfacing blockers, errors, or unresolved questions that need the user's attention.
45
+
46
+ Don't use `accent` on routine conversational replies — it's for status communication, not decoration. Omitting `accent` (the default) produces identical output to today's behavior.
47
+
48
+ **Resume protocol — interrupted turns.** When you boot, the start-up env may include `SWITCHROOM_PENDING_TURN=true`. That means the previous gateway died mid-turn (SIGTERM, restart, or a crash that bypassed the SIGTERM handler) and the user's last message was likely never fully answered. The accompanying env vars tell you what was in flight:
49
+
50
+ - `SWITCHROOM_PENDING_CHAT_ID` — the chat the interrupted turn belonged to
51
+ - `SWITCHROOM_PENDING_THREAD_ID` — the forum topic id (empty if not a forum)
52
+ - `SWITCHROOM_PENDING_USER_MSG_ID` — the inbound message_id that started the turn (you can quote-reply to it for context)
53
+ - `SWITCHROOM_PENDING_ENDED_VIA` — `restart` (user ran `switchroom agent restart`), `sigterm` (systemd/manual kill), `timeout` (watchdog), or `unknown` (crash before stamp)
54
+ - `SWITCHROOM_PENDING_STARTED_AT` — unix-ms when the turn started
55
+
56
+ **Your first action on a `SWITCHROOM_PENDING_TURN=true` boot must be to acknowledge the gap and confirm direction.** Don't silently pick up where you left off — the user has no way to know whether you remember what you were doing. Use `reply` with `accent: 'issue'` to make it obvious. Quote-reply to `SWITCHROOM_PENDING_USER_MSG_ID` so the original message is in view. Sample wording (adapt to the situation):
57
+
58
+ > ⚠️ Issue
59
+ >
60
+ > I was killed mid-turn — looks like my previous shutdown was via `<endedVia>`. Don't have full context on what I'd already done. Want me to: (a) start over from your last message, (b) summarize what I think was in flight and continue, or (c) drop it and move on?
61
+
62
+ The env vars are one-shot — start.sh deletes the file after sourcing. So this prompt only fires on the immediately-following session, not every restart afterward. If you genuinely don't remember anything useful about the prior turn (Hindsight didn't catch it, no handoff briefing landed), say so explicitly rather than guessing.
63
+
64
+ If `SWITCHROOM_PENDING_TURN` is unset or empty, do nothing special — the previous turn ended cleanly.
65
+
66
+ **Long replies → Telegraph Instant View.** When the operator has telegraph enabled (per-agent flag `telegraph.enabled`), replies above the configured threshold (default 3000 chars) get auto-published to a Telegraph article and the user sees a single Telegram message with a tappable link rendered as a native Instant View card — much cleaner read on mobile than a 4000-char wall-of-text chunked into three messages. You don't have to think about it: write the reply normally; the gateway decides whether to publish based on length alone. Two practical implications: (a) if the user asks "what was in that link?" they want the substance restated in chat, not "see the Telegraph"; (b) if telegraph is OFF and you write a 5000-char reply, it'll arrive as 2-3 chunked Telegram messages — that's fine but consider whether you actually need that much text.
67
+
68
+ **Voice messages.** When the operator has enabled voice transcription (per-agent flag `voice_in.enabled`), inbound Telegram voice messages reach you as plain text with a `[voice transcript]` prefix — e.g. `[voice transcript] yeah let's do option B and ping me when it's done`. Treat the prefix as informational only: it tells you the user spoke rather than typed, which sometimes matters for tone (more conversational, less precise) but doesn't change what to do. Do NOT echo the prefix back. If transcription was unavailable (key missing, API down) the user's message arrives as `(voice message)` with the audio attached as a file_id; in that case acknowledge that you couldn't transcribe and ask them to retype the key bits. Voice-in defaults off; if a user seems frustrated that you don't transcribe their voice memos, suggest they ask the operator to set it up.
69
+
70
+ **Stickers and GIFs — use sparingly, by persona.** You have `mcp__switchroom-telegram__send_sticker` and `mcp__switchroom-telegram__send_gif` available. Treat them as emotional punctuation, not vocabulary. The right rate is _maybe_ once per several conversations for assistant / health-coach / personal personas; effectively never for coding / lawyer / executive personas where warmth would feel off.
71
+
72
+ **When stickers / GIFs land well**: confirming a real milestone the user celebrated (✅ workout logged, 🎉 deal closed); softening genuinely awkward news; mirroring back a sticker or GIF the user just sent — once, not as a habit. Use the user's emoji-sticker (echo back the file_id from inbound `(sticker — 😊 from "PackName")`) to acknowledge their tone. The agent persona's own curated aliases — declared by the operator under `telegram.stickers` in switchroom.yaml — are the standard alphabet (`happy`, `thinking`, `done`, etc.); call `send_sticker(chat_id, sticker='happy')`. Errors list available aliases when an unknown one is asked for.
73
+
74
+ **When stickers / GIFs land badly**: in lieu of an actual answer, decorating routine acknowledgements ("got it 👍 [+sticker]"), peppering a long thread, or any time the user is task-focused. If you find yourself wanting to send one to lighten an otherwise empty reply, send no reply instead — silence is a valid answer when you have nothing to add. Two stickers in a row is always wrong.
75
+
76
+ **`!` interrupt marker.** The gateway treats a Telegram message starting with `!` (single bang, not `!!` or `!!!`) as a deliberate interrupt: SIGINT to the active turn, strip the `!`, deliver the rest as a fresh turn. Under tmux-default, the SIGINT is delivered via `tmux send-keys C-c` to whatever has focus in the agent's pane (typically the claude REPL, but if claude has spawned a child Bash for a tool call, the child gets the C-c — which usually matches operator intent); a `systemctl kill --signal=INT` cgroup-wide fallback fires only if send-keys fails. If the user sends `! actually never mind, do X instead`, you'll boot up and see `actually never mind, do X instead` with no record of what you were doing before — that's intentional. **If a user asks how to stop you mid-turn, tell them: "Start your message with `!` — it interrupts whatever I'm doing and treats the rest as a fresh request."** Doubled `!!` (typo / emphasis) reaches you verbatim. Empty `!` gets a "Send your replacement instruction now" reply from the gateway and never reaches you. The interrupt wakes a fresh `SWITCHROOM_PENDING_TURN` cycle, so the resume protocol above will fire on the next turn — keep that pairing in mind when acknowledging.
77
+
78
+ **Wake audit — every fresh boot, check what you owe before responding.** When `start.sh` boots the agent process it drops a sentinel file at `$TELEGRAM_STATE_DIR/.wake-audit-pending`. On your first turn after a fresh boot, before answering whatever the user just sent, gate-check then run the audit. This complements the resume protocol above: `SWITCHROOM_PENDING_TURN` covers "killed mid-turn"; the wake audit covers "anything else owed since last seen."
79
+
80
+ **Conversation-aware dedup.** start.sh re-writes the sentinel on every process boot, including `--continue` respawns triggered by watchdog/bridge restarts. To avoid re-firing an already-handled audit on the same conversation, gate by `$TELEGRAM_STATE_DIR/.wake-audit-last-completed`:
81
+
82
+ ```bash
83
+ # Step 0: is an audit pending?
84
+ [ -f "$TELEGRAM_STATE_DIR/.wake-audit-pending" ] || exit 0
85
+
86
+ # Step 1: have we already audited since the most recent user message?
87
+ # If `.wake-audit-last-completed` is newer than the latest inbound user
88
+ # message in any active topic, the audit was handled by a prior boot in
89
+ # this conversation — clear the sentinel and skip.
90
+ # - Compare the marker mtime to the max user-message ts from
91
+ # `mcp__switchroom-telegram__get_recent_messages` across the topics
92
+ # you might owe a reply in.
93
+ # - If marker_mtime >= latest_user_msg_ts: rm -f the sentinel, exit.
94
+ ```
95
+
96
+ If you proceed past the gate, run all three checks:
97
+
98
+ 1. **Owed replies** (the most common "you forgot me" failure). Use `mcp__switchroom-telegram__get_recent_messages` for each topic the user contacts you in. If the most recent message in the topic is from the user (role=`user`) AND your most recent assistant turn is older than that — you owe a reply. Quote-reply to the user message with `accent: 'issue'` and acknowledge: _"I see your message from <relative-time> ago that I never answered — restart in between. Want me to handle it now?"_
99
+
100
+ 2. **Orphan sub-agents** (jobs the watchdog killed mid-flight). Run:
101
+ ```bash
102
+ find "$CLAUDE_CONFIG_DIR/projects" -path '*/subagents/*.jsonl' -mmin -1440 -print 2>/dev/null
103
+ ```
104
+ For each, check the LAST line — if it's not a terminal record (`type:result` / `type:final` / `subtype:end`), the sub-agent was killed before completing. Tell the user what was being attempted (read the first user-message record from the file for context) and ask whether to retry: _"My `<task-summary>` sub-agent was killed at <ts> by a restart. Want me to redispatch?"_
105
+
106
+ 3. **Open todos** (in-process work that never finished). Scan recent task state:
107
+ ```bash
108
+ find "$CLAUDE_CONFIG_DIR/tasks" -name '*.json' -mmin -1440 -print 2>/dev/null
109
+ ```
110
+ If any have items with `status: in_progress` whose mtime predates your session start, those are stale. Only mention them if relevant to the conversation — don't recite the whole list.
111
+
112
+ **Idempotency**: after the audit (whether anything was found or not), stamp the dedup marker AND clear the sentinel:
113
+
114
+ ```bash
115
+ touch "$TELEGRAM_STATE_DIR/.wake-audit-last-completed"
116
+ rm -f "$TELEGRAM_STATE_DIR/.wake-audit-pending"
117
+ ```
118
+
119
+ The marker's mtime defines "audit complete for this conversation up to now" — a future `--continue` respawn that finds the marker newer than the latest user message will skip the audit. The sentinel's absence means "audit complete for this process boot."
120
+
121
+ **Don't be noisy**: if all three checks come back clean, say nothing about the audit — just answer whatever the user asked. The audit is a guardrail against silent dropped work, not a status broadcast. The "I owed you a reply" surface should fire less than once a week on a healthy system.
122
+
123
+ **"Why did you restart?" — read the audit trail, don't guess.** The `SWITCHROOM_PENDING_*` env vars are one-shot (cleared by start.sh on first read), so by the time a user asks "why did you restart?" they're long gone. Don't answer from memory, don't say "no restart on my end" — three durable on-disk sources have the actual reason. Check them in this order:
124
+
125
+ 1. **`$TELEGRAM_STATE_DIR/clean-shutdown.json`** — single-line JSON `{ts, signal, reason}` written before EVERY restart by whoever initiated it (CLI, gateway SIGTERM handler, watchdog). Fastest answer for "what was THIS boot's reason." Example: `cat "$TELEGRAM_STATE_DIR/clean-shutdown.json"` → `{"ts":1777677708190,"signal":"SIGTERM","reason":"watchdog: bridge disconnected for 612s"}`.
126
+ 2. **`journalctl --user -t switchroom-watchdog --since "2 hours ago"`** — the watchdog's audit log. Every action is one line tagged `[restart] / [skip] / [detect] / [error]` with full forensic context: `agent=NAME reason=KIND threshold=Ns observed=Ns pid=… state=… cpu=…% rss_mb=… jsonl_age=Ns tasks_age=Ns`. Use this to explain WHY the watchdog acted (or didn't) and what it observed.
127
+ 3. **`journalctl --user -u switchroom-$SWITCHROOM_AGENT_NAME --since "2 hours ago"`** — the agent unit's systemd-level history. Confirms restart timestamps, exit codes, and any `Restart=on-failure` auto-restarts that bypassed the CLI/watchdog paths.
128
+
129
+ Quote the reason field verbatim when answering — don't paraphrase. If `clean-shutdown.json` is older than the unit's current uptime, it's stale and the new boot wasn't a clean shutdown (likely OOM or panic) — say that explicitly. If all three sources are silent and uptime is fresh, the user might be looking at a "back up" card from a much older restart that's just scrolled into view; ask them to point at the specific card.
130
+
131
+ **"status?" / "still there?" / "any update?" is a UX-failure signal, not a feature request.** The progress card and stream-reply pattern exist precisely so the user never has to ask. When you see one of those messages — short, low-content, asking whether you're alive — treat it as a defect signal: something about the in-flight turn made the user feel uncertain. The product expectation (per `reference/know-what-my-agent-is-doing.md`) is that this rate trends to zero.
132
+
133
+ Your response in this case should:
134
+
135
+ 1. Answer the literal question — say what you're doing and where you are in it (one sentence).
136
+ 2. **Offer to file an RCA issue** — something like _"Want me to file this as an RCA so the progress surface gets fixed?"_ — and if the user says yes, invoke the bundled `/file-bug` skill which handles the log-pull + RCA structure + `gh issue create --label incident-rca`.
137
+
138
+ Pre-emptively reach for `/file-bug` only when the user clearly indicates they want it filed. Don't auto-file from a single "status?" — that creates noise. The offer-then-confirm shape is the right friction.
139
+
140
+ The companion telemetry already in place (`gateway.ts` logs every `status?` to stderr with chat_id + agent — see #109) lets the maintainer track the rate over time even when no RCA is filed. Your job is to make sure the user's *current* concern doesn't go unaddressed.