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,699 @@
1
+ /**
2
+ * Real-gateway harness — Phase 3 of #545 / first PR of #553.
3
+ *
4
+ * Wraps the Phase 1 `waiting-ux-harness` with the real production
5
+ * `InboundCoalescer` so the F1–F4 user-perceived UX deadlines are
6
+ * asserted against the same coalescing timing the live gateway uses,
7
+ * not a parallel reimplementation.
8
+ *
9
+ * The Phase 1 harness called `controller.setQueued()` (👀) synchronously
10
+ * in `inbound()` — that's why F2 ("👀 within 800ms") passed trivially
11
+ * there. Production code routes inbound through `handleInboundCoalesced`
12
+ * first, which buffers messages for `gapMs` (default 1500ms) and only
13
+ * THEN calls the first-paint flow that fires the reaction. This harness
14
+ * exposes that gap to tests so the F2 deadline becomes catchable.
15
+ *
16
+ * Composition (top-down):
17
+ * inbound(chatId, msgId, text)
18
+ * → inboundCoalescer.enqueue(key, payload)
19
+ * → after gapMs, onFlush() runs:
20
+ * → controller.setQueued() (👀)
21
+ * → driver.startTurn()
22
+ * feedSessionEvent(ev)
23
+ * → controller.setThinking() / setTool() / setDone()
24
+ * → driver.ingest()
25
+ *
26
+ * `gapMs` defaults to 1500 (production value). Tests can pass `gapMs: 0`
27
+ * to disable coalescing and verify the upper-bound on first-paint
28
+ * latency without the coalesce wait, or `gapMs: 500` to mimic an
29
+ * operator who tuned it down.
30
+ *
31
+ * F1–F4 deadlines this harness lets us assert:
32
+ * - F1 ladder collapse: reaction sequence over a multi-tool turn
33
+ * - F2 no instant draft: firstReactionMs - inboundAt
34
+ * - F3 late progress card: progressCardSendMs - firstToolUseMs
35
+ * - F4 static interim text: edits per session-event step transition
36
+ */
37
+
38
+ import {
39
+ createWaitingUxHarness,
40
+ type CreateHarnessOpts,
41
+ type HarnessHandle,
42
+ type RecordedCall,
43
+ } from './waiting-ux-harness.js'
44
+ import type { SessionEvent } from '../session-tail.js'
45
+ import {
46
+ createInboundCoalescer,
47
+ inboundCoalesceKey,
48
+ type InboundCoalescer,
49
+ } from '../gateway/inbound-coalesce.js'
50
+ import { validateClientMessage } from '../gateway/ipc-server.js'
51
+ import { flushOnAgentDisconnect } from '../gateway/disconnect-flush.js'
52
+ import { StatusReactionController } from '../status-reactions.js'
53
+ import { OutboundDedupCache } from '../recent-outbound-dedup.js'
54
+
55
+ /**
56
+ * Literal placeholder strings the v2 spec contract forbids. Listed
57
+ * centrally so the harness helpers and PR-5 removal sweep stay in
58
+ * sync. Must match the exact emoji + text used by production today —
59
+ * see `pre-alloc-decision.ts`, `placeholder-phase.ts`,
60
+ * `forum-topic-placeholder.ts`.
61
+ */
62
+ export const PLACEHOLDER_STRINGS = [
63
+ '🔵 thinking',
64
+ '📚 recalling memories',
65
+ '💭 thinking',
66
+ ] as const
67
+
68
+ function isPlaceholderPayload(payload: string | undefined): boolean {
69
+ if (payload == null) return false
70
+ for (const s of PLACEHOLDER_STRINGS) {
71
+ if (payload === s || payload === `${s}…` || payload.startsWith(`${s} `)) {
72
+ return true
73
+ }
74
+ }
75
+ return false
76
+ }
77
+
78
+ /**
79
+ * Mirror of the recorder's progress-card heuristic from
80
+ * `waiting-ux-harness.ts`. Kept in sync by hand — change both if the
81
+ * card text glyphs shift.
82
+ */
83
+ function isCardPayload(text: string | undefined): boolean {
84
+ return (
85
+ text != null &&
86
+ (text.includes('Working') ||
87
+ text.includes('⚙') ||
88
+ text.includes('⏳') ||
89
+ text.includes('• '))
90
+ )
91
+ }
92
+
93
+ export interface RealGatewayHarnessOpts extends CreateHarnessOpts {
94
+ /**
95
+ * Inbound coalesce window in ms. Production reads this per-call from
96
+ * the access file (default 1500). Tests can pass 0 to disable
97
+ * coalescing entirely.
98
+ */
99
+ gapMs?: number
100
+
101
+ /**
102
+ * Wire the production `OutboundDedupCache` into the harness's
103
+ * `streamReply` path. When enabled, repeated streamReply calls with
104
+ * the same normalized content within the TTL are suppressed —
105
+ * mimicking the #546 fix in production. Default false (preserves
106
+ * back-compat with F1–F4 tests that don't care about dedup).
107
+ *
108
+ * When true, tests can introspect the cache via `harness.dedup`.
109
+ */
110
+ withDedup?: boolean
111
+
112
+ /**
113
+ * TTL for the wired-in dedup cache. Only used when `withDedup` is
114
+ * true. Default matches production (`DEFAULT_DEDUP_TTL_MS = 60_000`).
115
+ */
116
+ dedupTtlMs?: number
117
+ }
118
+
119
+ interface CoalescePayload {
120
+ chatId: string
121
+ messageId: number
122
+ text: string
123
+ userId: string
124
+ }
125
+
126
+ export interface RealGatewayHarnessHandle extends HarnessHandle {
127
+ /**
128
+ * Total inbound messages currently buffered by the coalescer (across
129
+ * all keys). For tests asserting that flush actually fired.
130
+ */
131
+ coalesceBufferSize(): number
132
+ /** Underlying coalescer — exposed for tests that need direct introspection. */
133
+ coalescer: InboundCoalescer<CoalescePayload>
134
+ /**
135
+ * Effective gapMs the harness was configured with. Pinned for tests
136
+ * that compute deadlines relative to the coalesce window.
137
+ */
138
+ gapMs: number
139
+
140
+ // ─── v2 spec helpers (PR 1 of #553 series) ──────────────────────────
141
+ // The waiting-UX v2 contract forbids placeholder-text edits ("🔵
142
+ // thinking", "📚 recalling memories", "💭 thinking"), suppresses the
143
+ // progress card for Class A/B turns, and pins a first-answer-text
144
+ // deadline. These three helpers expose those checks in a form that
145
+ // reads cleanly inside `expect(...)` assertions.
146
+
147
+ /**
148
+ * Returns recorded `sendMessage` and `editMessageText` calls for
149
+ * `chat_id` whose payload matches one of the literal placeholder
150
+ * strings the v2 spec bans. Class A and B tests assert
151
+ * `expect(h.recorder.expectNoPlaceholderEdits(CHAT)).toEqual([])`.
152
+ *
153
+ * NOTE: this name is a slight misnomer — it returns hits to
154
+ * inspect, not throws. A non-empty array IS the failure signal.
155
+ */
156
+ expectNoPlaceholderEdits(chatId: string): RecordedCall[]
157
+
158
+ /**
159
+ * Returns the timestamp of the first progress-card render for
160
+ * `chat_id`, or null if none. Thin wrapper around
161
+ * `recorder.progressCardSendMs` so spec tests can write
162
+ * `expect(h.recorder.expectNoCardSent(CHAT)).toBeNull()` for the
163
+ * Class A/B "no card" invariant without poking at the underlying
164
+ * recorder helper directly.
165
+ */
166
+ expectNoCardSent(chatId: string): number | null
167
+
168
+ /**
169
+ * Returns the timestamp of the first `sendMessage` or
170
+ * `editMessageText` for `chat_id` whose payload is plausibly
171
+ * answer text — i.e. NOT a progress-card payload (per
172
+ * `isCardPayload` heuristic) and NOT a placeholder string.
173
+ * Returns null if no such call has been recorded.
174
+ *
175
+ * Used to pin the v2 first-answer-text deadline (Class A: <800ms
176
+ * for 👀 and answer text bounded TBD by PR 3; Class B/C: TBD).
177
+ */
178
+ firstAnswerTextMs(chatId: string): number | null
179
+
180
+ /**
181
+ * Issue #626 invariant — exactly one anchor `sendMessage` per
182
+ * (chatId, threadId, turnKey?). Returns the count of fresh
183
+ * `sendMessage` calls (NOT edits) for the chat. The anchor is the
184
+ * single message that subsequent edits target. Multiple anchors for
185
+ * the same logical turn = the duplicate-status-message bug.
186
+ *
187
+ * Usage: `expect(h.anchorMessageCount(CHAT)).toBe(1)` after a
188
+ * complete turn. Pass `threadId` to disambiguate forum topics.
189
+ *
190
+ * Returns -1 if the recorder isn't tracking calls (defensive — the
191
+ * harness shouldn't reach this state, but a -1 is more actionable
192
+ * than a silent 0 if it does).
193
+ */
194
+ anchorMessageCount(chatId: string, threadId?: number): number
195
+
196
+ // ─── IPC + bridge lifecycle helpers (ships with PR for I1–I5) ───────
197
+ // The IPC lifecycle (clients connecting, registering, sending typed
198
+ // messages, disconnecting) is invisible to the existing waiting-UX
199
+ // helpers above. Production bugs in this layer (Bug A premature 👍 on
200
+ // anonymous disconnect, Bug B `update_placeholder` lethality, Bug D
201
+ // 👍-before-delivery) all share a root cause: the harness had no way
202
+ // to express "a client just connected/sent/disconnected." These
203
+ // helpers route through PRODUCTION code paths where possible —
204
+ // `validateClientMessage` is the real validator from
205
+ // `gateway/ipc-server.ts`; the disconnect handler is mirrored from
206
+ // `gateway.ts`'s `onClientDisconnected` (extracted helper landing in
207
+ // PR #600 — until that merges, the harness mirror keeps the same
208
+ // semantics so the invariants are testable now).
209
+
210
+ /**
211
+ * Simulate a client opening an IPC connection. If `agentName` is
212
+ * provided, the harness immediately routes a `register` message
213
+ * through the production validator so subsequent
214
+ * `bridgeDisconnect()` cleans up the right per-agent state. If
215
+ * `agentName == null`, the connection stays anonymous (recall.py-
216
+ * style one-shot caller). Returns the synthetic `clientId`.
217
+ */
218
+ bridgeConnect(agentName: string | null): string
219
+
220
+ /**
221
+ * Simulate a client closing its IPC connection. Routes through the
222
+ * harness's mirror of `onClientDisconnected` — flushes per-agent
223
+ * status reactions to setDone() and disposes that agent's draft
224
+ * streams. **Crucially: anonymous clients (agentName=null) flow
225
+ * through the same handler but MUST NOT mutate any active state.**
226
+ * That's invariant I1 (Bug A's failure mode).
227
+ */
228
+ bridgeDisconnect(clientId: string): void
229
+
230
+ /**
231
+ * Simulate a client sending an IPC message. The payload is run
232
+ * through the production `validateClientMessage` validator — if it
233
+ * fails validation (e.g. legacy `update_placeholder` type), the
234
+ * harness logs and discards, mirroring `processBuffer`'s loop. The
235
+ * connection stays open; no state is mutated. That's invariant I4.
236
+ */
237
+ sendIpcMessage(clientId: string, message: object): void
238
+
239
+ /**
240
+ * Timestamp of the last `setMessageReaction` for `chatId`, or null.
241
+ * Used by I3 to compare reaction-fired-at against
242
+ * answer-text-delivered-at.
243
+ */
244
+ lastReactionEmojiAt(chatId: string): number | null
245
+
246
+ /**
247
+ * Timestamp of the LAST `sendMessage` / `editMessageText` whose
248
+ * payload looks like real model text (not card, not placeholder).
249
+ * Used by I3 to assert 👍 fires AFTER delivery, not before.
250
+ */
251
+ lastAnswerTextDeliveredAt(chatId: string): number | null
252
+
253
+ /**
254
+ * Test introspection of the side-effect callbacks fired by the real
255
+ * `flushOnAgentDisconnect` helper since the harness was created. Tests
256
+ * that want to assert "no flush ran" check `clearActiveReactionsCalls`
257
+ * and `disposeProgressDriverCalls` are still 0 after a sequence of
258
+ * anonymous bridge cycles. `activeAgentCount` is the live size of the
259
+ * harness's mirror of `activeStatusReactions` — non-zero means at
260
+ * least one registered agent is still active.
261
+ */
262
+ flushSideEffects(): {
263
+ clearActiveReactionsCalls: number
264
+ disposeProgressDriverCalls: number
265
+ flushLog: ReadonlyArray<string>
266
+ activeAgentCount: number
267
+ }
268
+
269
+ // ─── #546 dedup integration ─────────────────────────────────────────
270
+ /**
271
+ * Real `OutboundDedupCache` wired into the harness's `streamReply`
272
+ * path when `opts.withDedup === true`. Null otherwise. Tests assert
273
+ * on `harness.dedup.size(now)` to confirm a record landed; or invoke
274
+ * `harness.dedup.check(...)` directly to verify a hit before the
275
+ * second send is attempted.
276
+ */
277
+ dedup: OutboundDedupCache | null
278
+
279
+ /**
280
+ * Count of dedup-suppressed sends since harness creation. When the
281
+ * cache catches a retry, the harness records this so I6 / replay
282
+ * tests can assert "yes, dedup actually fired" without poking at
283
+ * counters in the cache.
284
+ */
285
+ dedupSuppressedCount(): number
286
+
287
+ /**
288
+ * Convenience scenario: simulate the #546 turn-flush + replay
289
+ * sequence end-to-end:
290
+ * 1. First send(text) — lands as a fresh sendMessage and records
291
+ * into the dedup cache.
292
+ * 2. Bridge disconnects + a fresh agent reconnects. Disconnect is
293
+ * REGISTERED (not anonymous) so `flushOnAgentDisconnect` actually
294
+ * runs — proving dedup survives the production cleanup path.
295
+ * Anonymous disconnects are a no-op (I1) and would let this
296
+ * scenario pass even if dedup were broken in flush.
297
+ * 3. Second send(text) — claude-code's preserved tool_call replay.
298
+ * Should be suppressed by dedup (no second outbound landed).
299
+ *
300
+ * Returns `{ firstMessageId, suppressedSecond, flushRan }`. Tests
301
+ * assert `suppressedSecond === true` AND `flushRan === true` so the
302
+ * full path is exercised, not a tautology.
303
+ */
304
+ simulateRetryDup(args: {
305
+ chat_id: string
306
+ text: string
307
+ }): Promise<{
308
+ firstMessageId: number | null
309
+ suppressedSecond: boolean
310
+ flushRan: boolean
311
+ }>
312
+
313
+ /**
314
+ * "Fresh send" — always issues a new `sendMessage` for `chat_id`,
315
+ * does NOT update the harness's stream-edit cache. Routes through
316
+ * the dedup cache when wired. Mirrors production's turn-flush
317
+ * backstop and the wake-audit greeting path: every fire is a
318
+ * fresh user-visible message, not a streaming edit. Use this in
319
+ * dedup tests where "the same content emitted twice" means two
320
+ * NEW messages, not a streaming edit-in-place.
321
+ *
322
+ * Returns the new `message_id`, or null if dedup suppressed the send.
323
+ */
324
+ send(args: { chat_id: string; text: string; parse_mode?: string }): Promise<number | null>
325
+ }
326
+
327
+ const DEFAULT_GAP_MS = 1500
328
+
329
+ export function createRealGatewayHarness(
330
+ opts: RealGatewayHarnessOpts = {},
331
+ ): RealGatewayHarnessHandle {
332
+ const gapMs = opts.gapMs ?? DEFAULT_GAP_MS
333
+
334
+ // Phase 1 harness: controller + driver + recorder + clock.
335
+ const inner = createWaitingUxHarness(opts)
336
+
337
+ // Track which (chatId) keys have an active turn — mirrors gateway.ts's
338
+ // `activeTurnStartedAt` for the F2 early-ack mid-turn check. Set on
339
+ // flush (when inner.inbound runs); cleared by the `turn_end` session
340
+ // event so subsequent fresh inbounds get the early-ack again.
341
+ const activeTurns = new Set<string>()
342
+
343
+ // Wrap inner.inbound() with the real coalescer so the test surface
344
+ // matches what production sees end-to-end.
345
+ const coalescer = createInboundCoalescer<CoalescePayload>({
346
+ gapMs,
347
+ merge: (entries) => {
348
+ const last = entries[entries.length - 1]
349
+ return {
350
+ chatId: last.chatId,
351
+ messageId: last.messageId,
352
+ userId: last.userId,
353
+ text: entries.map((e) => e.text).join('\n'),
354
+ }
355
+ },
356
+ onFlush: (_key, merged) => {
357
+ // The flush is the moment first-paint runs in production —
358
+ // controller.setQueued() (👀) and driver.startTurn(). Delegate
359
+ // to the inner harness's inbound() which already wires both.
360
+ activeTurns.add(merged.chatId)
361
+ inner.inbound({ chatId: merged.chatId, messageId: merged.messageId, text: merged.text })
362
+ },
363
+ })
364
+
365
+ function inbound(args: { chatId: string; messageId: number; text?: string; userId?: string }): void {
366
+ const userId = args.userId ?? '777' // matches update-factory's default sender
367
+
368
+ // F2 fix mirror: fire 👀 directly via bot.api on raw arrival, BEFORE
369
+ // the coalescer's gap window. Production runs `maybeEarlyAckReaction`
370
+ // here for paired DM users on a fresh turn. The harness skips the
371
+ // access/chatType checks (the harness has no access file) and gates
372
+ // only on "no active turn" so the mid-turn-flash case stays catchable.
373
+ const turnKey = args.chatId
374
+ if (!activeTurns.has(turnKey)) {
375
+ void inner.bot.api.setMessageReaction(args.chatId, args.messageId, [
376
+ { type: 'emoji', emoji: '👀' },
377
+ ])
378
+ }
379
+
380
+ const payload: CoalescePayload = {
381
+ chatId: args.chatId,
382
+ messageId: args.messageId,
383
+ text: args.text ?? '',
384
+ userId,
385
+ }
386
+ const key = inboundCoalesceKey(args.chatId, userId)
387
+ const result = coalescer.enqueue(key, payload)
388
+ if (result.bypass) {
389
+ // gapMs <= 0 — production calls handleInbound directly; mirror
390
+ // by calling the inner harness's first-paint immediately.
391
+ activeTurns.add(turnKey)
392
+ inner.inbound({ chatId: args.chatId, messageId: args.messageId, text: args.text })
393
+ }
394
+ }
395
+
396
+ function feedSessionEvent(ev: SessionEvent): void {
397
+ if (ev.kind === 'turn_end') {
398
+ // Turn complete — clear the active-turn marker so the next inbound
399
+ // gets the early-ack again. Mirrors gateway.ts clearing
400
+ // activeTurnStartedAt on turn-end (production tracks it per
401
+ // statusKey but the harness collapses to per-chat).
402
+ activeTurns.clear()
403
+ }
404
+ inner.feedSessionEvent(ev)
405
+ }
406
+
407
+ function finalize(): void {
408
+ coalescer.reset()
409
+ inner.finalize()
410
+ }
411
+
412
+ function expectNoPlaceholderEdits(chatId: string): RecordedCall[] {
413
+ return inner.recorder.calls.filter(
414
+ (c) =>
415
+ (c.kind === 'sendMessage' || c.kind === 'editMessageText') &&
416
+ c.chat_id === chatId &&
417
+ isPlaceholderPayload(c.payload),
418
+ )
419
+ }
420
+
421
+ function expectNoCardSent(chatId: string): number | null {
422
+ return inner.recorder.progressCardSendMs(chatId)
423
+ }
424
+
425
+ function firstAnswerTextMs(chatId: string): number | null {
426
+ const hit = inner.recorder.calls.find(
427
+ (c) =>
428
+ (c.kind === 'sendMessage' || c.kind === 'editMessageText') &&
429
+ c.chat_id === chatId &&
430
+ !isCardPayload(c.payload) &&
431
+ !isPlaceholderPayload(c.payload),
432
+ )
433
+ return hit ? hit.ts : null
434
+ }
435
+
436
+ function anchorMessageCount(chatId: string, threadId?: number): number {
437
+ if (!Array.isArray(inner.recorder.calls)) return -1
438
+ return inner.recorder.calls.filter((c) => {
439
+ if (c.kind !== 'sendMessage') return false
440
+ if (c.chat_id !== chatId) return false
441
+ if (threadId == null) return true
442
+ // RecordedCall payload may carry message_thread_id when the
443
+ // production code passed one — match if requested.
444
+ const opts = (c as { opts?: { message_thread_id?: number } }).opts
445
+ return opts?.message_thread_id === threadId
446
+ }).length
447
+ }
448
+
449
+ function lastReactionEmojiAt(chatId: string): number | null {
450
+ const hits = inner.recorder.calls.filter(
451
+ (c) => c.kind === 'setMessageReaction' && c.chat_id === chatId,
452
+ )
453
+ return hits.length === 0 ? null : hits[hits.length - 1].ts
454
+ }
455
+
456
+ function lastAnswerTextDeliveredAt(chatId: string): number | null {
457
+ const hits = inner.recorder.calls.filter(
458
+ (c) =>
459
+ (c.kind === 'sendMessage' || c.kind === 'editMessageText') &&
460
+ c.chat_id === chatId &&
461
+ !isCardPayload(c.payload) &&
462
+ !isPlaceholderPayload(c.payload),
463
+ )
464
+ return hits.length === 0 ? null : hits[hits.length - 1].ts
465
+ }
466
+
467
+ // ─── #546 dedup wiring (opt-in) ───────────────────────────────────────
468
+ // When `withDedup` is set, wrap the inner harness's `streamReply` so
469
+ // the same content sent twice within the TTL only lands once. Mirrors
470
+ // the production fix at `gateway.ts:2233` (`executeStreamReply`) and
471
+ // `gateway.ts:1893` (`executeReply`): both check the cache, return
472
+ // early on hit (NOT calling setDone — the original send already
473
+ // finalized), and record after a successful send. F1–F4 tests don't
474
+ // care about dedup so it stays opt-in.
475
+ //
476
+ // INVARIANT MIRROR: production's dedup-hit branch returns
477
+ // { content: [{ type: 'text', text: 'sent (deduped — ...)' }] }
478
+ // without firing setDone. The harness wrap matches this — the
479
+ // controller is left untouched on suppression. If production
480
+ // changes (e.g. fires setDone on suppression for some reason),
481
+ // update both sites together.
482
+ const dedup = opts.withDedup === true ? new OutboundDedupCache({ ttlMs: opts.dedupTtlMs }) : null
483
+ let dedupSuppressed = 0
484
+ const innerStreamReply = inner.streamReply
485
+ const streamReply = dedup == null
486
+ ? innerStreamReply
487
+ : async (args: { chat_id: string; text: string; done?: boolean }): Promise<void> => {
488
+ const now = Date.now()
489
+ const hit = dedup.check(args.chat_id, undefined, args.text, now)
490
+ if (hit != null) {
491
+ dedupSuppressed++
492
+ return
493
+ }
494
+ await innerStreamReply(args)
495
+ dedup.record(args.chat_id, undefined, args.text, Date.now())
496
+ }
497
+
498
+ /**
499
+ * Fresh-send wrapper. Routes through the dedup cache (if wired) and
500
+ * always calls `bot.api.sendMessage` directly — bypasses the inner
501
+ * harness's stream-edit cache. Returns the new message_id, or null
502
+ * if dedup suppressed the send.
503
+ */
504
+ async function send(args: {
505
+ chat_id: string
506
+ text: string
507
+ parse_mode?: string
508
+ }): Promise<number | null> {
509
+ const now = Date.now()
510
+ if (dedup != null) {
511
+ const hit = dedup.check(args.chat_id, undefined, args.text, now)
512
+ if (hit != null) {
513
+ dedupSuppressed++
514
+ return null
515
+ }
516
+ }
517
+ const result = (await inner.bot.api.sendMessage(args.chat_id, args.text, {
518
+ parse_mode: args.parse_mode ?? 'HTML',
519
+ })) as { message_id: number }
520
+ if (dedup != null) {
521
+ dedup.record(args.chat_id, undefined, args.text, Date.now())
522
+ }
523
+ return result.message_id
524
+ }
525
+
526
+ async function simulateRetryDup(args: {
527
+ chat_id: string
528
+ text: string
529
+ }): Promise<{
530
+ firstMessageId: number | null
531
+ suppressedSecond: boolean
532
+ flushRan: boolean
533
+ }> {
534
+ if (dedup == null) {
535
+ throw new Error(
536
+ 'simulateRetryDup requires withDedup: true on createRealGatewayHarness',
537
+ )
538
+ }
539
+ const firstMessageId = await send(args)
540
+
541
+ // Bridge cycle with a REGISTERED agent so flushOnAgentDisconnect
542
+ // actually runs. Anonymous disconnects no-op (I1) — using one
543
+ // there would make the scenario a tautology (the bridge cycle
544
+ // wouldn't touch state at all). Production's #546 reproducer
545
+ // involves the claude-code bridge (registered) crashing, so the
546
+ // registered path is the one we need to prove dedup survives.
547
+ const flushBefore = disposeProgressDriverCalls
548
+ const cid = bridgeConnect('agent-claude')
549
+ bridgeDisconnect(cid)
550
+ const flushRan = disposeProgressDriverCalls > flushBefore
551
+
552
+ const suppressedBefore = dedupSuppressed
553
+ const secondMessageId = await send(args)
554
+ const suppressedSecond = dedupSuppressed > suppressedBefore && secondMessageId == null
555
+
556
+ return { firstMessageId, suppressedSecond, flushRan }
557
+ }
558
+
559
+ // ─── IPC + bridge lifecycle simulation ────────────────────────────────
560
+ // The harness wires `bridgeDisconnect` through the REAL production
561
+ // helper `flushOnAgentDisconnect` from `gateway/disconnect-flush.ts`
562
+ // (extracted in PR #600). Tests against this harness exercise actual
563
+ // production code, not a parallel reimplementation — so the I1/I2
564
+ // invariants would catch a regression if someone reverted the
565
+ // `if (agentName == null) return false` gate in the helper.
566
+ //
567
+ // Per-agent state mirrors what `gateway.ts` holds at module scope:
568
+ // `activeStatusReactions` keyed by agent name. Each registered agent
569
+ // gets a fresh per-agent controller; the production helper mutates
570
+ // the Map in place when an agent disconnects.
571
+ //
572
+ // The shared `inner.controller` (from waiting-ux-harness) stays as
573
+ // the default for back-compat with tests that don't go through the
574
+ // bridge surface — `bridgeConnect(null)` doesn't touch it either.
575
+ const clientsById = new Map<string, { agentName: string | null }>()
576
+ // Production-shaped Maps for the helper. Keyed by agent name (one
577
+ // entry per registered agent in the harness; production keys by
578
+ // chat:thread:msgId but the helper's behavior is per-entry-iteration
579
+ // either way, so the key shape doesn't change semantics).
580
+ const activeStatusReactions = new Map<string, StatusReactionController>()
581
+ const activeReactionMsgIds = new Map<string, { chatId: string; messageId: number }>()
582
+ const activeTurnStartedAt = new Map<string, number>()
583
+ const activeDraftStreams = new Map<string, { isFinal: () => boolean; finalize: () => Promise<void> }>()
584
+ const activeDraftParseModes = new Map<string, 'HTML' | 'MarkdownV2' | undefined>()
585
+ let clearActiveReactionsCalls = 0
586
+ let disposeProgressDriverCalls = 0
587
+ const flushLog: string[] = []
588
+ const ipcLog: Array<{ kind: 'invalid' | 'unknown' | 'accepted'; raw: unknown }> = []
589
+
590
+ function bridgeConnect(agentName: string | null): string {
591
+ const clientId = `client-${Math.random().toString(36).slice(2, 10)}`
592
+ clientsById.set(clientId, { agentName })
593
+ if (agentName != null) {
594
+ // Validate the synthetic register message through the real validator.
595
+ const reg = { type: 'register', agentName }
596
+ if (!validateClientMessage(reg)) {
597
+ // Should never happen with a sane agentName — surface loudly.
598
+ throw new Error(`harness bug: register validation failed for ${agentName}`)
599
+ }
600
+ // Per-agent controller mirrors what gateway.ts puts in
601
+ // `activeStatusReactions.set(key, ctrl)`. The production helper
602
+ // iterates the Map and calls setDone on each entry; per-agent
603
+ // isolation comes from the helper's `agentName == null` gate
604
+ // (anonymous = skip everything) — NOT from selective deletion.
605
+ const ctrl = new StatusReactionController(
606
+ async () => { /* harness uses inner.controller for the shared chat */ },
607
+ opts.allowedReactions ?? null,
608
+ { debounceMs: opts.debounceMs ?? 700 },
609
+ )
610
+ activeStatusReactions.set(agentName, ctrl)
611
+ }
612
+ return clientId
613
+ }
614
+
615
+ function bridgeDisconnect(clientId: string): void {
616
+ const meta = clientsById.get(clientId)
617
+ if (meta == null) return
618
+ clientsById.delete(clientId)
619
+
620
+ // I1 + I2 contract: route through the REAL production helper.
621
+ // `agentName == null` ⇒ helper's anonymous-skip gate fires and the
622
+ // Map is untouched. `agentName != null` ⇒ helper iterates the Map
623
+ // and flushes setDone on every entry. The Map keys mean: in the
624
+ // I1 test, ANY remaining controller would prove the gate was
625
+ // bypassed; in the I2 test, the Map will have entries for OTHER
626
+ // agents that get incorrectly cleared if the helper is buggy.
627
+ flushOnAgentDisconnect({
628
+ agentName: meta.agentName,
629
+ activeStatusReactions,
630
+ activeReactionMsgIds,
631
+ activeTurnStartedAt,
632
+ activeDraftStreams,
633
+ activeDraftParseModes,
634
+ clearActiveReactions: () => { clearActiveReactionsCalls++ },
635
+ disposeProgressDriver: () => { disposeProgressDriverCalls++ },
636
+ log: (msg) => { flushLog.push(msg) },
637
+ })
638
+ }
639
+
640
+ /** Test introspection — counts of side-effect callbacks fired by the helper. */
641
+ function flushSideEffects(): {
642
+ clearActiveReactionsCalls: number
643
+ disposeProgressDriverCalls: number
644
+ flushLog: ReadonlyArray<string>
645
+ activeAgentCount: number
646
+ } {
647
+ return {
648
+ clearActiveReactionsCalls,
649
+ disposeProgressDriverCalls,
650
+ flushLog,
651
+ activeAgentCount: activeStatusReactions.size,
652
+ }
653
+ }
654
+
655
+ function sendIpcMessage(clientId: string, message: object): void {
656
+ if (!clientsById.has(clientId)) {
657
+ throw new Error(`harness: unknown clientId ${clientId} (was bridgeConnect called?)`)
658
+ }
659
+ // I4: legacy IPC types must be tolerated — the validator returns
660
+ // false, processBuffer logs+continues, the connection stays open.
661
+ // The harness records the outcome so tests can assert "logged and
662
+ // discarded, not thrown."
663
+ if (!validateClientMessage(message)) {
664
+ ipcLog.push({ kind: 'invalid', raw: message })
665
+ return
666
+ }
667
+ // Validated messages would normally route to the gateway's
668
+ // per-type handler. The harness doesn't replay every dispatch —
669
+ // tests that exercise the full session-event path use
670
+ // `feedSessionEvent` directly. This helper exists to exercise the
671
+ // VALIDATOR boundary, which is where the lethality lives.
672
+ ipcLog.push({ kind: 'accepted', raw: message })
673
+ }
674
+
675
+ return {
676
+ ...inner,
677
+ inbound,
678
+ feedSessionEvent,
679
+ finalize,
680
+ coalescer,
681
+ coalesceBufferSize: () => coalescer.size(),
682
+ gapMs,
683
+ expectNoPlaceholderEdits,
684
+ expectNoCardSent,
685
+ anchorMessageCount,
686
+ firstAnswerTextMs,
687
+ bridgeConnect,
688
+ bridgeDisconnect,
689
+ sendIpcMessage,
690
+ lastReactionEmojiAt,
691
+ lastAnswerTextDeliveredAt,
692
+ flushSideEffects,
693
+ streamReply,
694
+ dedup,
695
+ dedupSuppressedCount: () => dedupSuppressed,
696
+ simulateRetryDup,
697
+ send,
698
+ }
699
+ }