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,248 @@
1
+ import { describe, it, expect, vi } from 'vitest'
2
+
3
+ import { redactAuthCodeMessage } from '../auth-code-redact.js'
4
+
5
+ /**
6
+ * Regression coverage for #488. The helper is wired into all 6
7
+ * auth-code paste paths (gateway + server, bare-paste + /auth code +
8
+ * /reauth shortcut). The contract pinned here is what callers depend
9
+ * on — and what makes the difference between "OAuth code stays in
10
+ * chat history" and "OAuth code disappears within ~1s".
11
+ */
12
+ describe('redactAuthCodeMessage', () => {
13
+ function makeApi() {
14
+ return {
15
+ deleteMessage: vi.fn(async () => true as const),
16
+ setMessageReaction: vi.fn(async () => true as const),
17
+ }
18
+ }
19
+
20
+ it('deletes the message AND emits a 🔑 reaction (best-effort breadcrumb)', () => {
21
+ const api = makeApi()
22
+ redactAuthCodeMessage(api, '12345', 999)
23
+
24
+ expect(api.deleteMessage).toHaveBeenCalledTimes(1)
25
+ expect(api.deleteMessage).toHaveBeenCalledWith('12345', 999)
26
+
27
+ expect(api.setMessageReaction).toHaveBeenCalledTimes(1)
28
+ expect(api.setMessageReaction).toHaveBeenCalledWith('12345', 999, [
29
+ { type: 'emoji', emoji: '🔑' },
30
+ ])
31
+ })
32
+
33
+ it('is a no-op when messageId is null (defensive guard for ctx without a message)', () => {
34
+ const api = makeApi()
35
+ redactAuthCodeMessage(api, '12345', null)
36
+
37
+ expect(api.deleteMessage).not.toHaveBeenCalled()
38
+ expect(api.setMessageReaction).not.toHaveBeenCalled()
39
+ })
40
+
41
+ it('returns synchronously — does not await either call', () => {
42
+ // The function fires both API calls fire-and-forget so the caller
43
+ // can return to the event loop immediately. A blocking helper
44
+ // would slow every auth-code paste by ~1 RTT to Telegram.
45
+ const api = {
46
+ deleteMessage: vi.fn(() => new Promise(() => {})), // never resolves
47
+ setMessageReaction: vi.fn(() => new Promise(() => {})),
48
+ }
49
+ const start = Date.now()
50
+ redactAuthCodeMessage(api, '12345', 999)
51
+ const elapsed = Date.now() - start
52
+ // <50ms is plenty of headroom for the synchronous fire-and-forget
53
+ // dispatch — would be ~∞ if we awaited.
54
+ expect(elapsed).toBeLessThan(50)
55
+ })
56
+
57
+ it('swallows deleteMessage errors (message too old, user already deleted)', async () => {
58
+ const api = {
59
+ deleteMessage: vi.fn(async () => {
60
+ throw new Error('Bad Request: message to delete not found')
61
+ }),
62
+ setMessageReaction: vi.fn(async () => true as const),
63
+ }
64
+ // Must not throw synchronously, must not reject the unhandled promise.
65
+ expect(() => redactAuthCodeMessage(api, '12345', 999)).not.toThrow()
66
+ // Drain the microtask queue so the rejection fires + is caught.
67
+ await new Promise((resolve) => setTimeout(resolve, 0))
68
+ expect(api.deleteMessage).toHaveBeenCalledTimes(1)
69
+ })
70
+
71
+ it('swallows setMessageReaction errors (race with successful delete)', async () => {
72
+ const api = {
73
+ deleteMessage: vi.fn(async () => true as const),
74
+ setMessageReaction: vi.fn(async () => {
75
+ throw new Error('Bad Request: message not found')
76
+ }),
77
+ }
78
+ expect(() => redactAuthCodeMessage(api, '12345', 999)).not.toThrow()
79
+ await new Promise((resolve) => setTimeout(resolve, 0))
80
+ expect(api.setMessageReaction).toHaveBeenCalledTimes(1)
81
+ })
82
+
83
+ it('handles negative chat ids (groups / supergroups / channels)', () => {
84
+ // Telegram chat ids are negative for groups; helper passes them
85
+ // through verbatim — no parsing, no validation.
86
+ const api = makeApi()
87
+ redactAuthCodeMessage(api, '-1001234567890', 42)
88
+ expect(api.deleteMessage).toHaveBeenCalledWith('-1001234567890', 42)
89
+ expect(api.setMessageReaction).toHaveBeenCalledWith('-1001234567890', 42, [
90
+ { type: 'emoji', emoji: '🔑' },
91
+ ])
92
+ })
93
+
94
+ it('keeps reaction + delete independently dispatched even if one fails', async () => {
95
+ // The two calls should not depend on each other — if delete
96
+ // succeeds the reaction silently fails (message gone), if delete
97
+ // fails the reaction provides the visible breadcrumb. Both
98
+ // fire-and-forget, neither blocks the other.
99
+ const api = {
100
+ deleteMessage: vi.fn(async () => {
101
+ throw new Error('failed')
102
+ }),
103
+ setMessageReaction: vi.fn(async () => true as const),
104
+ }
105
+ redactAuthCodeMessage(api, '12345', 999)
106
+ await new Promise((resolve) => setTimeout(resolve, 0))
107
+ // Delete failed but reaction still went through.
108
+ expect(api.deleteMessage).toHaveBeenCalledTimes(1)
109
+ expect(api.setMessageReaction).toHaveBeenCalledTimes(1)
110
+ })
111
+ })
112
+
113
+ /**
114
+ * Diagnostic logging (#561 follow-up). Before this commit the function
115
+ * silently swallowed every API failure — when an OAuth code paste stuck
116
+ * around in chat, operators had no way to tell whether deleteMessage
117
+ * failed on permissions, on a 48h-too-old message, or because msgId was
118
+ * null. The optional `log` sink emits one line per attempt (success or
119
+ * specific error message).
120
+ */
121
+ describe('redactAuthCodeMessage — diagnostic logging', () => {
122
+ it('logs nothing when no log sink is provided (back-compat)', async () => {
123
+ const api = {
124
+ deleteMessage: vi.fn(async () => true as const),
125
+ setMessageReaction: vi.fn(async () => true as const),
126
+ }
127
+ // Just verify it doesn't crash without a sink.
128
+ expect(() => redactAuthCodeMessage(api, '12345', 999)).not.toThrow()
129
+ await new Promise((resolve) => setTimeout(resolve, 0))
130
+ })
131
+
132
+ it('logs the no-message-id case so the silent skip is visible', () => {
133
+ const api = {
134
+ deleteMessage: vi.fn(async () => true as const),
135
+ setMessageReaction: vi.fn(async () => true as const),
136
+ }
137
+ const lines: string[] = []
138
+ redactAuthCodeMessage(api, '12345', null, line => lines.push(line))
139
+ expect(lines).toHaveLength(1)
140
+ expect(lines[0]).toMatch(/no message_id/)
141
+ expect(lines[0]).toMatch(/skipping/)
142
+ })
143
+
144
+ it('logs SUCCESS for both delete and reaction with msgId + chatId for grep-by', async () => {
145
+ const api = {
146
+ deleteMessage: vi.fn(async () => true as const),
147
+ setMessageReaction: vi.fn(async () => true as const),
148
+ }
149
+ const lines: string[] = []
150
+ redactAuthCodeMessage(api, '12345', 999, line => lines.push(line))
151
+ await new Promise((resolve) => setTimeout(resolve, 0))
152
+ expect(lines).toHaveLength(2)
153
+ // Order isn't guaranteed (independent dispatch). Assert content.
154
+ const joined = lines.join('\n')
155
+ expect(joined).toMatch(/deleted/)
156
+ expect(joined).toMatch(/reaction added/)
157
+ expect(joined).toMatch(/msgId=999/)
158
+ expect(joined).toMatch(/chatId=12345/)
159
+ })
160
+
161
+ it('logs FAILED with the actual error message on deleteMessage rejection', async () => {
162
+ const api = {
163
+ deleteMessage: vi.fn(async () => {
164
+ throw new Error('Bad Request: not enough rights to delete a message')
165
+ }),
166
+ setMessageReaction: vi.fn(async () => true as const),
167
+ }
168
+ const lines: string[] = []
169
+ redactAuthCodeMessage(api, '12345', 999, line => lines.push(line))
170
+ await new Promise((resolve) => setTimeout(resolve, 0))
171
+ const failed = lines.find(l => l.includes('delete FAILED'))
172
+ expect(failed).toBeDefined()
173
+ // The actual Telegram error must be carried verbatim — that's the
174
+ // signal operators need to root-cause the redaction failure.
175
+ expect(failed).toMatch(/not enough rights to delete a message/)
176
+ // And the warning must mention the user-visible consequence so a
177
+ // reader of the journal understands why this matters.
178
+ expect(failed).toMatch(/may still be visible/)
179
+ })
180
+
181
+ it('logs FAILED with the actual error message on setMessageReaction rejection', async () => {
182
+ const api = {
183
+ deleteMessage: vi.fn(async () => true as const),
184
+ setMessageReaction: vi.fn(async () => {
185
+ throw new Error('Bad Request: REACTION_INVALID')
186
+ }),
187
+ }
188
+ const lines: string[] = []
189
+ redactAuthCodeMessage(api, '12345', 999, line => lines.push(line))
190
+ await new Promise((resolve) => setTimeout(resolve, 0))
191
+ const failed = lines.find(l => l.includes('reaction FAILED'))
192
+ expect(failed).toBeDefined()
193
+ expect(failed).toMatch(/REACTION_INVALID/)
194
+ })
195
+
196
+ it('logs are independent — failure of one path does not suppress the other', async () => {
197
+ const api = {
198
+ deleteMessage: vi.fn(async () => {
199
+ throw new Error('boom')
200
+ }),
201
+ setMessageReaction: vi.fn(async () => true as const),
202
+ }
203
+ const lines: string[] = []
204
+ redactAuthCodeMessage(api, '12345', 999, line => lines.push(line))
205
+ await new Promise((resolve) => setTimeout(resolve, 0))
206
+ expect(lines).toHaveLength(2)
207
+ expect(lines.some(l => l.includes('reaction added'))).toBe(true)
208
+ expect(lines.some(l => l.includes('delete FAILED'))).toBe(true)
209
+ })
210
+ })
211
+
212
+ /**
213
+ * Architectural pin: every auth-code paste call site MUST go through
214
+ * the helper. Greps the source — if a future PR adds a new auth-code
215
+ * paste handler that forgets to call `redactAuthCodeMessage`, this
216
+ * test fails and points at the right pattern.
217
+ *
218
+ * The current 2 call sites (post-v0.6.13):
219
+ * 1. gateway.ts — bare-code paste during pending reauth (the
220
+ * generic message intercept that watches `pendingReauthFlows`)
221
+ * 2. gateway.ts — /auth code intent dispatch
222
+ *
223
+ * Removed in v0.6.13:
224
+ * - /reauth <code> typed-command shortcut (the entire `bot.command(
225
+ * 'reauth', ...)` handler removed; the dashboard's Reauth button
226
+ * fires the same flow and the generic intercept catches the
227
+ * paste-back).
228
+ *
229
+ * #235 Wave 3 F4: server.ts monolith removed; the 3 server.ts call
230
+ * sites previously listed (bare paste / /auth code / /reauth <code>)
231
+ * no longer exist — gateway.ts is the only file with the live paths.
232
+ */
233
+ describe('auth-code paste call-site coverage (architectural pin)', () => {
234
+ it('every gateway.ts call site calls redactAuthCodeMessage', async () => {
235
+ const fs = await import('node:fs')
236
+ const path = await import('node:path')
237
+ const repoRoot = path.resolve(__dirname, '..', '..')
238
+ const text = fs.readFileSync(
239
+ path.join(repoRoot, 'telegram-plugin', 'gateway', 'gateway.ts'),
240
+ 'utf-8',
241
+ )
242
+ const matches = text.match(/redactAuthCodeMessage\s*\(/g) ?? []
243
+ // 2 call sites + 1 import statement = ≥3. Floor at 2 to be safe.
244
+ // (Pre-v0.6.13 was floor=3 with three call sites including
245
+ // the now-removed /reauth typed handler.)
246
+ expect(matches.length).toBeGreaterThanOrEqual(2)
247
+ })
248
+ })
@@ -0,0 +1,260 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ buildDashboardText,
4
+ buildDashboardKeyboard,
5
+ parseCallbackData,
6
+ encodeCallbackData,
7
+ isQuotaHot,
8
+ buildRemoveConfirmKeyboard,
9
+ QUOTA_HOT_THRESHOLD_PCT,
10
+ type DashboardSlot,
11
+ } from "../auth-dashboard";
12
+
13
+ /**
14
+ * Edge-case coverage for the /auth dashboard. Pair with
15
+ * auth-dashboard.test.ts which covers the happy paths. This file
16
+ * focuses on pathological input, security boundaries, and failure
17
+ * modes we should not regress.
18
+ */
19
+
20
+ function slot(o: Partial<DashboardSlot> = {}): DashboardSlot {
21
+ return { slot: "default", active: false, health: "healthy", quotaExhaustedUntil: null, fiveHourPct: null, sevenDayPct: null, ...o };
22
+ }
23
+
24
+ describe("callback payload — hostile inputs", () => {
25
+ const cases: Array<[string, string]> = [
26
+ ["shell expansion", "auth:reauth:$(whoami)"],
27
+ ["backticks", "auth:reauth:`id`"],
28
+ ["semicolons", "auth:reauth:clerk;ls"],
29
+ ["pipes", "auth:reauth:clerk|nc attacker"],
30
+ ["dot-segments", "auth:use:../../../etc/passwd:default"],
31
+ ["null bytes", "auth:reauth:clerk\0xyz"],
32
+ ["tabs", "auth:reauth:clerk\ttab"],
33
+ ["newlines", "auth:reauth:clerk\nextra"],
34
+ ["leading space", "auth:reauth: clerk"],
35
+ ["trailing space", "auth:reauth:clerk "],
36
+ ["unicode lookalike", "auth:reauth:\u202eevil"],
37
+ ["empty agent", "auth:reauth:"],
38
+ ["empty slot for use", "auth:use:clerk:"],
39
+ ["slot too long (33 chars)", "auth:use:clerk:" + "a".repeat(33)],
40
+ ["agent too long (65 chars)", "auth:reauth:" + "a".repeat(65)],
41
+ ["slot contains dot", "auth:use:clerk:slot.name"],
42
+ ["slot contains slash", "auth:use:clerk:slot/name"],
43
+ ["slot contains space", "auth:use:clerk:slot name"],
44
+ ];
45
+
46
+ it.each(cases)("rejects %s as noop: %s", (_desc, data) => {
47
+ expect(parseCallbackData(data)).toEqual({ kind: "noop" });
48
+ });
49
+
50
+ it("accepts legitimately hyphenated slot names", () => {
51
+ expect(parseCallbackData("auth:use:clerk:backup-1")).toMatchObject({ kind: "use", slot: "backup-1" });
52
+ });
53
+
54
+ it("accepts underscored names", () => {
55
+ expect(parseCallbackData("auth:use:clerk:work_personal")).toMatchObject({ kind: "use", slot: "work_personal" });
56
+ });
57
+ });
58
+
59
+ describe("dashboard text — pathological slot states", () => {
60
+ it("renders 10 slots without breaking layout", () => {
61
+ const slots: DashboardSlot[] = Array.from({ length: 10 }, (_, i) => slot({
62
+ slot: `slot-${i}`,
63
+ active: i === 0,
64
+ }));
65
+ const text = buildDashboardText({ agent: "clerk", bankId: "assistant", plan: "max", slots, quotaHot: false });
66
+ // All 10 slot names appear in the output
67
+ for (let i = 0; i < 10; i++) {
68
+ expect(text).toContain(`slot-${i}`);
69
+ }
70
+ });
71
+
72
+ it("renders when ALL slots are quota-exhausted (fallback-impossible state)", () => {
73
+ const slots = [
74
+ slot({ slot: "default", active: true, health: "quota-exhausted", quotaExhaustedUntil: Date.now() + 60_000 }),
75
+ slot({ slot: "backup", active: false, health: "quota-exhausted", quotaExhaustedUntil: Date.now() + 120_000 }),
76
+ ];
77
+ const text = buildDashboardText({ agent: "clerk", bankId: "assistant", slots, quotaHot: true });
78
+ expect(text).toContain("default");
79
+ expect(text).toContain("backup");
80
+ expect(text.match(/quota-exhausted/g)?.length).toBe(2);
81
+ });
82
+
83
+ it("renders when a slot has zero quota data (no fiveHour/sevenDay pct)", () => {
84
+ const text = buildDashboardText({
85
+ agent: "clerk",
86
+ bankId: "assistant",
87
+ slots: [slot({ active: true, fiveHourPct: null, sevenDayPct: null })],
88
+ quotaHot: false,
89
+ });
90
+ // Shouldn't contain '5h:' or '7d:' if no data
91
+ expect(text).not.toContain("5h:");
92
+ expect(text).not.toContain("7d:");
93
+ });
94
+
95
+ it("handles plan=null gracefully", () => {
96
+ const text = buildDashboardText({
97
+ agent: "clerk",
98
+ bankId: "assistant",
99
+ plan: null,
100
+ slots: [slot({ active: true })],
101
+ quotaHot: false,
102
+ });
103
+ expect(text).toContain("assistant");
104
+ expect(text).not.toContain("Plan:");
105
+ });
106
+
107
+ it("handles 0% utilization (falsy but present)", () => {
108
+ const text = buildDashboardText({
109
+ agent: "clerk",
110
+ bankId: "a",
111
+ slots: [slot({ active: true, fiveHourPct: 0, sevenDayPct: 0 })],
112
+ quotaHot: false,
113
+ });
114
+ expect(text).toContain("5h: 0%");
115
+ expect(text).toContain("7d: 0%");
116
+ });
117
+
118
+ it("handles 100% utilization", () => {
119
+ const text = buildDashboardText({
120
+ agent: "clerk",
121
+ bankId: "a",
122
+ slots: [slot({ active: true, fiveHourPct: 100, sevenDayPct: 100 })],
123
+ quotaHot: true,
124
+ });
125
+ expect(text).toContain("5h: 100%");
126
+ expect(text).toContain("7d: 100%");
127
+ });
128
+
129
+ it("handles negative reset time (already expired)", () => {
130
+ const text = buildDashboardText({
131
+ agent: "clerk",
132
+ bankId: "a",
133
+ slots: [slot({ active: true, health: "quota-exhausted", quotaExhaustedUntil: Date.now() - 60_000 })],
134
+ quotaHot: true,
135
+ });
136
+ // Should clamp to 0 rather than show negative minutes
137
+ expect(text).toContain("resets in ~0m");
138
+ });
139
+
140
+ it("escapes very adversarial agent names", () => {
141
+ const text = buildDashboardText({
142
+ agent: '</b><script>alert("x")</script><b>',
143
+ bankId: "a",
144
+ slots: [slot({ active: true })],
145
+ quotaHot: false,
146
+ });
147
+ expect(text).not.toContain("<script>");
148
+ expect(text).toContain("&lt;script&gt;");
149
+ });
150
+ });
151
+
152
+ describe("dashboard keyboard — edge cases", () => {
153
+ it("caps non-active slot buttons at 3 (prevents runaway rows)", () => {
154
+ const slots = [
155
+ slot({ slot: "active", active: true }),
156
+ slot({ slot: "s1" }),
157
+ slot({ slot: "s2" }),
158
+ slot({ slot: "s3" }),
159
+ slot({ slot: "s4" }),
160
+ slot({ slot: "s5" }),
161
+ ];
162
+ const kb = buildDashboardKeyboard({ agent: "clerk", bankId: "a", slots, quotaHot: false });
163
+ const useButtons = kb.inline_keyboard.flat().filter((b) => b.text.startsWith("Use:"));
164
+ expect(useButtons.length).toBeLessThanOrEqual(3);
165
+ });
166
+
167
+ it("no [Reauth active] button when no active slot", () => {
168
+ const kb = buildDashboardKeyboard({ agent: "clerk", bankId: "a", slots: [slot({ slot: "a", active: false })], quotaHot: false });
169
+ const reauthButton = kb.inline_keyboard.flat().find((b) => b.text.includes("Reauth"));
170
+ // There IS still a Reauth button (agent-level, no slot) — expected behaviour
171
+ expect(reauthButton).toBeDefined();
172
+ // But it should NOT reference a specific slot name
173
+ expect(reauthButton!.text).not.toMatch(/Reauth \S+$/);
174
+ });
175
+
176
+ it("no Use/Remove rows at all when only the active slot exists", () => {
177
+ const kb = buildDashboardKeyboard({ agent: "clerk", bankId: "a", slots: [slot({ active: true })], quotaHot: false });
178
+ const flat = kb.inline_keyboard.flat();
179
+ expect(flat.some((b) => b.text.startsWith("Use:"))).toBe(false);
180
+ expect(flat.some((b) => b.text.startsWith("🗑 Remove:"))).toBe(false);
181
+ });
182
+
183
+ it("empty slot set still shows Add + Refresh", () => {
184
+ const kb = buildDashboardKeyboard({ agent: "clerk", bankId: "a", slots: [], quotaHot: false });
185
+ const flat = kb.inline_keyboard.flat();
186
+ expect(flat.some((b) => b.text.includes("Add slot"))).toBe(true);
187
+ expect(flat.some((b) => b.text.includes("Refresh"))).toBe(true);
188
+ });
189
+
190
+ it("Refresh callback always targets the correct agent", () => {
191
+ const kb = buildDashboardKeyboard({ agent: "specific-agent", bankId: "a", slots: [], quotaHot: false });
192
+ const refreshBtn = kb.inline_keyboard.flat().find((b) => b.text.includes("Refresh"));
193
+ if (refreshBtn && "callback_data" in refreshBtn) {
194
+ expect(refreshBtn.callback_data).toBe("auth:refresh:specific-agent");
195
+ }
196
+ });
197
+ });
198
+
199
+ describe("isQuotaHot — boundary conditions", () => {
200
+ it("99% 5h does NOT trip hot (cold, auto-fallback at 99.5%)", () => {
201
+ expect(isQuotaHot([slot({ fiveHourPct: 89 })])).toBe(false);
202
+ });
203
+
204
+ it("exactly QUOTA_HOT_THRESHOLD_PCT (90%) trips hot", () => {
205
+ expect(isQuotaHot([slot({ fiveHourPct: QUOTA_HOT_THRESHOLD_PCT })])).toBe(true);
206
+ expect(isQuotaHot([slot({ sevenDayPct: QUOTA_HOT_THRESHOLD_PCT })])).toBe(true);
207
+ });
208
+
209
+ it("one hot slot among many cold → hot", () => {
210
+ expect(isQuotaHot([
211
+ slot({ fiveHourPct: 10 }),
212
+ slot({ fiveHourPct: 20 }),
213
+ slot({ fiveHourPct: 95 }),
214
+ slot({ fiveHourPct: 0 }),
215
+ ])).toBe(true);
216
+ });
217
+
218
+ it("quota-exhausted always hot, even with 0% pct", () => {
219
+ expect(isQuotaHot([slot({ health: "quota-exhausted", fiveHourPct: 0, sevenDayPct: 0 })])).toBe(true);
220
+ });
221
+
222
+ it("null utilization doesn't trip", () => {
223
+ expect(isQuotaHot([slot({ fiveHourPct: null, sevenDayPct: null })])).toBe(false);
224
+ });
225
+ });
226
+
227
+ describe("remove confirm keyboard — edge cases", () => {
228
+ it("cancel button refreshes back to the dashboard (doesn't leave orphan)", () => {
229
+ const kb = buildRemoveConfirmKeyboard("clerk", "personal");
230
+ const cancelBtn = kb.inline_keyboard.flat().find((b) => b.text.includes("Cancel"));
231
+ if (cancelBtn && "callback_data" in cancelBtn) {
232
+ expect(cancelBtn.callback_data).toBe("auth:refresh:clerk");
233
+ }
234
+ });
235
+
236
+ it("handles slot names with hyphens/underscores in the confirm label", () => {
237
+ const kb = buildRemoveConfirmKeyboard("clerk", "backup_slot-v2");
238
+ const confirmBtn = kb.inline_keyboard.flat().find((b) => b.text.startsWith("⚠️"));
239
+ expect(confirmBtn?.text).toContain("backup_slot-v2");
240
+ });
241
+ });
242
+
243
+ describe("encode/parse round-trip — lots of identities", () => {
244
+ const actions = [
245
+ { kind: "refresh", agent: "a" },
246
+ { kind: "reauth", agent: "a" },
247
+ { kind: "reauth", agent: "a", slot: "b" },
248
+ { kind: "add", agent: "a" },
249
+ { kind: "use", agent: "a", slot: "b" },
250
+ { kind: "rm", agent: "a", slot: "b" },
251
+ { kind: "confirm-rm", agent: "a", slot: "b" },
252
+ { kind: "fallback", agent: "a" },
253
+ { kind: "usage", agent: "a" },
254
+ ] as const;
255
+
256
+ it.each(actions)("round-trips %s", (action) => {
257
+ const encoded = encodeCallbackData(action);
258
+ expect(parseCallbackData(encoded)).toEqual(action);
259
+ });
260
+ });
@@ -0,0 +1,140 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ buildDashboardText,
4
+ buildDashboardKeyboard,
5
+ encodeCallbackData,
6
+ parseCallbackData,
7
+ type DashboardState,
8
+ type DashboardSlot,
9
+ } from "../auth-dashboard";
10
+
11
+ function slot(o: Partial<DashboardSlot> = {}): DashboardSlot {
12
+ return { slot: "default", active: false, health: "healthy", quotaExhaustedUntil: null, fiveHourPct: null, sevenDayPct: null, ...o };
13
+ }
14
+
15
+ /**
16
+ * PR C — [♻️ Restart flow] dashboard button.
17
+ *
18
+ * Pairs with PR B (automatic stale-session detection). When the user
19
+ * wants to explicitly kill + restart a pending auth flow without
20
+ * waiting for the PKCE challenge to drift, the dashboard surfaces a
21
+ * button keyed by the pending slot name. Gateway routes it to
22
+ * cancel + re-initiate the matching reauth/add.
23
+ */
24
+
25
+ describe("restart-flow callback — encode / parse round-trip", () => {
26
+ it("encodes as auth:restart-flow:<agent>:<slot>", () => {
27
+ expect(encodeCallbackData({ kind: "restart-flow", agent: "clerk", slot: "default" }))
28
+ .toBe("auth:restart-flow:clerk:default");
29
+ expect(encodeCallbackData({ kind: "restart-flow", agent: "lawgpt", slot: "slot-2" }))
30
+ .toBe("auth:restart-flow:lawgpt:slot-2");
31
+ });
32
+
33
+ it("round-trips cleanly", () => {
34
+ for (const action of [
35
+ { kind: "restart-flow", agent: "clerk", slot: "default" },
36
+ { kind: "restart-flow", agent: "lawgpt", slot: "slot-2" },
37
+ { kind: "restart-flow", agent: "klanker", slot: "personal_v2" },
38
+ ] as const) {
39
+ expect(parseCallbackData(encodeCallbackData(action))).toEqual(action);
40
+ }
41
+ });
42
+
43
+ it("rejects restart-flow without a slot (slot is required)", () => {
44
+ // The `use`, `rm`, `confirm-rm`, and `restart-flow` verbs all
45
+ // require a slot. Missing slot → noop (doesn't accidentally fire
46
+ // a wider-scope reset).
47
+ expect(parseCallbackData("auth:restart-flow:clerk")).toEqual({ kind: "noop" });
48
+ expect(parseCallbackData("auth:restart-flow:clerk:")).toEqual({ kind: "noop" });
49
+ });
50
+
51
+ it("rejects unsafe slot names as noop (shell-injection guard)", () => {
52
+ expect(parseCallbackData("auth:restart-flow:clerk:../etc")).toEqual({ kind: "noop" });
53
+ expect(parseCallbackData("auth:restart-flow:clerk:bad slot")).toEqual({ kind: "noop" });
54
+ expect(parseCallbackData("auth:restart-flow:clerk:slot;ls")).toEqual({ kind: "noop" });
55
+ });
56
+
57
+ it("encoded payload fits Telegram's 64-byte callback_data cap", () => {
58
+ // Longest practical: auth:restart-flow:<agent32>:<slot32> = 17 + 32 + 1 + 32 = 82.
59
+ // Agent + slot each capped at 16 chars realistic → well under 64.
60
+ const realistic = encodeCallbackData({
61
+ kind: "restart-flow",
62
+ agent: "a".repeat(16),
63
+ slot: "b".repeat(16),
64
+ });
65
+ expect(realistic.length).toBeLessThanOrEqual(64);
66
+ });
67
+ });
68
+
69
+ describe("dashboard renders [Restart flow] button when pending session exists", () => {
70
+ const base: DashboardState = {
71
+ agent: "lawgpt",
72
+ bankId: "lawgpt",
73
+ plan: "max",
74
+ slots: [slot({ slot: "default", active: true })],
75
+ quotaHot: false,
76
+ };
77
+
78
+ it("omits the button when pendingSessionSlot is absent", () => {
79
+ const kb = buildDashboardKeyboard(base);
80
+ const flat = kb.inline_keyboard.flat();
81
+ expect(flat.some((b) => b.text.includes("Restart"))).toBe(false);
82
+ });
83
+
84
+ it("renders the button when pendingSessionSlot is set", () => {
85
+ const kb = buildDashboardKeyboard({ ...base, pendingSessionSlot: "default" });
86
+ const flat = kb.inline_keyboard.flat();
87
+ const btn = flat.find((b) => b.text.includes("Restart"));
88
+ expect(btn).toBeDefined();
89
+ expect(btn!.text).toContain("default");
90
+ if (btn && "callback_data" in btn && btn.callback_data) {
91
+ expect(btn.callback_data).toBe("auth:restart-flow:lawgpt:default");
92
+ }
93
+ });
94
+
95
+ it("includes slot name in the button label for named-slot pending flows", () => {
96
+ const kb = buildDashboardKeyboard({ ...base, pendingSessionSlot: "slot-2" });
97
+ const flat = kb.inline_keyboard.flat();
98
+ const btn = flat.find((b) => b.text.includes("Restart"));
99
+ expect(btn!.text).toContain("slot-2");
100
+ if (btn && "callback_data" in btn && btn.callback_data) {
101
+ expect(btn.callback_data).toBe("auth:restart-flow:lawgpt:slot-2");
102
+ }
103
+ });
104
+
105
+ it("pendingSessionSlot=null is treated as 'no pending' (no button)", () => {
106
+ const kb = buildDashboardKeyboard({ ...base, pendingSessionSlot: null });
107
+ const flat = kb.inline_keyboard.flat();
108
+ expect(flat.some((b) => b.text.includes("Restart"))).toBe(false);
109
+ });
110
+ });
111
+
112
+ describe("dashboard text includes the pending-flow notice", () => {
113
+ const base: DashboardState = {
114
+ agent: "lawgpt",
115
+ bankId: "lawgpt",
116
+ plan: "max",
117
+ slots: [slot({ active: true })],
118
+ quotaHot: false,
119
+ };
120
+
121
+ it("no notice when no pending", () => {
122
+ const text = buildDashboardText(base);
123
+ expect(text).not.toContain("Auth flow pending");
124
+ expect(text).not.toContain("⏳");
125
+ });
126
+
127
+ it("shows a pending-flow notice when pendingSessionSlot is set", () => {
128
+ const text = buildDashboardText({ ...base, pendingSessionSlot: "slot-2" });
129
+ expect(text).toContain("Auth flow pending");
130
+ expect(text).toContain("slot-2");
131
+ expect(text).toContain("⏳");
132
+ expect(text).toContain("♻️");
133
+ });
134
+
135
+ it("escapes HTML in pendingSessionSlot to guard against injection", () => {
136
+ const text = buildDashboardText({ ...base, pendingSessionSlot: "<script>alert(1)</script>" });
137
+ expect(text).not.toContain("<script>");
138
+ expect(text).toContain("&lt;script&gt;");
139
+ });
140
+ });