switchroom 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (718) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +447 -0
  3. package/bin/autoaccept.exp +81 -0
  4. package/bin/boot-self-test.sh +149 -0
  5. package/bin/bridge-watchdog.sh +967 -0
  6. package/bin/handoff-briefing.sh +206 -0
  7. package/bin/run-hook.sh +228 -0
  8. package/bin/switchroom.ts +4 -0
  9. package/bin/timezone-hook.sh +67 -0
  10. package/bin/user-profile-refresh-hook.sh +38 -0
  11. package/bin/workspace-dynamic-hook.sh +142 -0
  12. package/bin/workspace-stable-hook.sh +57 -0
  13. package/dist/cli/autoaccept-poll.js +118 -0
  14. package/dist/cli/switchroom.js +48557 -0
  15. package/package.json +95 -0
  16. package/profiles/_base/settings.json.hbs +15 -0
  17. package/profiles/_base/start.sh.hbs +383 -0
  18. package/profiles/_shared/telegram-style.md.hbs +140 -0
  19. package/profiles/coding/CLAUDE.md.hbs +57 -0
  20. package/profiles/coding/skills/architecture/SKILL.md +70 -0
  21. package/profiles/coding/skills/code-review/SKILL.md +58 -0
  22. package/profiles/coding/workspace/SOUL.md.hbs +25 -0
  23. package/profiles/default/CLAUDE.md +238 -0
  24. package/profiles/default/CLAUDE.md.hbs +113 -0
  25. package/profiles/default/workspace/CLAUDE.md.hbs +126 -0
  26. package/profiles/default/workspace/HEARTBEAT.md.hbs +40 -0
  27. package/profiles/default/workspace/IDENTITY.md.hbs +32 -0
  28. package/profiles/default/workspace/MEMORY.md.hbs +29 -0
  29. package/profiles/default/workspace/SOUL.md.hbs +61 -0
  30. package/profiles/default/workspace/TOOLS.md.hbs +29 -0
  31. package/profiles/default/workspace/USER.md.hbs +52 -0
  32. package/profiles/default/workspace/memory/.gitkeep +0 -0
  33. package/profiles/executive-assistant/CLAUDE.md.hbs +51 -0
  34. package/profiles/executive-assistant/skills/daily-briefing/SKILL.md +55 -0
  35. package/profiles/executive-assistant/skills/meeting-prep/SKILL.md +58 -0
  36. package/profiles/executive-assistant/workspace/SOUL.md.hbs +25 -0
  37. package/profiles/health-coach/CLAUDE.md.hbs +45 -0
  38. package/profiles/health-coach/skills/check-in/SKILL.md +41 -0
  39. package/profiles/health-coach/skills/weekly-review/SKILL.md +53 -0
  40. package/profiles/health-coach/workspace/SOUL.md.hbs +25 -0
  41. package/skills/buildkite-agent-infrastructure/SKILL.md +302 -0
  42. package/skills/buildkite-agent-infrastructure/agents/openai.yaml +6 -0
  43. package/skills/buildkite-agent-infrastructure/assets/buildkite-icon-large.png +0 -0
  44. package/skills/buildkite-agent-infrastructure/assets/buildkite-icon-small.png +0 -0
  45. package/skills/buildkite-agent-infrastructure/references/audit-logging.md +87 -0
  46. package/skills/buildkite-agent-infrastructure/references/graphql-mutations.md +690 -0
  47. package/skills/buildkite-agent-infrastructure/references/instance-shapes.md +38 -0
  48. package/skills/buildkite-agent-infrastructure/references/pipeline-templates.md +73 -0
  49. package/skills/buildkite-agent-infrastructure/references/self-hosted-agents.md +137 -0
  50. package/skills/buildkite-agent-infrastructure/references/sso-saml.md +92 -0
  51. package/skills/buildkite-agent-runtime/SKILL.md +476 -0
  52. package/skills/buildkite-agent-runtime/agents/openai.yaml +6 -0
  53. package/skills/buildkite-agent-runtime/assets/buildkite-icon-large.png +0 -0
  54. package/skills/buildkite-agent-runtime/assets/buildkite-icon-small.png +0 -0
  55. package/skills/buildkite-agent-runtime/references/flag-reference.md +417 -0
  56. package/skills/buildkite-agent-runtime/references/patterns-and-recipes.md +555 -0
  57. package/skills/buildkite-api/SKILL.md +285 -0
  58. package/skills/buildkite-api/agents/openai.yaml +6 -0
  59. package/skills/buildkite-api/assets/buildkite-icon-large.png +0 -0
  60. package/skills/buildkite-api/assets/buildkite-icon-small.png +0 -0
  61. package/skills/buildkite-api/references/graphql-reference.md +195 -0
  62. package/skills/buildkite-api/references/patterns.md +44 -0
  63. package/skills/buildkite-api/references/webhooks.md +161 -0
  64. package/skills/buildkite-cli/SKILL.md +379 -0
  65. package/skills/buildkite-cli/agents/openai.yaml +6 -0
  66. package/skills/buildkite-cli/assets/buildkite-icon-large.png +0 -0
  67. package/skills/buildkite-cli/assets/buildkite-icon-small.png +0 -0
  68. package/skills/buildkite-cli/references/command-reference.md +181 -0
  69. package/skills/buildkite-migration/SKILL.md +182 -0
  70. package/skills/buildkite-pipelines/SKILL.md +464 -0
  71. package/skills/buildkite-pipelines/agents/openai.yaml +6 -0
  72. package/skills/buildkite-pipelines/assets/buildkite-icon-large.png +0 -0
  73. package/skills/buildkite-pipelines/assets/buildkite-icon-small.png +0 -0
  74. package/skills/buildkite-pipelines/examples/basic-pipeline.yml +24 -0
  75. package/skills/buildkite-pipelines/examples/optimized-pipeline.yml +100 -0
  76. package/skills/buildkite-pipelines/references/advanced-patterns.md +286 -0
  77. package/skills/buildkite-pipelines/references/retry-and-error-codes.md +131 -0
  78. package/skills/buildkite-pipelines/references/step-types-reference.md +225 -0
  79. package/skills/buildkite-secure-delivery/SKILL.md +168 -0
  80. package/skills/buildkite-secure-delivery/agents/openai.yaml +6 -0
  81. package/skills/buildkite-secure-delivery/assets/buildkite-icon-large.png +0 -0
  82. package/skills/buildkite-secure-delivery/assets/buildkite-icon-small.png +0 -0
  83. package/skills/buildkite-secure-delivery/references/oidc-cloud-providers.md +83 -0
  84. package/skills/buildkite-secure-delivery/references/package-publishing.md +100 -0
  85. package/skills/buildkite-test-engine/SKILL.md +239 -0
  86. package/skills/buildkite-test-engine/agents/openai.yaml +6 -0
  87. package/skills/buildkite-test-engine/assets/buildkite-icon-large.png +0 -0
  88. package/skills/buildkite-test-engine/assets/buildkite-icon-small.png +0 -0
  89. package/skills/buildkite-test-engine/examples/bktec-splitting.yml +16 -0
  90. package/skills/buildkite-test-engine/examples/collector-pipeline.yml +11 -0
  91. package/skills/buildkite-test-engine/references/collectors.md +198 -0
  92. package/skills/buildkite-test-engine/references/splitting-examples.md +93 -0
  93. package/skills/docx/LICENSE.txt +30 -0
  94. package/skills/docx/SKILL.md +590 -0
  95. package/skills/docx/VENDORED.md +32 -0
  96. package/skills/docx/scripts/__init__.py +1 -0
  97. package/skills/docx/scripts/accept_changes.py +135 -0
  98. package/skills/docx/scripts/comment.py +318 -0
  99. package/skills/docx/scripts/office/helpers/__init__.py +0 -0
  100. package/skills/docx/scripts/office/helpers/merge_runs.py +199 -0
  101. package/skills/docx/scripts/office/helpers/simplify_redlines.py +197 -0
  102. package/skills/docx/scripts/office/pack.py +159 -0
  103. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  104. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  105. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  106. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  107. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  108. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  109. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  110. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  111. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  112. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  113. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  114. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  115. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  116. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  117. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  118. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  119. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  120. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  121. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  122. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  123. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  124. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  125. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  126. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  127. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  128. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  129. package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  130. package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  131. package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  132. package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  133. package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  134. package/skills/docx/scripts/office/schemas/mce/mc.xsd +75 -0
  135. package/skills/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  136. package/skills/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  137. package/skills/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  138. package/skills/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  139. package/skills/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  140. package/skills/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  141. package/skills/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  142. package/skills/docx/scripts/office/soffice.py +183 -0
  143. package/skills/docx/scripts/office/unpack.py +132 -0
  144. package/skills/docx/scripts/office/validate.py +111 -0
  145. package/skills/docx/scripts/office/validators/__init__.py +15 -0
  146. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-313.pyc +0 -0
  147. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-313.pyc +0 -0
  148. package/skills/docx/scripts/office/validators/base.py +847 -0
  149. package/skills/docx/scripts/office/validators/docx.py +446 -0
  150. package/skills/docx/scripts/office/validators/pptx.py +275 -0
  151. package/skills/docx/scripts/office/validators/redlining.py +247 -0
  152. package/skills/docx/scripts/templates/comments.xml +3 -0
  153. package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  154. package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  155. package/skills/docx/scripts/templates/commentsIds.xml +3 -0
  156. package/skills/docx/scripts/templates/people.xml +3 -0
  157. package/skills/file-bug/SKILL.md +129 -0
  158. package/skills/humanizer/LICENSE +21 -0
  159. package/skills/humanizer/SKILL.md +559 -0
  160. package/skills/humanizer/VENDORED.md +38 -0
  161. package/skills/humanizer-calibrate/SKILL.md +144 -0
  162. package/skills/mcp-builder/LICENSE.txt +202 -0
  163. package/skills/mcp-builder/SKILL.md +236 -0
  164. package/skills/mcp-builder/VENDORED.md +32 -0
  165. package/skills/mcp-builder/reference/evaluation.md +602 -0
  166. package/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  167. package/skills/mcp-builder/reference/node_mcp_server.md +970 -0
  168. package/skills/mcp-builder/reference/python_mcp_server.md +719 -0
  169. package/skills/mcp-builder/scripts/connections.py +151 -0
  170. package/skills/mcp-builder/scripts/evaluation.py +373 -0
  171. package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  172. package/skills/mcp-builder/scripts/requirements.txt +2 -0
  173. package/skills/pdf/LICENSE.txt +30 -0
  174. package/skills/pdf/SKILL.md +314 -0
  175. package/skills/pdf/VENDORED.md +32 -0
  176. package/skills/pdf/forms.md +294 -0
  177. package/skills/pdf/reference.md +612 -0
  178. package/skills/pdf/scripts/check_bounding_boxes.py +65 -0
  179. package/skills/pdf/scripts/check_fillable_fields.py +11 -0
  180. package/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
  181. package/skills/pdf/scripts/create_validation_image.py +37 -0
  182. package/skills/pdf/scripts/extract_form_field_info.py +122 -0
  183. package/skills/pdf/scripts/extract_form_structure.py +115 -0
  184. package/skills/pdf/scripts/fill_fillable_fields.py +98 -0
  185. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  186. package/skills/pptx/LICENSE.txt +30 -0
  187. package/skills/pptx/SKILL.md +232 -0
  188. package/skills/pptx/VENDORED.md +32 -0
  189. package/skills/pptx/editing.md +205 -0
  190. package/skills/pptx/pptxgenjs.md +420 -0
  191. package/skills/pptx/scripts/__init__.py +0 -0
  192. package/skills/pptx/scripts/add_slide.py +195 -0
  193. package/skills/pptx/scripts/clean.py +286 -0
  194. package/skills/pptx/scripts/office/helpers/__init__.py +0 -0
  195. package/skills/pptx/scripts/office/helpers/merge_runs.py +199 -0
  196. package/skills/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
  197. package/skills/pptx/scripts/office/pack.py +159 -0
  198. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  199. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  200. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  201. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  202. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  203. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  204. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  205. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  206. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  207. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  208. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  209. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  210. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  211. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  212. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  213. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  214. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  215. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  216. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  217. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  218. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  219. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  220. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  221. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  222. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  223. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  224. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  225. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  226. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  227. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  228. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  229. package/skills/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
  230. package/skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  231. package/skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  232. package/skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  233. package/skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  234. package/skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  235. package/skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  236. package/skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  237. package/skills/pptx/scripts/office/soffice.py +183 -0
  238. package/skills/pptx/scripts/office/unpack.py +132 -0
  239. package/skills/pptx/scripts/office/validate.py +111 -0
  240. package/skills/pptx/scripts/office/validators/__init__.py +15 -0
  241. package/skills/pptx/scripts/office/validators/base.py +847 -0
  242. package/skills/pptx/scripts/office/validators/docx.py +446 -0
  243. package/skills/pptx/scripts/office/validators/pptx.py +275 -0
  244. package/skills/pptx/scripts/office/validators/redlining.py +247 -0
  245. package/skills/pptx/scripts/thumbnail.py +289 -0
  246. package/skills/skill-creator/LICENSE.txt +202 -0
  247. package/skills/skill-creator/SKILL.md +485 -0
  248. package/skills/skill-creator/VENDORED.md +32 -0
  249. package/skills/skill-creator/agents/analyzer.md +274 -0
  250. package/skills/skill-creator/agents/comparator.md +202 -0
  251. package/skills/skill-creator/agents/grader.md +223 -0
  252. package/skills/skill-creator/assets/eval_review.html +146 -0
  253. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  254. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  255. package/skills/skill-creator/references/schemas.md +430 -0
  256. package/skills/skill-creator/scripts/__init__.py +0 -0
  257. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  258. package/skills/skill-creator/scripts/generate_report.py +326 -0
  259. package/skills/skill-creator/scripts/improve_description.py +247 -0
  260. package/skills/skill-creator/scripts/package_skill.py +136 -0
  261. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  262. package/skills/skill-creator/scripts/run_eval.py +310 -0
  263. package/skills/skill-creator/scripts/run_loop.py +328 -0
  264. package/skills/skill-creator/scripts/utils.py +47 -0
  265. package/skills/switchroom-architecture/SKILL.md +60 -0
  266. package/skills/switchroom-architecture/cascade.md +112 -0
  267. package/skills/switchroom-architecture/sub-agents.md +87 -0
  268. package/skills/switchroom-architecture/telegram.md +94 -0
  269. package/skills/switchroom-cli/SKILL.md +274 -0
  270. package/skills/switchroom-health/SKILL.md +101 -0
  271. package/skills/switchroom-install/SKILL.md +116 -0
  272. package/skills/switchroom-manage/SKILL.md +90 -0
  273. package/skills/switchroom-status/SKILL.md +69 -0
  274. package/skills/switchroom-status/scripts/status.sh +69 -0
  275. package/skills/telegram-test-harness/SKILL.md +191 -0
  276. package/skills/token-helpers/SKILL.md +73 -0
  277. package/skills/token-helpers/scripts/google-cal-token.sh +62 -0
  278. package/skills/token-helpers/scripts/ms-graph-token.sh +70 -0
  279. package/skills/webapp-testing/LICENSE.txt +202 -0
  280. package/skills/webapp-testing/SKILL.md +96 -0
  281. package/skills/webapp-testing/VENDORED.md +32 -0
  282. package/skills/webapp-testing/examples/console_logging.py +35 -0
  283. package/skills/webapp-testing/examples/element_discovery.py +40 -0
  284. package/skills/webapp-testing/examples/static_html_automation.py +33 -0
  285. package/skills/webapp-testing/scripts/with_server.py +106 -0
  286. package/skills/xlsx/LICENSE.txt +30 -0
  287. package/skills/xlsx/SKILL.md +292 -0
  288. package/skills/xlsx/VENDORED.md +32 -0
  289. package/skills/xlsx/scripts/office/helpers/__init__.py +0 -0
  290. package/skills/xlsx/scripts/office/helpers/merge_runs.py +199 -0
  291. package/skills/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
  292. package/skills/xlsx/scripts/office/pack.py +159 -0
  293. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  294. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  295. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  296. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  297. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  298. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  299. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  300. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  301. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  302. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  303. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  304. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  305. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  306. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  307. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  308. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  309. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  310. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  311. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  312. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  313. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  314. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  315. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  316. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  317. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  318. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  319. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  320. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  321. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  322. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  323. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  324. package/skills/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
  325. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  326. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  327. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  328. package/skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  329. package/skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  330. package/skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  331. package/skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  332. package/skills/xlsx/scripts/office/soffice.py +183 -0
  333. package/skills/xlsx/scripts/office/unpack.py +132 -0
  334. package/skills/xlsx/scripts/office/validate.py +111 -0
  335. package/skills/xlsx/scripts/office/validators/__init__.py +15 -0
  336. package/skills/xlsx/scripts/office/validators/base.py +847 -0
  337. package/skills/xlsx/scripts/office/validators/docx.py +446 -0
  338. package/skills/xlsx/scripts/office/validators/pptx.py +275 -0
  339. package/skills/xlsx/scripts/office/validators/redlining.py +247 -0
  340. package/skills/xlsx/scripts/recalc.py +184 -0
  341. package/telegram-plugin/.claude-plugin/plugin.json +20 -0
  342. package/telegram-plugin/.mcp.json +14 -0
  343. package/telegram-plugin/LICENSE +21 -0
  344. package/telegram-plugin/README.md +352 -0
  345. package/telegram-plugin/active-pins-sweep.ts +204 -0
  346. package/telegram-plugin/active-pins.ts +146 -0
  347. package/telegram-plugin/active-reactions-sweep.ts +79 -0
  348. package/telegram-plugin/active-reactions.ts +134 -0
  349. package/telegram-plugin/admin-commands/dispatch.test.ts +149 -0
  350. package/telegram-plugin/admin-commands/index.ts +106 -0
  351. package/telegram-plugin/answer-stream.ts +565 -0
  352. package/telegram-plugin/ask-user.ts +179 -0
  353. package/telegram-plugin/attachment-path.ts +80 -0
  354. package/telegram-plugin/auth-code-redact.ts +83 -0
  355. package/telegram-plugin/auth-dashboard.ts +1104 -0
  356. package/telegram-plugin/auth-slot-parser.ts +497 -0
  357. package/telegram-plugin/auto-fallback-dispatcher.ts +68 -0
  358. package/telegram-plugin/auto-fallback.ts +348 -0
  359. package/telegram-plugin/bridge/bridge.ts +687 -0
  360. package/telegram-plugin/bridge/ipc-client.ts +326 -0
  361. package/telegram-plugin/bun.lock +218 -0
  362. package/telegram-plugin/card-format.ts +62 -0
  363. package/telegram-plugin/channel-envelope-safety.test.ts +56 -0
  364. package/telegram-plugin/channel-envelope-safety.ts +56 -0
  365. package/telegram-plugin/chat-lock.ts +65 -0
  366. package/telegram-plugin/context-exhaustion.ts +38 -0
  367. package/telegram-plugin/credits-watch.ts +220 -0
  368. package/telegram-plugin/dist/bridge/bridge.js +24758 -0
  369. package/telegram-plugin/dist/foreman/foreman.js +30723 -0
  370. package/telegram-plugin/dist/gateway/gateway.js +46497 -0
  371. package/telegram-plugin/dist/server.js +24551 -0
  372. package/telegram-plugin/dm-command-gate.ts +56 -0
  373. package/telegram-plugin/docs/gateway-server-split.md +133 -0
  374. package/telegram-plugin/docs/multi-agent-card-design.md +847 -0
  375. package/telegram-plugin/docs/pinned-progress-card-reliability.md +144 -0
  376. package/telegram-plugin/docs/stream-json-daemon-mode.md +477 -0
  377. package/telegram-plugin/docs/waiting-ux-spec.md +233 -0
  378. package/telegram-plugin/draft-stream.ts +442 -0
  379. package/telegram-plugin/draft-transport.ts +72 -0
  380. package/telegram-plugin/first-paint.ts +246 -0
  381. package/telegram-plugin/fleet-state.ts +246 -0
  382. package/telegram-plugin/foreman/foreman-create-flow.ts +202 -0
  383. package/telegram-plugin/foreman/foreman-handlers.ts +493 -0
  384. package/telegram-plugin/foreman/foreman.ts +1130 -0
  385. package/telegram-plugin/foreman/setup-flow.ts +345 -0
  386. package/telegram-plugin/foreman/setup-state.ts +239 -0
  387. package/telegram-plugin/foreman/state.ts +203 -0
  388. package/telegram-plugin/format.ts +685 -0
  389. package/telegram-plugin/gateway/access-validator.test.ts +95 -0
  390. package/telegram-plugin/gateway/access-validator.ts +37 -0
  391. package/telegram-plugin/gateway/boot-card.ts +582 -0
  392. package/telegram-plugin/gateway/boot-probes.ts +863 -0
  393. package/telegram-plugin/gateway/boot-reason.ts +51 -0
  394. package/telegram-plugin/gateway/boot-sweep-filter.test.ts +54 -0
  395. package/telegram-plugin/gateway/boot-sweep-filter.ts +32 -0
  396. package/telegram-plugin/gateway/clean-shutdown-marker.ts +183 -0
  397. package/telegram-plugin/gateway/disconnect-flush.ts +109 -0
  398. package/telegram-plugin/gateway/gateway.ts +10202 -0
  399. package/telegram-plugin/gateway/inbound-coalesce.ts +147 -0
  400. package/telegram-plugin/gateway/inject-handler.test.ts +221 -0
  401. package/telegram-plugin/gateway/inject-handler.ts +190 -0
  402. package/telegram-plugin/gateway/ipc-protocol.ts +151 -0
  403. package/telegram-plugin/gateway/ipc-server.ts +494 -0
  404. package/telegram-plugin/gateway/pid-file.ts +103 -0
  405. package/telegram-plugin/gateway/poll-health.ts +156 -0
  406. package/telegram-plugin/gateway/preamble-suppressor.ts +154 -0
  407. package/telegram-plugin/gateway/quota-cache.ts +125 -0
  408. package/telegram-plugin/gateway/resolve-calling-subagent.ts +78 -0
  409. package/telegram-plugin/gateway/restart-watchdog.ts +200 -0
  410. package/telegram-plugin/gateway/session-marker.ts +83 -0
  411. package/telegram-plugin/gateway/shutdown-drain.ts +162 -0
  412. package/telegram-plugin/gateway/startup-mutex.ts +285 -0
  413. package/telegram-plugin/gateway/startup-network-retry.ts +142 -0
  414. package/telegram-plugin/gateway/turn-active-marker.ts +176 -0
  415. package/telegram-plugin/gateway/unhandled-rejection-policy.ts +78 -0
  416. package/telegram-plugin/handoff-continuity.ts +200 -0
  417. package/telegram-plugin/history.ts +468 -0
  418. package/telegram-plugin/hooks/hooks.json +58 -0
  419. package/telegram-plugin/hooks/secret-guard-pretool.mjs +208 -0
  420. package/telegram-plugin/hooks/secret-scrub-stop.mjs +98 -0
  421. package/telegram-plugin/hooks/silent-end-interrupt-stop.mjs +111 -0
  422. package/telegram-plugin/hooks/subagent-tracker-posttool.mjs +296 -0
  423. package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +261 -0
  424. package/telegram-plugin/html-sanitize.ts +244 -0
  425. package/telegram-plugin/idle-footer.ts +65 -0
  426. package/telegram-plugin/inline-keyboard-callbacks.ts +166 -0
  427. package/telegram-plugin/interrupt-marker.ts +66 -0
  428. package/telegram-plugin/issues-card.ts +371 -0
  429. package/telegram-plugin/issues-watcher.ts +125 -0
  430. package/telegram-plugin/model-unavailable.ts +325 -0
  431. package/telegram-plugin/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  432. package/telegram-plugin/operator-events-history.ts +94 -0
  433. package/telegram-plugin/operator-events.fixtures.json +161 -0
  434. package/telegram-plugin/operator-events.ts +421 -0
  435. package/telegram-plugin/package.json +55 -0
  436. package/telegram-plugin/permission-rule.ts +133 -0
  437. package/telegram-plugin/permission-title.ts +117 -0
  438. package/telegram-plugin/pin-event-log.ts +76 -0
  439. package/telegram-plugin/plugin-logger.ts +136 -0
  440. package/telegram-plugin/progress-card-driver.ts +2697 -0
  441. package/telegram-plugin/progress-card-pin-manager.ts +589 -0
  442. package/telegram-plugin/progress-card-pin-watchdog.ts +98 -0
  443. package/telegram-plugin/progress-card.ts +1409 -0
  444. package/telegram-plugin/pty-partial-handler.ts +247 -0
  445. package/telegram-plugin/pty-tail.ts +730 -0
  446. package/telegram-plugin/quota-check.ts +474 -0
  447. package/telegram-plugin/recent-outbound-dedup.ts +169 -0
  448. package/telegram-plugin/registry/api-registry.test.ts +201 -0
  449. package/telegram-plugin/registry/subagents-bugs.test.ts +454 -0
  450. package/telegram-plugin/registry/subagents-schema.ts +509 -0
  451. package/telegram-plugin/registry/subagents.test.ts +476 -0
  452. package/telegram-plugin/registry/turns-schema.test.ts +101 -0
  453. package/telegram-plugin/registry/turns-schema.ts +417 -0
  454. package/telegram-plugin/retry-api-call.ts +172 -0
  455. package/telegram-plugin/scripts/build.mjs +78 -0
  456. package/telegram-plugin/secret-detect/audit.ts +66 -0
  457. package/telegram-plugin/secret-detect/chunker.ts +37 -0
  458. package/telegram-plugin/secret-detect/entropy.ts +20 -0
  459. package/telegram-plugin/secret-detect/gitleaks-loader.ts +74 -0
  460. package/telegram-plugin/secret-detect/gitleaks.toml +27 -0
  461. package/telegram-plugin/secret-detect/index.ts +218 -0
  462. package/telegram-plugin/secret-detect/kv-scanner.ts +60 -0
  463. package/telegram-plugin/secret-detect/mask.ts +13 -0
  464. package/telegram-plugin/secret-detect/patterns.ts +115 -0
  465. package/telegram-plugin/secret-detect/pipeline.ts +144 -0
  466. package/telegram-plugin/secret-detect/rewrite.ts +26 -0
  467. package/telegram-plugin/secret-detect/secretlint-source.ts +95 -0
  468. package/telegram-plugin/secret-detect/slug.ts +44 -0
  469. package/telegram-plugin/secret-detect/staging.ts +85 -0
  470. package/telegram-plugin/secret-detect/suppressor.ts +34 -0
  471. package/telegram-plugin/secret-detect/url-redact.ts +60 -0
  472. package/telegram-plugin/secret-detect/vault-write.ts +56 -0
  473. package/telegram-plugin/server.js +41795 -0
  474. package/telegram-plugin/server.ts +171 -0
  475. package/telegram-plugin/session-tail.ts +884 -0
  476. package/telegram-plugin/shared/bot-runtime.ts +324 -0
  477. package/telegram-plugin/silent-reply.ts +58 -0
  478. package/telegram-plugin/slot-banner-driver.ts +147 -0
  479. package/telegram-plugin/slot-banner.ts +86 -0
  480. package/telegram-plugin/start.js +26 -0
  481. package/telegram-plugin/startup-reset.ts +45 -0
  482. package/telegram-plugin/status-reactions.ts +332 -0
  483. package/telegram-plugin/steering.ts +155 -0
  484. package/telegram-plugin/sticker-aliases.ts +249 -0
  485. package/telegram-plugin/stream-controller.ts +311 -0
  486. package/telegram-plugin/stream-reply-handler.ts +664 -0
  487. package/telegram-plugin/streaming-metrics.ts +134 -0
  488. package/telegram-plugin/streaming-report.ts +204 -0
  489. package/telegram-plugin/subagent-watcher.ts +880 -0
  490. package/telegram-plugin/telegram-button-constraints.ts +191 -0
  491. package/telegram-plugin/telegraph.ts +381 -0
  492. package/telegram-plugin/tests/HARNESS.md +340 -0
  493. package/telegram-plugin/tests/_progress-card-harness.ts +105 -0
  494. package/telegram-plugin/tests/active-pins-boot-reaper.test.ts +211 -0
  495. package/telegram-plugin/tests/active-pins-sweep.test.ts +309 -0
  496. package/telegram-plugin/tests/active-pins.test.ts +187 -0
  497. package/telegram-plugin/tests/active-reactions-sweep.test.ts +116 -0
  498. package/telegram-plugin/tests/active-reactions.test.ts +198 -0
  499. package/telegram-plugin/tests/answer-stream-dedup.test.ts +352 -0
  500. package/telegram-plugin/tests/answer-stream-silent-markers.test.ts +236 -0
  501. package/telegram-plugin/tests/answer-stream.test.ts +878 -0
  502. package/telegram-plugin/tests/ask-user.test.ts +203 -0
  503. package/telegram-plugin/tests/attachment-path.test.ts +199 -0
  504. package/telegram-plugin/tests/auth-account-identity-surface.test.ts +118 -0
  505. package/telegram-plugin/tests/auth-code-auto-capture.test.ts +144 -0
  506. package/telegram-plugin/tests/auth-code-redact.test.ts +248 -0
  507. package/telegram-plugin/tests/auth-dashboard-edge-cases.test.ts +260 -0
  508. package/telegram-plugin/tests/auth-dashboard-restart-flow.test.ts +140 -0
  509. package/telegram-plugin/tests/auth-dashboard-v3b.test.ts +559 -0
  510. package/telegram-plugin/tests/auth-dashboard.test.ts +1045 -0
  511. package/telegram-plugin/tests/auth-login-url-button.test.ts +122 -0
  512. package/telegram-plugin/tests/auth-slot-commands.test.ts +640 -0
  513. package/telegram-plugin/tests/auto-fallback-dispatcher.e2e.test.ts +183 -0
  514. package/telegram-plugin/tests/auto-fallback.test.ts +381 -0
  515. package/telegram-plugin/tests/boot-card-account-quota.test.ts +137 -0
  516. package/telegram-plugin/tests/boot-card-dedupe.test.ts +154 -0
  517. package/telegram-plugin/tests/boot-card-probe-target.test.ts +194 -0
  518. package/telegram-plugin/tests/boot-card-reason.test.ts +103 -0
  519. package/telegram-plugin/tests/boot-card-render.test.ts +219 -0
  520. package/telegram-plugin/tests/boot-probes.test.ts +451 -0
  521. package/telegram-plugin/tests/bot-api.harness.ts +116 -0
  522. package/telegram-plugin/tests/bot-runtime.test.ts +190 -0
  523. package/telegram-plugin/tests/bridge-anonymous-refuse.test.ts +60 -0
  524. package/telegram-plugin/tests/context-exhaustion.test.ts +114 -0
  525. package/telegram-plugin/tests/credits-watch.test.ts +221 -0
  526. package/telegram-plugin/tests/dm-command-gate.test.ts +176 -0
  527. package/telegram-plugin/tests/draft-stream.test.ts +752 -0
  528. package/telegram-plugin/tests/draft-transport.test.ts +141 -0
  529. package/telegram-plugin/tests/e2e.test.ts +436 -0
  530. package/telegram-plugin/tests/fake-bot-api.test.ts +213 -0
  531. package/telegram-plugin/tests/fake-bot-api.ts +617 -0
  532. package/telegram-plugin/tests/false-restart-banner.test.ts +253 -0
  533. package/telegram-plugin/tests/first-paint.test.ts +257 -0
  534. package/telegram-plugin/tests/fixtures/pty-tail-tmux-fragment.bin +6 -0
  535. package/telegram-plugin/tests/fixtures/service-log-current-claude-code.bin +3624 -0
  536. package/telegram-plugin/tests/fleet-state-watcher.test.ts +101 -0
  537. package/telegram-plugin/tests/fleet-state.test.ts +185 -0
  538. package/telegram-plugin/tests/foreman-create-flow.test.ts +359 -0
  539. package/telegram-plugin/tests/foreman-handlers.test.ts +347 -0
  540. package/telegram-plugin/tests/foreman-state.test.ts +164 -0
  541. package/telegram-plugin/tests/foreman-write-ops.test.ts +214 -0
  542. package/telegram-plugin/tests/gateway-409-retry-banner.test.ts +173 -0
  543. package/telegram-plugin/tests/gateway-boot-marker-clear.test.ts +72 -0
  544. package/telegram-plugin/tests/gateway-bridge.test.ts +811 -0
  545. package/telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts +414 -0
  546. package/telegram-plugin/tests/gateway-disconnect-flush.test.ts +144 -0
  547. package/telegram-plugin/tests/gateway-message-validator.test.ts +133 -0
  548. package/telegram-plugin/tests/gateway-no-reply-single-emit.test.ts +103 -0
  549. package/telegram-plugin/tests/gateway-secret-detect.test.ts +127 -0
  550. package/telegram-plugin/tests/gateway-startup-mutex.test.ts +284 -0
  551. package/telegram-plugin/tests/gateway-startup-network-retry.test.ts +185 -0
  552. package/telegram-plugin/tests/gateway-startup-reset.test.ts +72 -0
  553. package/telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts +125 -0
  554. package/telegram-plugin/tests/handoff-continuity.test.ts +249 -0
  555. package/telegram-plugin/tests/harness-ordering-invariants.test.ts +243 -0
  556. package/telegram-plugin/tests/harness-parse-mode-validation.test.ts +114 -0
  557. package/telegram-plugin/tests/history.test.ts +364 -0
  558. package/telegram-plugin/tests/html-balanced.ts +63 -0
  559. package/telegram-plugin/tests/html-sanitize.test.ts +146 -0
  560. package/telegram-plugin/tests/idle-footer-wiring.test.ts +88 -0
  561. package/telegram-plugin/tests/idle-footer.test.ts +66 -0
  562. package/telegram-plugin/tests/inbound-coalesce.test.ts +127 -0
  563. package/telegram-plugin/tests/inline-keyboard-callbacks.test.ts +150 -0
  564. package/telegram-plugin/tests/interrupt-marker.test.ts +126 -0
  565. package/telegram-plugin/tests/ipc-protocol.test.ts +218 -0
  566. package/telegram-plugin/tests/ipc-server-anonymous-refuse.test.ts +82 -0
  567. package/telegram-plugin/tests/ipc-server-client.test.ts +323 -0
  568. package/telegram-plugin/tests/ipc-server-race.test.ts +183 -0
  569. package/telegram-plugin/tests/ipc-server-validate-operator.test.ts +91 -0
  570. package/telegram-plugin/tests/ipc-server-validate-pty-partial.test.ts +64 -0
  571. package/telegram-plugin/tests/ipc-server-validate-update-placeholder.test.ts +77 -0
  572. package/telegram-plugin/tests/ipc-validator.test.ts +274 -0
  573. package/telegram-plugin/tests/issues-card.test.ts +495 -0
  574. package/telegram-plugin/tests/issues-watcher.test.ts +165 -0
  575. package/telegram-plugin/tests/model-unavailable.test.ts +303 -0
  576. package/telegram-plugin/tests/multi-turn-continuity.test.ts +159 -0
  577. package/telegram-plugin/tests/operator-events-history.test.ts +125 -0
  578. package/telegram-plugin/tests/operator-events-session-tail.test.ts +192 -0
  579. package/telegram-plugin/tests/operator-events.test.ts +331 -0
  580. package/telegram-plugin/tests/outbound-ordering.test.ts +293 -0
  581. package/telegram-plugin/tests/parse-mode-rotation.test.ts +164 -0
  582. package/telegram-plugin/tests/permission-rule.test.ts +121 -0
  583. package/telegram-plugin/tests/permission-title.test.ts +106 -0
  584. package/telegram-plugin/tests/pin-event-log.test.ts +124 -0
  585. package/telegram-plugin/tests/plugin-logger.test.ts +97 -0
  586. package/telegram-plugin/tests/poll-health.test.ts +86 -0
  587. package/telegram-plugin/tests/preamble-suppressor.test.ts +285 -0
  588. package/telegram-plugin/tests/progress-card-api-failure-during-deferred.test.ts +73 -0
  589. package/telegram-plugin/tests/progress-card-close-paths-converge.test.ts +272 -0
  590. package/telegram-plugin/tests/progress-card-cross-turn.test.ts +258 -0
  591. package/telegram-plugin/tests/progress-card-dispose-preservepending.test.ts +81 -0
  592. package/telegram-plugin/tests/progress-card-draft-flag.test.ts +80 -0
  593. package/telegram-plugin/tests/progress-card-driver-eviction.test.ts +215 -0
  594. package/telegram-plugin/tests/progress-card-driver-fleet-shadow.test.ts +123 -0
  595. package/telegram-plugin/tests/progress-card-driver-force-complete-parent-done.test.ts +76 -0
  596. package/telegram-plugin/tests/progress-card-edit-timestamps-budget.test.ts +62 -0
  597. package/telegram-plugin/tests/progress-card-memory-bounds.test.ts +84 -0
  598. package/telegram-plugin/tests/progress-card-pin-failure-paths.test.ts +139 -0
  599. package/telegram-plugin/tests/progress-card-pin-manager.test.ts +773 -0
  600. package/telegram-plugin/tests/progress-card-pin-race-fast-turn.test.ts +66 -0
  601. package/telegram-plugin/tests/progress-card-pin-sidecar-partial-write.test.ts +64 -0
  602. package/telegram-plugin/tests/progress-card-pin-watchdog.test.ts +190 -0
  603. package/telegram-plugin/tests/progress-card-sigterm-pin-flush.test.ts +146 -0
  604. package/telegram-plugin/tests/progress-update.test.ts +236 -0
  605. package/telegram-plugin/tests/protocol-fixtures.test.ts +59 -0
  606. package/telegram-plugin/tests/protocol-fixtures.ts +198 -0
  607. package/telegram-plugin/tests/pty-partial-handler.test.ts +326 -0
  608. package/telegram-plugin/tests/pty-tail-real-fixture.test.ts +114 -0
  609. package/telegram-plugin/tests/pty-tail-tmux-fragment.test.ts +71 -0
  610. package/telegram-plugin/tests/pty-tail.test.ts +525 -0
  611. package/telegram-plugin/tests/quota-cache.test.ts +187 -0
  612. package/telegram-plugin/tests/quota-check.test.ts +622 -0
  613. package/telegram-plugin/tests/races.test.ts +842 -0
  614. package/telegram-plugin/tests/real-gateway-f1-ladder-integrity.test.ts +123 -0
  615. package/telegram-plugin/tests/real-gateway-f2-instant-draft.test.ts +82 -0
  616. package/telegram-plugin/tests/real-gateway-f3-late-card.test.ts +114 -0
  617. package/telegram-plugin/tests/real-gateway-harness.ts +699 -0
  618. package/telegram-plugin/tests/real-gateway-i6-turn-flush-replay-dedup.test.ts +313 -0
  619. package/telegram-plugin/tests/real-gateway-ipc-lifecycle.test.ts +299 -0
  620. package/telegram-plugin/tests/real-gateway-spec.test.ts +487 -0
  621. package/telegram-plugin/tests/real-gateway.smoke.test.ts +101 -0
  622. package/telegram-plugin/tests/recent-outbound-dedup.test.ts +192 -0
  623. package/telegram-plugin/tests/registry-turns.test.ts +432 -0
  624. package/telegram-plugin/tests/reply-terminal-reaction.test.ts +149 -0
  625. package/telegram-plugin/tests/resolve-calling-subagent.test.ts +269 -0
  626. package/telegram-plugin/tests/restart-watchdog.test.ts +224 -0
  627. package/telegram-plugin/tests/retry-api-call.test.ts +287 -0
  628. package/telegram-plugin/tests/secret-detect-audit.test.ts +58 -0
  629. package/telegram-plugin/tests/secret-detect-fail-closed.test.ts +83 -0
  630. package/telegram-plugin/tests/secret-detect-gitleaks.test.ts +32 -0
  631. package/telegram-plugin/tests/secret-detect-oauth-code.test.ts +308 -0
  632. package/telegram-plugin/tests/secret-detect-pipeline.test.ts +123 -0
  633. package/telegram-plugin/tests/secret-detect-secretlint.test.ts +101 -0
  634. package/telegram-plugin/tests/secret-detect-staging.test.ts +45 -0
  635. package/telegram-plugin/tests/secret-detect-suppressor-no-silent-allow.test.ts +67 -0
  636. package/telegram-plugin/tests/secret-detect.test.ts +223 -0
  637. package/telegram-plugin/tests/secret-guard-pretool.test.ts +194 -0
  638. package/telegram-plugin/tests/send-typing-action-validation.test.ts +61 -0
  639. package/telegram-plugin/tests/session-tail-capped.test.ts +285 -0
  640. package/telegram-plugin/tests/session-tail.test.ts +524 -0
  641. package/telegram-plugin/tests/setup-flow.test.ts +510 -0
  642. package/telegram-plugin/tests/setup-state.test.ts +146 -0
  643. package/telegram-plugin/tests/silent-reply-guard.test.ts +122 -0
  644. package/telegram-plugin/tests/slot-banner-driver.e2e.test.ts +350 -0
  645. package/telegram-plugin/tests/slot-banner.test.ts +74 -0
  646. package/telegram-plugin/tests/snapshot-serializer.ts +79 -0
  647. package/telegram-plugin/tests/spawn-detached-cgroup-escape.test.ts +51 -0
  648. package/telegram-plugin/tests/status-accent.test.ts +186 -0
  649. package/telegram-plugin/tests/status-reactions-allowed-filter.test.ts +132 -0
  650. package/telegram-plugin/tests/status-reactions.test.ts +314 -0
  651. package/telegram-plugin/tests/steering.test.ts +282 -0
  652. package/telegram-plugin/tests/sticker-aliases.test.ts +232 -0
  653. package/telegram-plugin/tests/stream-controller-html-fallback.test.ts +127 -0
  654. package/telegram-plugin/tests/stream-controller.test.ts +262 -0
  655. package/telegram-plugin/tests/stream-reply-error-paths.test.ts +208 -0
  656. package/telegram-plugin/tests/stream-reply-handler.test.ts +1292 -0
  657. package/telegram-plugin/tests/streaming-e2e.test.ts +389 -0
  658. package/telegram-plugin/tests/streaming-metrics.test.ts +201 -0
  659. package/telegram-plugin/tests/streaming-orchestration.test.ts +756 -0
  660. package/telegram-plugin/tests/subagent-registry-bugs.test.ts +725 -0
  661. package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +213 -0
  662. package/telegram-plugin/tests/subagent-watcher-parent-marker.test.ts +274 -0
  663. package/telegram-plugin/tests/subagent-watcher-stall-notification.test.ts +243 -0
  664. package/telegram-plugin/tests/subagent-watcher.test.ts +877 -0
  665. package/telegram-plugin/tests/subagents-schema-init-order.test.ts +109 -0
  666. package/telegram-plugin/tests/sync-chat-running-subagents.test.ts +116 -0
  667. package/telegram-plugin/tests/telegram-button-constraints.test.ts +194 -0
  668. package/telegram-plugin/tests/telegram-format.test.ts +1093 -0
  669. package/telegram-plugin/tests/telegraph.test.ts +246 -0
  670. package/telegram-plugin/tests/tool-labels.test.ts +383 -0
  671. package/telegram-plugin/tests/turn-active-marker.test.ts +195 -0
  672. package/telegram-plugin/tests/turn-end-regressions.test.ts +489 -0
  673. package/telegram-plugin/tests/turn-flush-card-takeover.test.ts +218 -0
  674. package/telegram-plugin/tests/turn-flush-dedup-controller.test.ts +144 -0
  675. package/telegram-plugin/tests/turn-flush-prose-recovery.test.ts +78 -0
  676. package/telegram-plugin/tests/turn-flush-safety.test.ts +189 -0
  677. package/telegram-plugin/tests/turn-signal-tracker.test.ts +107 -0
  678. package/telegram-plugin/tests/turns-writer.test.ts +323 -0
  679. package/telegram-plugin/tests/two-zone-bg-carry-full-lifecycle.test.ts +131 -0
  680. package/telegram-plugin/tests/two-zone-bg-detection.test.ts +120 -0
  681. package/telegram-plugin/tests/two-zone-bg-done-when-all-terminal.test.ts +114 -0
  682. package/telegram-plugin/tests/two-zone-bg-early-turn-end.test.ts +87 -0
  683. package/telegram-plugin/tests/two-zone-bg-survives-next-turn.test.ts +211 -0
  684. package/telegram-plugin/tests/two-zone-card-cap.test.ts +62 -0
  685. package/telegram-plugin/tests/two-zone-card-fleet-row.test.ts +101 -0
  686. package/telegram-plugin/tests/two-zone-card-header-phases.test.ts +68 -0
  687. package/telegram-plugin/tests/two-zone-card-html-balance.test.ts +110 -0
  688. package/telegram-plugin/tests/two-zone-card-lifecycle.test.ts +128 -0
  689. package/telegram-plugin/tests/two-zone-card-sanitise.test.ts +58 -0
  690. package/telegram-plugin/tests/two-zone-card-snapshot.test.ts +133 -0
  691. package/telegram-plugin/tests/two-zone-concurrent-turns-isolation.test.ts +155 -0
  692. package/telegram-plugin/tests/two-zone-phasefor-precedence.test.ts +117 -0
  693. package/telegram-plugin/tests/two-zone-snapshot-extras.test.ts +143 -0
  694. package/telegram-plugin/tests/two-zone-stuck-edit-throttle.test.ts +149 -0
  695. package/telegram-plugin/tests/two-zone-stuck-header-escalation.test.ts +101 -0
  696. package/telegram-plugin/tests/two-zone-stuck-per-member.test.ts +114 -0
  697. package/telegram-plugin/tests/two-zone-stuck-recovery.test.ts +105 -0
  698. package/telegram-plugin/tests/typing-wrap.test.ts +141 -0
  699. package/telegram-plugin/tests/unhandled-rejection-policy.test.ts +147 -0
  700. package/telegram-plugin/tests/update-factory-edited-and-reactions.test.ts +108 -0
  701. package/telegram-plugin/tests/update-factory.ts +305 -0
  702. package/telegram-plugin/tests/vault-grant-wizard.test.ts +84 -0
  703. package/telegram-plugin/tests/vault-grants-revoke.test.ts +265 -0
  704. package/telegram-plugin/tests/vault-subcommands.test.ts +234 -0
  705. package/telegram-plugin/tests/voice-transcribe.test.ts +196 -0
  706. package/telegram-plugin/tests/waiting-ux-harness.ts +381 -0
  707. package/telegram-plugin/tests/waiting-ux.e2e.test.ts +233 -0
  708. package/telegram-plugin/tests/welcome-text.test.ts +407 -0
  709. package/telegram-plugin/tool-error-filter.ts +89 -0
  710. package/telegram-plugin/tool-labels.ts +330 -0
  711. package/telegram-plugin/tool-names.ts +53 -0
  712. package/telegram-plugin/turn-flush-prose-recovery.ts +40 -0
  713. package/telegram-plugin/turn-flush-safety.ts +109 -0
  714. package/telegram-plugin/turn-signal-tracker.ts +79 -0
  715. package/telegram-plugin/two-zone-card.ts +249 -0
  716. package/telegram-plugin/typing-wrap.ts +92 -0
  717. package/telegram-plugin/voice-transcribe.ts +166 -0
  718. package/telegram-plugin/welcome-text.ts +359 -0
@@ -0,0 +1,582 @@
1
+ /**
2
+ * Boot card — posts a quiet, contextual ack at gateway startup. Closes
3
+ * #60 and is PR 1 of 3 in #142's "telegram surfaces: quiet, contextual
4
+ * cards" workstream.
5
+ *
6
+ * Default state is a single line: `✅ <agent> back up · <version>`.
7
+ *
8
+ * Probes still run, but only at a settle window (6s by default) — long
9
+ * enough that systemd transients (`deactivating`, `activating`, crons
10
+ * mid-re-register) self-heal before any row could surface. If after the
11
+ * settle a probe is genuinely degraded or failed, the card edits to
12
+ * append a row for THAT probe only. Healthy probes never produce rows.
13
+ *
14
+ * What's deleted (relative to pre-#142):
15
+ * - The always-rendered six-row checklist (Account/Agent/Gateway/
16
+ * Quota/Hindsight/Crons) — all replaced by the silent-when-healthy
17
+ * contract.
18
+ * - The skeleton "probing…" placeholder edit dance — the immediate
19
+ * post is now the final post for healthy boots.
20
+ * - The session-greeting card written by scaffold.ts (~750 lines of
21
+ * curl + heredoc bash that baked Profile/Tools/Skills/Limits/
22
+ * Channel/Memory at scaffold time and re-posted on every
23
+ * SessionStart). That content moves to the future `/status`
24
+ * command (PR 3).
25
+ *
26
+ * What's kept:
27
+ * - The probe layer in `boot-probes.ts` — same probe set, same shapes,
28
+ * same defensive-against-throw discipline.
29
+ * - `BotApiForBootCard` / `BootCardHandle` / dedupe gate
30
+ * (`shouldSkipDuplicateBootCard`) — public API stable for the
31
+ * gateway's two call sites (boot path + bridge-reconnect).
32
+ * - `BootCardHandle` / `complete()` (called from the first user-turn handler).
33
+ */
34
+
35
+ import type { ProbeResult, GatewayRuntimeInfo } from './boot-probes.js'
36
+ import type { AccountSummary } from '../auth-dashboard.js'
37
+ import { formatAccountQuotaLine } from '../auth-dashboard.js'
38
+ import {
39
+ probeAccount,
40
+ probeAgentProcess,
41
+ probeGateway,
42
+ probeQuota,
43
+ probeHindsight,
44
+ probeCronTimers,
45
+ watchAgentProcess,
46
+ AGENT_LIVE_WINDOW_MS,
47
+ AGENT_LIVE_POLL_INTERVAL_MS,
48
+ } from './boot-probes.js'
49
+ import { escapeHtml } from '../card-format.js'
50
+ import { join } from 'path'
51
+ import { loadConfig as _loadSwitchroomConfig } from '../../src/config/loader.js'
52
+
53
+ // ─── Persona name resolution ─────────────────────────────────────────────────
54
+
55
+ /**
56
+ * Resolve the display name for an agent from its config's soul.name field.
57
+ *
58
+ * The slug (e.g. "finn") is an operator-facing identifier: agent directory,
59
+ * systemd unit name, vault key prefix. It should never appear in
60
+ * user-facing Telegram output. soul.name (e.g. "Finn") is the persona
61
+ * the user knows through the bot username, topic emoji, and conversation.
62
+ *
63
+ * Falls back to the slug when:
64
+ * - soul is not set in the agent config
65
+ * - the agent key is not found in switchroom.yaml
66
+ * - the config cannot be loaded (gateway running outside a switchroom env)
67
+ *
68
+ * The optional `loadConfig` override exists purely for unit-test injection.
69
+ * Production callers pass no second argument and get the live config.
70
+ *
71
+ * Closes #169.
72
+ */
73
+ export function resolvePersonaName(
74
+ slug: string,
75
+ loadConfig?: () => { agents?: Record<string, { soul?: { name?: string } | null }> } | null,
76
+ ): string {
77
+ try {
78
+ const config = loadConfig ? loadConfig() : _loadSwitchroomConfig()
79
+ const name = config?.agents?.[slug]?.soul?.name
80
+ return name && name.trim().length > 0 ? name : slug
81
+ } catch {
82
+ // Config unreadable (gateway running in a test env or outside a
83
+ // switchroom workspace). Degrade gracefully to the slug.
84
+ return slug
85
+ }
86
+ }
87
+
88
+ // ─── Types ──────────────────────────────────────────────────────────────────
89
+
90
+ export type RestartReason = 'planned' | 'graceful' | 'crash' | 'fresh'
91
+
92
+ export type ProbeKey = 'account' | 'agent' | 'gateway' | 'quota' | 'hindsight' | 'crons'
93
+
94
+ export type ProbeMap = Partial<Record<ProbeKey, ProbeResult | null>>
95
+
96
+ export interface BotApiForBootCard {
97
+ sendMessage(
98
+ chatId: string,
99
+ text: string,
100
+ opts?: Record<string, unknown>,
101
+ ): Promise<{ message_id: number }>
102
+ editMessageText(
103
+ chatId: string,
104
+ messageId: number,
105
+ text: string,
106
+ opts?: Record<string, unknown>,
107
+ ): Promise<unknown>
108
+ }
109
+
110
+ export interface BootCardHandle {
111
+ messageId: number
112
+ /** Call when the first user turn starts. */
113
+ complete(): void
114
+ }
115
+
116
+ export type BootCardSite = 'boot' | 'bridge-reconnect'
117
+
118
+ export interface BootCardGate {
119
+ /**
120
+ * Set after the boot path successfully posts a card. The bridge-reconnect
121
+ * path checks this to avoid posting a second card on the same gateway
122
+ * lifetime — observed in the wild as klanker msgId 2245 + 2248 within 5s
123
+ * (2026-04-26 11:19:47).
124
+ */
125
+ activeBootCard: { messageId: number } | null
126
+ /**
127
+ * True while a boot card emission is in-flight (sendMessage round-trip
128
+ * not yet resolved). Closes the race window where bridge-reconnect ran
129
+ * during the boot path's await and saw activeBootCard still null —
130
+ * observed as klanker msgId 4715 + 4716 (2026-05-01 10:13:15, issue #489).
131
+ * Optional for backward compatibility with callers that pre-date the flag.
132
+ */
133
+ bootCardPending?: boolean
134
+ }
135
+
136
+ export interface BootCardSkipDecision {
137
+ skip: boolean
138
+ /** Human-readable reason (only present when skip=true). */
139
+ reason?: string
140
+ }
141
+
142
+ /**
143
+ * Decide whether to skip posting the boot card based on gateway state.
144
+ *
145
+ * Two emit sites contend on every gateway lifetime:
146
+ *
147
+ * - `boot`: the gateway IIFE startup path (long: probes session
148
+ * marker, clean-shutdown marker, restart marker, etc).
149
+ * - `bridge-reconnect`: fires when the agent's IPC client connects
150
+ * to the gateway socket.
151
+ *
152
+ * Earlier versions of this gate special-cased `boot` as "primary"
153
+ * and let it post unconditionally. Empirically that assumption is
154
+ * wrong: when the agent process boots faster than the gateway IIFE
155
+ * reaches its emit, bridge-reconnect runs first, posts its card,
156
+ * and then boot fires its own card too — both with reason=graceful
157
+ * within ~100ms (observed in finn 2026-05-02: msgId 673 + 674
158
+ * with both `posted` log lines on consecutive lines).
159
+ *
160
+ * The fix is first-write-wins: whichever site fires first claims
161
+ * `bootCardPending` synchronously, posts the card, and releases.
162
+ * The other site sees pending or active and defers. Both sites'
163
+ * chat resolution is identical (same restart-marker / clean-shutdown
164
+ * / session-marker pipeline), so it doesn't matter which one wins.
165
+ */
166
+ export function shouldSkipDuplicateBootCard(
167
+ gate: BootCardGate,
168
+ site: BootCardSite,
169
+ ): BootCardSkipDecision {
170
+ if (gate.bootCardPending) {
171
+ return { skip: true, reason: `in-flight-other-site site=${site}` }
172
+ }
173
+ if (gate.activeBootCard != null) {
174
+ return {
175
+ skip: true,
176
+ reason: `already-posted-msgId=${gate.activeBootCard.messageId} site=${site}`,
177
+ }
178
+ }
179
+ return { skip: false }
180
+ }
181
+
182
+ // ─── Rendering ───────────────────────────────────────────────────────────────
183
+
184
+ /**
185
+ * Settle window before probes run. Long enough that systemd transients
186
+ * (`deactivating`/`activating`, dbus contention during reload, crons
187
+ * mid-re-register) self-heal so a transient red can't reach the user.
188
+ *
189
+ * Constant by design — not a config field. The issue is explicit:
190
+ * "Falls out of design, not a config knob." 6s is at the high end of the
191
+ * 5–7s range called out in #142 for headroom under load.
192
+ */
193
+ const SETTLE_WINDOW_MS = 6000
194
+
195
+ const DOT: Record<string, string> = {
196
+ ok: '🟢',
197
+ degraded: '🟡',
198
+ fail: '🔴',
199
+ }
200
+
201
+ const PROBE_LABELS: Record<ProbeKey, string> = {
202
+ account: 'Account',
203
+ agent: 'Agent',
204
+ gateway: 'Gateway',
205
+ quota: 'Quota',
206
+ hindsight: 'Hindsight',
207
+ crons: 'Crons',
208
+ }
209
+
210
+ const PROBE_KEYS: ReadonlyArray<ProbeKey> = [
211
+ 'account', 'agent', 'gateway', 'quota', 'hindsight', 'crons',
212
+ ]
213
+
214
+ const REASON_EMOJI: Record<RestartReason, string> = {
215
+ planned: '✅',
216
+ graceful: '✅',
217
+ crash: '⚠️',
218
+ fresh: '🆕',
219
+ }
220
+
221
+ const REASON_LABEL: Record<RestartReason, string> = {
222
+ planned: 'planned restart',
223
+ graceful: 'graceful restart',
224
+ crash: 'crash recovery',
225
+ fresh: 'fresh start',
226
+ }
227
+
228
+ export interface RenderBootCardOpts {
229
+ agentName: string
230
+ /** Pre-formatted version string, e.g. "v0.3.0+44" or "v0.3.0 · #143 · 2h ago". */
231
+ version: string
232
+ /** Probe results (only present after the settle window). When absent or
233
+ * empty, the card is the bare ack line — no probe rows. */
234
+ probes?: ProbeMap
235
+ /** What kind of restart this is. Crash flips the ack emoji to ⚠️ AND
236
+ * appends a "Crash recovery" row underneath. Other reasons just set
237
+ * the emoji. */
238
+ restartReason?: RestartReason
239
+ /** Age of the restart marker in ms — shown in the crash row. */
240
+ restartAgeMs?: number
241
+ /**
242
+ * Per-account quota snapshots to render below the probe rows.
243
+ * One line per enabled account showing 5h % / 7d % and the
244
+ * nearest reset countdown so users see headroom without running
245
+ * `/auth` or `/usage` after every restart.
246
+ *
247
+ * Empty / undefined hides the section entirely — preserves the
248
+ * silent-when-healthy contract for callers that don't pass account
249
+ * data (tests, harnesses, gateways without the auth model).
250
+ *
251
+ * Closes #708.
252
+ */
253
+ accounts?: ReadonlyArray<AccountSummary>
254
+ /** Clock injection point for tests; defaults to `new Date()`. */
255
+ now?: Date
256
+ }
257
+
258
+ /**
259
+ * Render the boot card. Single line by default; appends one row per
260
+ * fail/degraded probe (and one for crash recovery, if applicable).
261
+ *
262
+ * Healthy probes never produce a row. The ack line is sufficient — the
263
+ * user only needs to know the agent came back up. Anything red catches
264
+ * the eye; everything else stays out of the way.
265
+ */
266
+ export function renderBootCard(opts: RenderBootCardOpts): string {
267
+ const { agentName, version, probes, restartReason, restartAgeMs } = opts
268
+ const ackEmoji = restartReason ? REASON_EMOJI[restartReason] : '✅'
269
+ const ack = `${ackEmoji} <b>${escapeHtml(agentName)}</b> back up · ${escapeHtml(version)}`
270
+
271
+ const degradedRows: string[] = []
272
+
273
+ // Crash recovery: surface explicitly so the user can tell whether
274
+ // their next message will land on a fresh process. The agent-crashed
275
+ // operator event from #92/#147 is a separate notification surface;
276
+ // this row exists for users who only check the boot card.
277
+ if (restartReason === 'crash') {
278
+ const ageStr = restartAgeMs != null && restartAgeMs > 0
279
+ ? ` · ${(restartAgeMs / 1000).toFixed(1)}s ago`
280
+ : ''
281
+ degradedRows.push(`⚠️ <b>Restart</b> ${escapeHtml(REASON_LABEL.crash)}${ageStr}`)
282
+ }
283
+
284
+ // Probe rows — only those that surfaced as degraded/fail. Healthy
285
+ // (`ok`) probes don't render at all.
286
+ if (probes) {
287
+ for (const key of PROBE_KEYS) {
288
+ const r = probes[key]
289
+ if (!r) continue
290
+ if (r.status === 'ok') continue
291
+ const dot = DOT[r.status] ?? DOT.fail
292
+ degradedRows.push(`${dot} <b>${PROBE_LABELS[key]}</b> ${escapeHtml(r.detail)}`)
293
+ }
294
+ }
295
+
296
+ // Per-account quota section (issue #708) — one line per enabled
297
+ // account showing 5h % / 7d % / nearest reset, with the active
298
+ // account marked. Renders alongside the ack line so users see
299
+ // headroom without running /auth or /usage.
300
+ const accountRows = renderAccountRows(opts.accounts, opts.now ?? new Date())
301
+
302
+ const sections: string[] = [ack]
303
+ if (degradedRows.length > 0) sections.push('', ...degradedRows)
304
+ if (accountRows.length > 0) sections.push('', ...accountRows)
305
+ if (sections.length === 1) return ack
306
+ return sections.join('\n')
307
+ }
308
+
309
+ /**
310
+ * Render the per-account quota rows. Returns an empty array when no
311
+ * accounts are passed — keeping the boot card's silent-when-healthy
312
+ * default for callers that don't supply account data.
313
+ *
314
+ * Reuses the dashboard's `formatAccountQuotaLine` so the two surfaces
315
+ * speak with one voice.
316
+ */
317
+ export function renderAccountRows(
318
+ accounts: ReadonlyArray<AccountSummary> | undefined,
319
+ now: Date,
320
+ ): string[] {
321
+ if (!accounts || accounts.length === 0) return []
322
+ const rows: string[] = []
323
+ rows.push(`<b>Accounts (${accounts.length})</b>`)
324
+ const nowMs = now.getTime()
325
+ for (const a of accounts) {
326
+ const marker = a.activeForThisAgent ? '▶' : '↳'
327
+ const labelHtml = `<code>${escapeHtml(a.label)}</code>`
328
+ // formatAccountQuotaLine returns HTML (with <i> tags) so we don't
329
+ // re-escape — pass it through verbatim.
330
+ const quotaLine = formatAccountQuotaLine(a, nowMs)
331
+ rows.push(quotaLine ? `${marker} ${labelHtml} ${quotaLine}` : `${marker} ${labelHtml}`)
332
+ }
333
+ return rows
334
+ }
335
+
336
+ // ─── Probe orchestration ─────────────────────────────────────────────────────
337
+
338
+ export interface RunProbesOpts {
339
+ /** Persona display name — used only for rendering (ack line, probe rows). */
340
+ agentName: string
341
+ /** Lowercase systemd slug (e.g. "klanker") — used for systemctl unit targets.
342
+ * Must differ from agentName when the soul.name differs in case from the slug.
343
+ * Falls back to agentName when not provided (backwards-compat). */
344
+ agentSlug?: string
345
+ /** Pre-formatted version string passed through to the renderer. */
346
+ version: string
347
+ agentDir: string
348
+ gatewayInfo: GatewayRuntimeInfo
349
+ bankName?: string
350
+ /** Why the gateway is starting — feeds the ack-line emoji and the
351
+ * optional crash-recovery row. */
352
+ restartReason?: RestartReason
353
+ /** Age of the restart marker in ms — shown in the crash row. */
354
+ restartAgeMs?: number
355
+ /** Override fetch for tests. */
356
+ fetchImpl?: typeof fetch
357
+ /** Override settle window for tests; production uses SETTLE_WINDOW_MS. */
358
+ settleWindowMs?: number
359
+ /** Override setTimeout for tests. */
360
+ setTimeoutImpl?: typeof setTimeout
361
+ /**
362
+ * How long the live-agent-status loop keeps editing the card after the
363
+ * initial probe run. Defaults to AGENT_LIVE_WINDOW_MS (45s). Set to 0
364
+ * to disable the live loop entirely (e.g. in tests that only need the
365
+ * one-shot settle-window behaviour).
366
+ */
367
+ agentLiveWindowMs?: number
368
+ /** How often the live loop re-polls systemd. Defaults to
369
+ * AGENT_LIVE_POLL_INTERVAL_MS (2s). Override in tests for speed. */
370
+ agentLivePollIntervalMs?: number
371
+ /** Override for tests — replaces real execFile calls in the initial probe run
372
+ * (probeAgentProcess + probeCronTimers). Distinct from agentLiveExecFileImpl
373
+ * which covers the post-settle live-watch loop. */
374
+ probeExecFileImpl?: (cmd: string, args: string[]) => Promise<{ stdout: string; stderr: string }>
375
+ /** Override for tests — replaces real execFile calls in the live loop. */
376
+ agentLiveExecFileImpl?: (cmd: string, args: string[]) => Promise<{ stdout: string; stderr: string }>
377
+ /** Override for tests — replaces real delays in the live loop. */
378
+ agentLiveSleepImpl?: (ms: number) => Promise<void>
379
+ /**
380
+ * Loader for the per-account rows that get appended below the probe
381
+ * rows on the boot card (issue #708). Returns the account list
382
+ * synchronously or via a Promise; an empty array / null disables
383
+ * the section. Skipped on the immediate ack post — only consulted
384
+ * during the post-settle re-render so the first paint stays fast.
385
+ */
386
+ loadAccounts?: () =>
387
+ | ReadonlyArray<AccountSummary>
388
+ | null
389
+ | Promise<ReadonlyArray<AccountSummary> | null>
390
+ /** When true, resolve the agent PID via cgroup walk instead of MainPID
391
+ * (which is the tmux server pid under tmux supervisor). */
392
+ tmuxSupervisor?: boolean
393
+ }
394
+
395
+ /** Run all six probes concurrently with their own per-probe timeouts.
396
+ * Used by both the production startBootCard flow and any caller that
397
+ * wants the probe set without the post/edit dance. */
398
+ export async function runAllProbes(opts: RunProbesOpts): Promise<ProbeMap> {
399
+ const claudeDir = join(opts.agentDir, '.claude')
400
+ const probes: ProbeMap = {}
401
+ // Use the explicit slug for systemd unit targets; fall back to agentName for
402
+ // callers that haven't been updated yet (backwards-compat).
403
+ const slug = opts.agentSlug ?? opts.agentName
404
+
405
+ await Promise.allSettled([
406
+ probeAccount(opts.agentDir).then(r => { probes.account = r }),
407
+ probeAgentProcess(slug, { execFileImpl: opts.probeExecFileImpl, tmuxSupervisor: opts.tmuxSupervisor }).then(r => { probes.agent = r }),
408
+ probeGateway(opts.gatewayInfo).then(r => { probes.gateway = r }),
409
+ probeQuota(claudeDir, opts.agentDir, opts.fetchImpl).then(r => { probes.quota = r }),
410
+ probeHindsight(opts.bankName, opts.fetchImpl).then(r => { probes.hindsight = r }),
411
+ probeCronTimers(slug, { execFileImpl: opts.probeExecFileImpl }).then(r => { probes.crons = r }),
412
+ ])
413
+
414
+ return probes
415
+ }
416
+
417
+ /** Post the boot card, then run probes after a settle window and edit
418
+ * the card in-place if any probe came back degraded/failed. Healthy
419
+ * boots stay as the bare ack line forever.
420
+ *
421
+ * Returns a handle. The probe edit
422
+ * is fire-and-forget — failures are swallowed so the ack line is never
423
+ * rolled back to a worse state. */
424
+ export async function startBootCard(
425
+ chatId: string,
426
+ threadId: number | undefined,
427
+ bot: BotApiForBootCard,
428
+ opts: RunProbesOpts,
429
+ ackMessageId?: number,
430
+ log?: (line: string) => void,
431
+ ): Promise<BootCardHandle> {
432
+ const logger = log ?? ((l: string) => process.stderr.write(l))
433
+ const setTimeoutFn = opts.setTimeoutImpl ?? setTimeout
434
+ const settleMs = opts.settleWindowMs ?? SETTLE_WINDOW_MS
435
+
436
+ // Render and post the bare ack line immediately. The user gets
437
+ // confirmation that the agent is back without waiting on probes.
438
+ const ackText = renderBootCard({
439
+ agentName: opts.agentName,
440
+ version: opts.version,
441
+ restartReason: opts.restartReason,
442
+ restartAgeMs: opts.restartAgeMs,
443
+ })
444
+
445
+ let messageId: number
446
+ try {
447
+ const sent = await bot.sendMessage(chatId, ackText, {
448
+ parse_mode: 'HTML',
449
+ link_preview_options: { is_disabled: true },
450
+ ...(threadId != null ? { message_thread_id: threadId } : {}),
451
+ ...(ackMessageId != null ? { reply_parameters: { message_id: ackMessageId } } : {}),
452
+ })
453
+ messageId = sent.message_id
454
+ logger(`telegram gateway: boot-card: posted msgId=${messageId} chatId=${chatId} reason=${opts.restartReason ?? '-'}\n`)
455
+ } catch (err: unknown) {
456
+ logger(`telegram gateway: boot-card: failed to post ack: ${(err as Error)?.message ?? String(err)}\n`)
457
+ return { messageId: -1, complete: () => {} }
458
+ }
459
+
460
+ // Determine the live window for agent-service status updates. Callers
461
+ // can pass 0 to disable the live loop (e.g. in tests that only need
462
+ // the one-shot settle-window behaviour). Defaults to AGENT_LIVE_WINDOW_MS.
463
+ const liveWindowMs = opts.agentLiveWindowMs ?? AGENT_LIVE_WINDOW_MS
464
+
465
+ // Schedule the post-settle probe run + live agent-status loop. Wrapped
466
+ // in setTimeout so the boot path returns the handle immediately — the
467
+ // gateway can continue setup without waiting on probes.
468
+ setTimeoutFn(() => {
469
+ void (async () => {
470
+ try {
471
+ // ── Phase 1: one-shot probe run after the settle window ───────────
472
+ // Run all probes concurrently. If the agent probe comes back ok at
473
+ // this point, no live loop is needed. If it's degraded/fail we
474
+ // start the live watch (Phase 2) to keep updating the card.
475
+ const probes = await runAllProbes(opts)
476
+
477
+ // Per-account rows (issue #708). Loaded best-effort
478
+ // alongside probes; failures are swallowed so the card still
479
+ // renders correctly with no accounts section.
480
+ let accountRows: ReadonlyArray<AccountSummary> | null = null
481
+ if (opts.loadAccounts) {
482
+ try {
483
+ accountRows = await opts.loadAccounts()
484
+ } catch (loadErr: unknown) {
485
+ logger(
486
+ `telegram gateway: boot-card: loadAccounts failed: ${
487
+ (loadErr as Error)?.message ?? String(loadErr)
488
+ }\n`,
489
+ )
490
+ }
491
+ }
492
+
493
+ // Render with current probe state and edit if anything changed.
494
+ let currentText = renderBootCard({
495
+ agentName: opts.agentName,
496
+ version: opts.version,
497
+ probes,
498
+ restartReason: opts.restartReason,
499
+ restartAgeMs: opts.restartAgeMs,
500
+ ...(accountRows ? { accounts: accountRows } : {}),
501
+ })
502
+
503
+ if (currentText !== ackText) {
504
+ try {
505
+ await bot.editMessageText(chatId, messageId, currentText, {
506
+ parse_mode: 'HTML',
507
+ link_preview_options: { is_disabled: true },
508
+ ...(threadId != null ? { message_thread_id: threadId } : {}),
509
+ })
510
+ logger(`telegram gateway: boot-card: probes settled with degraded rows msgId=${messageId}\n`)
511
+ } catch (editErr: unknown) {
512
+ logger(`telegram gateway: boot-card: probe-edit error msgId=${messageId}: ${(editErr as Error)?.message ?? String(editErr)}\n`)
513
+ }
514
+ } else {
515
+ logger(`telegram gateway: boot-card: probes settled all-green msgId=${messageId}\n`)
516
+ }
517
+
518
+ // ── Phase 2: live agent-status watch loop ─────────────────────────
519
+ // If the agent probe is already ok, no need to keep watching.
520
+ if (probes.agent?.status === 'ok' || liveWindowMs <= 0) {
521
+ return
522
+ }
523
+
524
+ // Iterate watchAgentProcess — it yields on each meaningful state
525
+ // change and exits when active, failed, or the window expires.
526
+ // Use the slug for the systemd unit target, not the display name.
527
+ const watcher = watchAgentProcess(opts.agentSlug ?? opts.agentName, {
528
+ liveWindowMs,
529
+ pollIntervalMs: opts.agentLivePollIntervalMs,
530
+ sleepImpl: opts.agentLiveSleepImpl,
531
+ execFileImpl: opts.agentLiveExecFileImpl,
532
+ tmuxSupervisor: opts.tmuxSupervisor,
533
+ })
534
+
535
+ for await (const agentResult of watcher) {
536
+ // Merge the new agent result into the probes snapshot so all
537
+ // probe rows are re-rendered consistently.
538
+ const updatedProbes: ProbeMap = { ...probes, agent: agentResult }
539
+ const updatedText = renderBootCard({
540
+ agentName: opts.agentName,
541
+ version: opts.version,
542
+ probes: updatedProbes,
543
+ restartReason: opts.restartReason,
544
+ restartAgeMs: opts.restartAgeMs,
545
+ ...(accountRows ? { accounts: accountRows } : {}),
546
+ })
547
+
548
+ if (updatedText === currentText) continue
549
+
550
+ try {
551
+ await bot.editMessageText(chatId, messageId, updatedText, {
552
+ parse_mode: 'HTML',
553
+ link_preview_options: { is_disabled: true },
554
+ ...(threadId != null ? { message_thread_id: threadId } : {}),
555
+ })
556
+ logger(`telegram gateway: boot-card: live agent update msgId=${messageId} state=${agentResult.status} "${agentResult.detail}"\n`)
557
+ currentText = updatedText
558
+ } catch (editErr: unknown) {
559
+ // Swallow edit errors — the card may have been deleted or the
560
+ // user dismissed it. Don't let this crash the whole loop.
561
+ logger(`telegram gateway: boot-card: live edit error msgId=${messageId}: ${(editErr as Error)?.message ?? String(editErr)}\n`)
562
+ }
563
+
564
+ // Once agent is active (ok), we're done — no more edits needed.
565
+ if (agentResult.status === 'ok') break
566
+ }
567
+ } catch (err: unknown) {
568
+ logger(`telegram gateway: boot-card: probe-edit error msgId=${messageId}: ${(err as Error)?.message ?? String(err)}\n`)
569
+ }
570
+ })()
571
+ }, settleMs)
572
+
573
+ let completed = false
574
+ return {
575
+ messageId,
576
+ complete() {
577
+ if (completed) return
578
+ completed = true
579
+ logger(`telegram gateway: boot-card: completed msgId=${messageId}\n`)
580
+ },
581
+ }
582
+ }