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,215 @@
1
+ /**
2
+ * Regression: TTL eviction of internal dedup maps must NOT depend on the
3
+ * heartbeat tick. The heartbeat stops whenever `chats.size === 0`, so any
4
+ * eviction inside it leaves `seenEnqueueMsgIds` and `pendingSyncEchoes` to
5
+ * grow unbounded across idle periods. Outer-base-key entries
6
+ * (`chatRunningSubagents`, `baseTurnSeqs`) likewise need an explicit
7
+ * cleanup hook on chat-close because nothing else ever drops them.
8
+ *
9
+ * Fix shape: an inline throttled `maybeEvict(now)` runs at the top of
10
+ * every public ingress, and `completeTurnFully` calls
11
+ * `cleanupBaseKeyIfUnused` after `chats.delete`.
12
+ */
13
+ import { describe, it, expect } from 'vitest'
14
+ import { createProgressDriver } from '../progress-card-driver.js'
15
+ import type { SessionEvent } from '../session-tail.js'
16
+
17
+ let nextMsgId = 9000
18
+
19
+ function harness() {
20
+ let now = 1000
21
+ const timers: Array<{ fireAt: number; fn: () => void; ref: number; repeat?: number }> = []
22
+ let nextRef = 0
23
+ const emits: Array<{ chatId: string; threadId?: string; turnKey: string; html: string; done: boolean }> = []
24
+
25
+ const driver = createProgressDriver({
26
+ emit: (a) => emits.push(a),
27
+ minIntervalMs: 0,
28
+ coalesceMs: 0,
29
+ initialDelayMs: 0,
30
+ heartbeatMs: 5000,
31
+ now: () => now,
32
+ setTimeout: (fn, ms) => {
33
+ const ref = nextRef++
34
+ timers.push({ fireAt: now + ms, fn, ref })
35
+ return { ref }
36
+ },
37
+ clearTimeout: (handle) => {
38
+ const target = (handle as { ref: number }).ref
39
+ const idx = timers.findIndex((t) => t.ref === target)
40
+ if (idx !== -1) timers.splice(idx, 1)
41
+ },
42
+ setInterval: (fn, ms) => {
43
+ const ref = nextRef++
44
+ timers.push({ fireAt: now + ms, fn, ref, repeat: ms })
45
+ return { ref }
46
+ },
47
+ clearInterval: (handle) => {
48
+ const target = (handle as { ref: number }).ref
49
+ const idx = timers.findIndex((t) => t.ref === target)
50
+ if (idx !== -1) timers.splice(idx, 1)
51
+ },
52
+ })
53
+
54
+ const advance = (ms: number): void => {
55
+ now += ms
56
+ for (;;) {
57
+ timers.sort((a, b) => a.fireAt - b.fireAt)
58
+ const next = timers[0]
59
+ if (!next || next.fireAt > now) break
60
+ if (next.repeat != null) {
61
+ next.fireAt += next.repeat
62
+ next.fn()
63
+ } else {
64
+ timers.shift()
65
+ next.fn()
66
+ }
67
+ }
68
+ }
69
+
70
+ return { driver, emits, advance, getNow: () => now }
71
+ }
72
+
73
+ function enqueue(chatId: string, threadId?: string): SessionEvent {
74
+ return {
75
+ kind: 'enqueue',
76
+ chatId,
77
+ messageId: String(nextMsgId++),
78
+ threadId: threadId ?? null,
79
+ rawContent: `<channel chat_id="${chatId}">hi</channel>`,
80
+ }
81
+ }
82
+
83
+ describe('progress-card-driver: TTL eviction off the heartbeat', () => {
84
+ it('seenEnqueueMsgIds and pendingSyncEchoes stay bounded across idle periods (chats.size==0)', () => {
85
+ const { driver, advance } = harness()
86
+ const maps = driver._debugGetMaps!()
87
+
88
+ // Drive 20 turn enqueue->complete cycles, advancing past the 60s TTL
89
+ // between cycles. Critically, chats.size returns to 0 between cycles,
90
+ // so the heartbeat stops — exposing the leak the fix targets.
91
+ for (let i = 0; i < 20; i++) {
92
+ driver.ingest(enqueue('chatA'), null)
93
+ driver.ingest({ kind: 'turn_end', durationMs: 100 }, 'chatA')
94
+ // Advance well past both TTLs (60s for messageIds, 30s for echoes)
95
+ // and past the eviction throttle (30s) so the next ingest evicts.
96
+ advance(65_000)
97
+ expect(maps.chats.size).toBe(0)
98
+ }
99
+
100
+ // After 20 cycles spread across >20 minutes of fake time, both dedup
101
+ // maps must be tiny — they should never accumulate stale entries.
102
+ expect(maps.seenEnqueueMsgIds.size).toBeLessThanOrEqual(1)
103
+ expect(maps.pendingSyncEchoes.size).toBeLessThanOrEqual(1)
104
+ })
105
+
106
+ it('chatRunningSubagents and baseTurnSeqs drop their base-key on full chat close', () => {
107
+ const { driver, advance } = harness()
108
+ const maps = driver._debugGetMaps!()
109
+
110
+ for (let i = 0; i < 20; i++) {
111
+ driver.ingest(enqueue('chatA'), null)
112
+ driver.ingest({ kind: 'sub_agent_started', agentId: `agent-${i}`, firstPromptText: 'x' }, 'chatA')
113
+ driver.ingest({ kind: 'sub_agent_turn_end', agentId: `agent-${i}`, durationMs: 50 }, 'chatA')
114
+ driver.ingest({ kind: 'turn_end', durationMs: 100 }, 'chatA')
115
+ advance(65_000)
116
+ // Between turns, no chat is alive — outer base-key entries must be
117
+ // gone too.
118
+ expect(maps.chats.size).toBe(0)
119
+ expect(maps.chatRunningSubagents.size).toBe(0)
120
+ expect(maps.baseTurnSeqs.size).toBe(0)
121
+ }
122
+ })
123
+
124
+ it('two chats sharing a baseKey: closing one does NOT delete the shared outer key', () => {
125
+ // baseKey collapses (chatId, threadId) pairs with no thread to a single
126
+ // string. Two threads on the same chat share a base only if they have
127
+ // the same threadId; two distinct chatIds always have distinct bases.
128
+ // Within a single chat, multiple concurrent turn-keys share the same
129
+ // base — closing one of them must NOT prematurely drop the outer key
130
+ // while the other turn is still alive.
131
+ const { driver } = harness()
132
+ const maps = driver._debugGetMaps!()
133
+
134
+ // Start turn 1 on chatA — synthesises an enqueue and creates the card.
135
+ driver.startTurn({ chatId: 'chatA', userText: 'first' })
136
+ expect(maps.chats.size).toBe(1)
137
+ expect(maps.baseTurnSeqs.get('chatA')).toBeGreaterThanOrEqual(1)
138
+
139
+ // A second startTurn on the same chat force-closes turn 1 and creates
140
+ // turn 2 — there is exactly one chat live again, but baseTurnSeqs has
141
+ // ticked to 2. That outer entry must remain because turn 2 is alive.
142
+ driver.startTurn({ chatId: 'chatA', userText: 'second' })
143
+ expect(maps.chats.size).toBe(1)
144
+ const seqAfter = maps.baseTurnSeqs.get('chatA')
145
+ expect(seqAfter).toBeGreaterThanOrEqual(2)
146
+
147
+ // End turn 2 → chats empty → base-key cleanup must run.
148
+ driver.ingest({ kind: 'turn_end', durationMs: 100 }, 'chatA')
149
+ expect(maps.chats.size).toBe(0)
150
+ expect(maps.baseTurnSeqs.has('chatA')).toBe(false)
151
+ expect(maps.chatRunningSubagents.has('chatA')).toBe(false)
152
+ })
153
+
154
+ it('two distinct chats: closing one does NOT touch the other base-key', () => {
155
+ // The driver routes turn_end via `currentTurnKey`, not `chatIdMaybe` —
156
+ // a quirk of the session-tail single-stream design. To close a specific
157
+ // chat from a test we use `forceCompleteTurn`, which is the path the
158
+ // gateway invokes for explicit per-chat fan-out.
159
+ const { driver } = harness()
160
+ const maps = driver._debugGetMaps!()
161
+
162
+ driver.ingest(enqueue('chatA'), null)
163
+ driver.ingest(enqueue('chatB'), null)
164
+ expect(maps.chats.size).toBe(2)
165
+ expect(maps.baseTurnSeqs.has('chatA')).toBe(true)
166
+ expect(maps.baseTurnSeqs.has('chatB')).toBe(true)
167
+
168
+ // Close A only — must not touch chatB's base-key.
169
+ driver.forceCompleteTurn({ chatId: 'chatA' })
170
+ expect(maps.baseTurnSeqs.has('chatA')).toBe(false)
171
+ expect(maps.baseTurnSeqs.has('chatB')).toBe(true)
172
+
173
+ // Now close B.
174
+ driver.forceCompleteTurn({ chatId: 'chatB' })
175
+ expect(maps.baseTurnSeqs.has('chatB')).toBe(false)
176
+ expect(maps.chats.size).toBe(0)
177
+ })
178
+
179
+ it('PR-C2 follow-up: bg-subagent-carry guard — chatRunningSubagents inner map survives turn_end while a sub-agent is still in flight', () => {
180
+ // When parent turn_end fires but a sub-agent is still running, the
181
+ // chatState enters pendingCompletion and the per-base
182
+ // `chatRunningSubagents` inner map MUST NOT be cleaned up — the
183
+ // next turn's enqueue will clone it back into the new fleet
184
+ // (issue #334 / #64). Cleanup on close is gated on the inner map
185
+ // being empty.
186
+ const { driver } = harness()
187
+ const maps = driver._debugGetMaps!()
188
+
189
+ driver.ingest(enqueue('chatA'), null)
190
+ driver.ingest(
191
+ {
192
+ kind: 'tool_use', toolName: 'Agent', toolUseId: 'tu1',
193
+ input: { prompt: 'bg', run_in_background: true },
194
+ },
195
+ 'chatA',
196
+ )
197
+ driver.ingest({ kind: 'sub_agent_started', agentId: 'saBG', firstPromptText: 'bg' }, 'chatA')
198
+ driver.ingest({ kind: 'tool_use', toolName: 'mcp__switchroom-telegram__reply' }, 'chatA')
199
+ driver.recordOutboundDelivered('chatA')
200
+ driver.ingest({ kind: 'turn_end', durationMs: 100 }, 'chatA')
201
+
202
+ // Pending — chats.size==1 (originating bg-pending state survives).
203
+ expect(maps.chats.size).toBe(1)
204
+ // Critical: the running-subagents inner map for 'chatA' must still
205
+ // contain saBG. If cleanupBaseKeyIfUnused regressed and ran here,
206
+ // the next turn would lose the bg carry.
207
+ expect(maps.chatRunningSubagents.get('chatA')?.has('saBG')).toBe(true)
208
+
209
+ // Resolve the bg sub-agent; now full close should also drain the
210
+ // sync registry inner map.
211
+ driver.ingest({ kind: 'sub_agent_turn_end', agentId: 'saBG' }, 'chatA')
212
+ expect(maps.chats.size).toBe(0)
213
+ expect(maps.chatRunningSubagents.has('chatA')).toBe(false)
214
+ })
215
+ })
@@ -0,0 +1,123 @@
1
+ /**
2
+ * P0 of #662 — invariant test that the driver's `fleet` shadow Map
3
+ * stays in lockstep with the legacy `chatState.subAgents` map across a
4
+ * full sub-agent lifecycle.
5
+ *
6
+ * We drive the real driver via createProgressDriver (no Telegram bot
7
+ * required — the emit callback just records calls) and feed a complete
8
+ * lifecycle: started → 3× tool_use → tool_result(isError=true) →
9
+ * turn_end. After every event we assert:
10
+ * - cardinality matches between fleet and subAgents
11
+ * - on terminal turn_end: status='failed' (errorSeen accumulated)
12
+ * - originatingTurnKey was snapshotted from currentTurnKey
13
+ * - lastTool reflects the most recent tool_use's sanitised arg
14
+ */
15
+
16
+ import { describe, it, expect } from 'vitest'
17
+ import { createProgressDriver } from '../progress-card-driver.js'
18
+ import type { SessionEvent } from '../session-tail.js'
19
+
20
+ function harness() {
21
+ let now = 1000
22
+ const timers: Array<{ fireAt: number; fn: () => void; ref: number; repeat?: number }> = []
23
+ let nextRef = 0
24
+ const driver = createProgressDriver({
25
+ emit: () => {},
26
+ minIntervalMs: 500,
27
+ coalesceMs: 400,
28
+ initialDelayMs: 0,
29
+ promoteAfterMs: 999_999,
30
+ now: () => now,
31
+ setTimeout: (fn, ms) => {
32
+ const ref = nextRef++
33
+ timers.push({ fireAt: now + ms, fn, ref })
34
+ return { ref }
35
+ },
36
+ clearTimeout: (h) => {
37
+ const ref = (h as { ref: number }).ref
38
+ const idx = timers.findIndex((t) => t.ref === ref)
39
+ if (idx !== -1) timers.splice(idx, 1)
40
+ },
41
+ setInterval: (fn, ms) => {
42
+ const ref = nextRef++
43
+ timers.push({ fireAt: now + ms, fn, ref, repeat: ms })
44
+ return { ref }
45
+ },
46
+ clearInterval: (h) => {
47
+ const ref = (h as { ref: number }).ref
48
+ const idx = timers.findIndex((t) => t.ref === ref)
49
+ if (idx !== -1) timers.splice(idx, 1)
50
+ },
51
+ })
52
+ return { driver, advance: (ms: number) => { now += ms } }
53
+ }
54
+
55
+ const enqueue = (chatId: string): SessionEvent => ({
56
+ kind: 'enqueue',
57
+ chatId,
58
+ messageId: '1',
59
+ threadId: null,
60
+ rawContent: `<channel chat_id="${chatId}">go</channel>`,
61
+ })
62
+
63
+ describe('driver fleet-state shadow', () => {
64
+ it('shadow Map stays in lockstep with chatState.subAgents through a failed sub-agent lifecycle', () => {
65
+ const { driver } = harness()
66
+ const CHAT = 'c1'
67
+ driver.ingest(enqueue(CHAT), null)
68
+
69
+ const events: SessionEvent[] = [
70
+ { kind: 'sub_agent_started', agentId: 'sa1', firstPromptText: 'do work', subagentType: 'worker' },
71
+ { kind: 'sub_agent_tool_use', agentId: 'sa1', toolUseId: 't1', toolName: 'Read', input: { file_path: '/etc/secrets/k.key' } },
72
+ { kind: 'sub_agent_tool_use', agentId: 'sa1', toolUseId: 't2', toolName: 'Bash', input: { command: 'ls' } },
73
+ { kind: 'sub_agent_tool_use', agentId: 'sa1', toolUseId: 't3', toolName: 'Edit', input: { file_path: '/tmp/x.ts' } },
74
+ { kind: 'sub_agent_tool_result', agentId: 'sa1', toolUseId: 't3', isError: true, errorText: 'boom' },
75
+ ]
76
+
77
+ for (const ev of events) {
78
+ driver.ingest(ev, CHAT)
79
+ const state = driver.peek(CHAT)
80
+ const fleet = driver.peekFleet(CHAT)
81
+ expect(state).toBeDefined()
82
+ expect(fleet).toBeDefined()
83
+ // Cardinality invariant — every sub-agent in the legacy map has a
84
+ // shadow entry, and vice versa.
85
+ expect(fleet!.size).toBe(state!.subAgents.size)
86
+ for (const id of state!.subAgents.keys()) {
87
+ expect(fleet!.has(id)).toBe(true)
88
+ }
89
+ }
90
+
91
+ // Pre-turn-end: fleet member exists, status still running, errorSeen true.
92
+ const midFleet = driver.peekFleet(CHAT)!
93
+ const midMember = midFleet.get('sa1')!
94
+ expect(midMember.status).toBe('running')
95
+ expect(midMember.errorSeen).toBe(true)
96
+ expect(midMember.toolCount).toBe(3)
97
+ expect(midMember.lastTool).toEqual({ name: 'Edit', sanitisedArg: 'x.ts' })
98
+ expect(midMember.role).toBe('worker') // from subagentType fallback
99
+ // Snapshotted from currentTurnKey at sub_agent_started.
100
+ expect(midMember.originatingTurnKey).toMatch(/^c1:/)
101
+
102
+ // Now end the sub-agent's turn — fleet member should flip to failed.
103
+ driver.ingest({ kind: 'sub_agent_turn_end', agentId: 'sa1' }, CHAT)
104
+ const finalFleet = driver.peekFleet(CHAT)!
105
+ const finalMember = finalFleet.get('sa1')!
106
+ expect(finalMember.status).toBe('failed')
107
+ expect(finalMember.terminalAt).not.toBeNull()
108
+ })
109
+
110
+ it('uses description as role when present', () => {
111
+ const { driver } = harness()
112
+ driver.ingest(enqueue('c2'), null)
113
+ // session-tail's sub_agent_started doesn't carry description directly,
114
+ // but the watcher path supplies subagentType — verify the fallback chain
115
+ // works when neither is set: first 20 chars of firstPromptText.
116
+ driver.ingest(
117
+ { kind: 'sub_agent_started', agentId: 'sa2', firstPromptText: 'investigate the auth bug end-to-end' },
118
+ 'c2',
119
+ )
120
+ const m = driver.peekFleet('c2')!.get('sa2')!
121
+ expect(m.role).toBe('investigate the auth')
122
+ })
123
+ })
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Regression: forceCompleteTurn must set `parentTurnEndAt` so the heartbeat's
3
+ * `parentDone` branch lights up and the elapsed counter keeps ticking through
4
+ * `subAgentTickIntervalMs` while sub-agents are still running.
5
+ *
6
+ * Bug shape (#686, fixed in #687): forceCompleteTurn reduced `turn_end` but
7
+ * never set `parentTurnEndAt`. The heartbeat's `parentDone` was therefore
8
+ * always false during the deferred-unpin window, the elapsed-ticker bypass
9
+ * never engaged, and the rendered card froze on its last emit until the
10
+ * sub-agents finished.
11
+ *
12
+ * Test shape: spawn a sub-agent, call forceCompleteTurn, then advance fake
13
+ * time across several heartbeat ticks. The "Done" header (parentDone branch
14
+ * of the renderer) MUST appear and elapsed time MUST keep advancing in the
15
+ * emitted HTML.
16
+ */
17
+ import { describe, it, expect } from 'vitest'
18
+ import { makeHarness, enqueue } from './_progress-card-harness.js'
19
+
20
+ describe('progress-card-driver: forceCompleteTurn unfreezes elapsed-ticker', () => {
21
+ it('parentDone engages and elapsed advances after forceCompleteTurn while a sub-agent is still running', () => {
22
+ const { driver, emits, advance } = makeHarness({
23
+ minIntervalMs: 0,
24
+ coalesceMs: 0,
25
+ heartbeatMs: 1_000,
26
+ })
27
+ const CHAT = 'chatF'
28
+
29
+ driver.ingest(enqueue(CHAT), null)
30
+ driver.ingest(
31
+ {
32
+ kind: 'tool_use',
33
+ toolName: 'Agent',
34
+ toolUseId: 'tu1',
35
+ input: { prompt: 'bg work', run_in_background: true },
36
+ },
37
+ CHAT,
38
+ )
39
+ driver.ingest({ kind: 'sub_agent_started', agentId: 'saBG', firstPromptText: 'bg work' }, CHAT)
40
+ driver.ingest({ kind: 'tool_use', toolName: 'mcp__switchroom-telegram__reply' }, CHAT)
41
+ driver.recordOutboundDelivered(CHAT)
42
+
43
+ // External completion signal (e.g. stream_reply done=true). Sub-agent
44
+ // is still running, so the chatState enters pendingCompletion and the
45
+ // heartbeat keeps the card alive.
46
+ driver.forceCompleteTurn({ chatId: CHAT })
47
+
48
+ // The flush triggered by forceCompleteTurn itself produces an emit
49
+ // with the parentDone-branch ("Done") header.
50
+ const emitsAfterForce = emits.length
51
+ expect(emitsAfterForce).toBeGreaterThan(0)
52
+ const renderedAtForce = emits[emitsAfterForce - 1].html
53
+ // The renderer surfaces "Background" once parentDone=true and a bg
54
+ // sub-agent is still running; if the bug regresses (parentTurnEndAt
55
+ // stays null), parentDone is false and we'd see "Working".
56
+ expect(renderedAtForce).toMatch(/Background/)
57
+ expect(renderedAtForce).not.toMatch(/Working/)
58
+
59
+ // Advance well past the elapsed-ticker interval to prove the
60
+ // heartbeat keeps emitting fresh elapsed values rather than freezing
61
+ // on the last emit. Several ticks should produce at least one extra
62
+ // emit with different rendered HTML.
63
+ advance(15_000)
64
+ const tailEmits = emits.slice(emitsAfterForce)
65
+ expect(tailEmits.length).toBeGreaterThan(0)
66
+ // At least one post-force emit must differ from the force-emit HTML —
67
+ // proving the elapsed counter advanced rather than freezing.
68
+ const advanced = tailEmits.some((e) => e.html !== renderedAtForce)
69
+ expect(advanced).toBe(true)
70
+
71
+ // Resolve the sub-agent and assert the deferred completion fires.
72
+ driver.ingest({ kind: 'sub_agent_turn_end', agentId: 'saBG' }, CHAT)
73
+ const finalEmit = emits[emits.length - 1]
74
+ expect(finalEmit.done).toBe(true)
75
+ })
76
+ })
@@ -0,0 +1,62 @@
1
+ /**
2
+ * PR-C2 — `editTimestamps` sliding-window cleanup must keep the array
3
+ * bounded under sustained burst.
4
+ *
5
+ * The driver maintains a per-turn array of recent emit timestamps and
6
+ * uses its length within the trailing 60s to flip "hot" mode (longer
7
+ * coalesce window). The cleanup is `while (arr[0] < cutoff) arr.shift()`,
8
+ * which only fires when `recordEdit` or `isBudgetHot` is called. If
9
+ * that cleanup ever regresses, the array would grow unbounded across a
10
+ * long-running turn.
11
+ *
12
+ * fails when: the `arr.shift()` cleanup is removed from `recordEdit` or
13
+ * `isBudgetHot`, OR the cutoff window is widened beyond 60s without a
14
+ * matching upper bound.
15
+ */
16
+ import { describe, it, expect } from 'vitest'
17
+ import { makeHarness, enqueue } from './_progress-card-harness.js'
18
+
19
+ describe('PR-C2: editTimestamps stays bounded under sustained emit burst', () => {
20
+ it('after 100 emits spread across 5 minutes, the per-turn array holds <= ~window-worth', () => {
21
+ // Use very low coalesce so each ingest can drive an emit. Keep the
22
+ // turn open for the whole burst.
23
+ const { driver, advance } = makeHarness({
24
+ minIntervalMs: 0,
25
+ coalesceMs: 0,
26
+ heartbeatMs: 999_999, // never auto-fire heartbeat
27
+ promoteAfterMs: 999_999,
28
+ })
29
+ const maps = driver._debugGetMaps!()
30
+
31
+ driver.ingest(enqueue('cA'), null)
32
+
33
+ // Drive 100 events spaced 3s apart — so the trailing 60s only ever
34
+ // contains ~21 timestamps. With a working sliding-window cleanup the
35
+ // array should stay bounded near that figure.
36
+ for (let i = 0; i < 100; i++) {
37
+ driver.ingest(
38
+ {
39
+ kind: 'tool_use',
40
+ toolName: 'Read',
41
+ toolUseId: `tu${i}`,
42
+ input: { file_path: `/tmp/${i}.txt` },
43
+ },
44
+ 'cA',
45
+ )
46
+ advance(3000)
47
+ }
48
+
49
+ // Find the per-turn timestamp array. The key is the active turnKey;
50
+ // there's only one turn so we can pick it.
51
+ const sizes = [...maps.editTimestamps.values()].map((a) => a.length)
52
+ expect(sizes.length).toBeGreaterThan(0)
53
+ const max = Math.max(...sizes)
54
+ // 60s window / 3s spacing = 20 entries. Allow tight slack (<= 22)
55
+ // for one or two boundary timestamps recorded by the harness's
56
+ // setup (initial enqueue, etc.) — anything looser fails to catch
57
+ // off-by-N regressions in the sliding-window cleanup.
58
+ expect(max).toBeLessThanOrEqual(22)
59
+ // And critically, NOT 100+ — that would mean cleanup never ran.
60
+ expect(max).toBeLessThan(100)
61
+ })
62
+ })
@@ -0,0 +1,84 @@
1
+ /**
2
+ * PR-C2 — end-to-end memory bounds: drive 100 turn cycles and assert
3
+ * every internal Map remains bounded.
4
+ *
5
+ * Companion to PR-B's targeted eviction test, which drove only 20
6
+ * cycles and asserted on `seenEnqueueMsgIds` / `pendingSyncEchoes`.
7
+ * This larger run is a regression net for "everything else" — if a
8
+ * future refactor forgets to evict any new map keyed by chat/turn,
9
+ * the size invariant blows up here even when the PR-B test still
10
+ * passes.
11
+ *
12
+ * fails when: any of the per-chat/per-turn Maps in `_debugGetMaps`
13
+ * grows linearly with turn count (e.g. cleanup is removed from
14
+ * completeTurnFully, or a new Map is added without an eviction hook).
15
+ */
16
+ import { describe, it, expect } from 'vitest'
17
+ import { makeHarness, enqueue } from './_progress-card-harness.js'
18
+
19
+ describe('PR-C2: end-to-end memory bounds across 100 turn cycles', () => {
20
+ it('all _debugGetMaps Maps stay bounded', () => {
21
+ const { driver, advance } = makeHarness({
22
+ heartbeatMs: 5_000,
23
+ promoteAfterMs: 999_999,
24
+ })
25
+ const maps = driver._debugGetMaps!()
26
+
27
+ for (let i = 0; i < 100; i++) {
28
+ driver.ingest(enqueue('chatA'), null)
29
+ driver.ingest({ kind: 'tool_use', toolName: 'mcp__switchroom-telegram__reply' }, 'chatA')
30
+ driver.recordOutboundDelivered('chatA')
31
+ driver.ingest({ kind: 'turn_end', durationMs: 50 }, 'chatA')
32
+ // Advance well past TTLs (60s) and the eviction throttle (~30s).
33
+ advance(65_000)
34
+ }
35
+
36
+ expect(maps.chats.size).toBe(0)
37
+ expect(maps.chatRunningSubagents.size).toBe(0)
38
+ expect(maps.baseTurnSeqs.size).toBe(0)
39
+ // The dedup maps may keep at most one straggler from the final turn.
40
+ expect(maps.seenEnqueueMsgIds.size).toBeLessThanOrEqual(1)
41
+ expect(maps.pendingSyncEchoes.size).toBeLessThanOrEqual(1)
42
+ // editTimestamps is per-turnKey; cleared on completeTurnFully.
43
+ expect(maps.editTimestamps.size).toBeLessThanOrEqual(1)
44
+ })
45
+
46
+ it('with a long-lived bg sub-agent across cycles, only the originating turnKey persists', () => {
47
+ const { driver, advance } = makeHarness({
48
+ heartbeatMs: 5_000,
49
+ promoteAfterMs: 999_999,
50
+ })
51
+ const maps = driver._debugGetMaps!()
52
+
53
+ // One bg sub-agent that NEVER finishes; 50 surrounding turns close cleanly.
54
+ driver.ingest(enqueue('chatA'), null)
55
+ driver.ingest(
56
+ {
57
+ kind: 'tool_use', toolName: 'Agent', toolUseId: 'tu1',
58
+ input: { prompt: 'forever-bg', run_in_background: true },
59
+ },
60
+ 'chatA',
61
+ )
62
+ driver.ingest({ kind: 'sub_agent_started', agentId: 'saBG', firstPromptText: 'forever-bg' }, 'chatA')
63
+ driver.ingest({ kind: 'tool_use', toolName: 'mcp__switchroom-telegram__reply' }, 'chatA')
64
+ driver.recordOutboundDelivered('chatA')
65
+ driver.ingest({ kind: 'turn_end', durationMs: 50 }, 'chatA')
66
+
67
+ for (let i = 0; i < 50; i++) {
68
+ driver.ingest(enqueue('chatA'), null)
69
+ driver.ingest({ kind: 'tool_use', toolName: 'mcp__switchroom-telegram__reply' }, 'chatA')
70
+ driver.recordOutboundDelivered('chatA')
71
+ driver.ingest({ kind: 'turn_end', durationMs: 50 }, 'chatA')
72
+ advance(65_000)
73
+ }
74
+
75
+ // After 50 clean surrounding turns each followed by `advance(65_000)`
76
+ // (well past TTL + eviction throttle), every chatState — including
77
+ // the originating one whose bg sub-agent never finished — has been
78
+ // rolled forward and evicted. Empty is the correct steady state, not
79
+ // the "≤ 2" the original PR shipped. What this test really proves
80
+ // is that `chats` doesn't grow with cycle count.
81
+ expect(maps.chats.size).toBe(0)
82
+ expect(maps.baseTurnSeqs.size).toBeLessThanOrEqual(1)
83
+ })
84
+ })