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,308 @@
1
+ /**
2
+ * Tests for the Anthropic OAuth browser-code detection added in issue #44.
3
+ *
4
+ * Channel A — anchored pattern (`anthropic_oauth_code`):
5
+ * Positive: two URL-safe base64 segments (≥20 chars each) separated by `#`.
6
+ * Negative: ordinary URL fragments, short anchors, markdown link targets.
7
+ *
8
+ * Channel B — context rule (`awaitingAuthCodeAt` map in gateway.ts):
9
+ * Tested structurally: verify the gateway source wires the map, sets it
10
+ * when emitting the "Paste the browser code here" prompt, checks it on
11
+ * inbound, and clears it after one message.
12
+ */
13
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest'
14
+ import { readFileSync } from 'node:fs'
15
+ import { detectSecrets } from '../secret-detect/index.js'
16
+ import { runPipeline } from '../secret-detect/pipeline.js'
17
+ import { setAuditSink } from '../secret-detect/audit.js'
18
+ import type { VaultWriteFn, VaultListFn } from '../secret-detect/vault-write.js'
19
+
20
+ // ─── Channel A — pattern unit tests ──────────────────────────────────────────
21
+
22
+ describe('anthropic_oauth_code pattern — Channel A', () => {
23
+ it('detects a bare auth code (two long url-safe-b64 segments with #)', () => {
24
+ // Shape emitted by the claude.com/cai authorize flow
25
+ const code = 'tle0rmXYZabc123defGHIjkl#00EySjXYZabc123defGHIjklmno'
26
+ const d = detectSecrets(code)
27
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(true)
28
+ const hit = d.find((h) => h.rule_id === 'anthropic_oauth_code')!
29
+ expect(hit.confidence).toBe('high')
30
+ expect(hit.matched_text).toBe(code)
31
+ })
32
+
33
+ it('detects a code embedded in prose (prefixed with "here is the code:")', () => {
34
+ const code = 'aBcDeFgHiJkLmNoPqRsTuVwX#xYz123456789abcdefghijkl'
35
+ const text = `here is the browser code: ${code} please use it`
36
+ const d = detectSecrets(text)
37
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(true)
38
+ const hit = d.find((h) => h.rule_id === 'anthropic_oauth_code')!
39
+ expect(hit.matched_text).toBe(code)
40
+ })
41
+
42
+ it('does NOT match https:// URL fragments (section anchor)', () => {
43
+ const text = 'see https://example.com/docs#installation for more'
44
+ const d = detectSecrets(text)
45
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(false)
46
+ })
47
+
48
+ it('does NOT match a short first segment (ordinary markdown anchor)', () => {
49
+ // "callback" is only 8 chars — below the 20-char minimum
50
+ const text = 'https://claude.ai/callback#state123456789012345'
51
+ const d = detectSecrets(text)
52
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(false)
53
+ })
54
+
55
+ it('does NOT match a markdown link target like [link](/foo#bar)', () => {
56
+ // "/foo" is 4 chars — well below minimum; "bar" is 3 chars — also below
57
+ const text = '[see here](/features#quickstart-guide)'
58
+ const d = detectSecrets(text)
59
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(false)
60
+ })
61
+
62
+ it('does NOT match when either segment is shorter than 20 chars', () => {
63
+ // First segment: 19 chars (one short)
64
+ const text = 'aBcDeFgHiJkLmNoPqRs#xYz123456789abcdefghijkl'
65
+ const d = detectSecrets(text)
66
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(false)
67
+
68
+ // Second segment: 19 chars
69
+ const text2 = 'aBcDeFgHiJkLmNoPqRsT#xYz123456789abcde'
70
+ const d2 = detectSecrets(text2)
71
+ // "xYz123456789abcde" is 18 chars — below minimum
72
+ expect(d2.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(false)
73
+ })
74
+
75
+ it('flows through runPipeline and stores the code in the vault', () => {
76
+ const store = new Map<string, string>()
77
+ const write: VaultWriteFn = (slug, value) => { store.set(slug, value); return { ok: true, output: 'ok' } }
78
+ const list: VaultListFn = () => ({ ok: true, keys: [...store.keys()] })
79
+
80
+ const code = 'tle0rmXYZabc123defGHIjkl#00EySjXYZabc123defGHIjklmno'
81
+ const res = runPipeline({
82
+ chat_id: 'test-chat',
83
+ message_id: 1,
84
+ text: code,
85
+ passphrase: 'pw',
86
+ vaultWrite: write,
87
+ vaultList: list,
88
+ })
89
+
90
+ expect(res.stored).toHaveLength(1)
91
+ expect(res.stored[0]!.detection.rule_id).toBe('anthropic_oauth_code')
92
+ expect(res.rewritten_text).not.toContain(code)
93
+ expect(res.rewritten_text).toContain('[secret stored as vault:')
94
+ expect([...store.values()]).toContain(code)
95
+ })
96
+ })
97
+
98
+ // ─── Channel B — context rule structural tests ────────────────────────────────
99
+
100
+ describe('auth-flow context rule — Channel B (structural wiring in gateway.ts)', () => {
101
+ const src = readFileSync(
102
+ new URL('../gateway/gateway.ts', import.meta.url),
103
+ 'utf8',
104
+ )
105
+
106
+ it('declares awaitingAuthCodeAt map and AUTH_CODE_CONTEXT_TTL_MS constant', () => {
107
+ expect(src).toMatch(/const awaitingAuthCodeAt = new Map<string, number>/)
108
+ expect(src).toMatch(/AUTH_CODE_CONTEXT_TTL_MS\s*=\s*5\s*\*\s*60_000/)
109
+ })
110
+
111
+ it('sets awaitingAuthCodeAt near the "Paste the browser code here" prompt (before or after)', () => {
112
+ // awaitingAuthCodeAt.set is armed before the ForceReply attempt so that a
113
+ // switchroomReply throw doesn't leave Channel B unarmed. Verify it lives
114
+ // within 500 chars of the prompt string in either direction.
115
+ const promptIdx = src.indexOf("'📋 Paste the browser code here ↓'")
116
+ expect(promptIdx).toBeGreaterThan(0)
117
+ const start = Math.max(0, promptIdx - 500)
118
+ const window = src.slice(start, promptIdx + 500)
119
+ expect(window).toMatch(/awaitingAuthCodeAt\.set\(/)
120
+ })
121
+
122
+ it('clears awaitingAuthCodeAt (delete) in the inbound handler when the flag is active', () => {
123
+ // The inbound handler must call delete after reading the flag
124
+ expect(src).toMatch(/awaitingAuthCodeAt\.delete\(chat_id\)/)
125
+ })
126
+
127
+ it('checks isAuthFlowContext in the secret-detect block (passphrase path)', () => {
128
+ const pipelineIdx = src.indexOf('runPipeline({')
129
+ expect(pipelineIdx).toBeGreaterThan(0)
130
+ // After the pipeline call, isAuthFlowContext must gate the fallback branch
131
+ const tail = src.slice(pipelineIdx, pipelineIdx + 2000)
132
+ expect(tail).toMatch(/isAuthFlowContext/)
133
+ })
134
+
135
+ it('checks isAuthFlowContext in the no-passphrase path (deferred branch)', () => {
136
+ // The no-passphrase branch must also check isAuthFlowContext so a context
137
+ // hit is deferred even without a cached passphrase. (Window widened in
138
+ // #44's PR — the comment block above the branch grew when the legacy
139
+ // "/vault list + re-paste" UX got replaced with the inline-button
140
+ // flow; the structural invariant we're pinning is unchanged.)
141
+ const noPpIdx = src.indexOf('No passphrase cached — detect, but defer')
142
+ expect(noPpIdx).toBeGreaterThan(0)
143
+ const window = src.slice(noPpIdx, noPpIdx + 1200)
144
+ expect(window).toMatch(/isAuthFlowContext/)
145
+ })
146
+
147
+ it('reaps awaitingAuthCodeAt in the TTL reaper alongside other pending-state maps', () => {
148
+ // The pendingStateReaper interval must sweep expired auth-code-context entries
149
+ const reaperIdx = src.indexOf('pendingStateReaper = setInterval')
150
+ expect(reaperIdx).toBeGreaterThan(0)
151
+ const reaperBlock = src.slice(reaperIdx, reaperIdx + 800)
152
+ expect(reaperBlock).toMatch(/awaitingAuthCodeAt/)
153
+ expect(reaperBlock).toMatch(/AUTH_CODE_CONTEXT_TTL_MS/)
154
+ })
155
+
156
+ it('auth-flow context rule sits BEFORE recordInbound() and broadcast()', () => {
157
+ const contextIdx = src.indexOf('isAuthFlowContext')
158
+ const recordIdx = src.indexOf('recordInbound(', contextIdx)
159
+ const broadcastIdx = src.indexOf('ipcServer.broadcast(inboundMsg)', contextIdx)
160
+ expect(contextIdx).toBeGreaterThan(0)
161
+ expect(recordIdx).toBeGreaterThan(contextIdx)
162
+ expect(broadcastIdx).toBeGreaterThan(contextIdx)
163
+ })
164
+ })
165
+
166
+ // ─── New tests for reviewer-requested coverage ────────────────────────────────
167
+
168
+ // Test 1: Negative URL test — Channel A regex must NOT match real URLs with
169
+ // long path segments + long fragment anchors (Blocker 2 regression test).
170
+ describe('anthropic_oauth_code pattern — URL false-positive regression', () => {
171
+ it('does NOT match a URL with long path segment and long fragment (inline in sentence)', () => {
172
+ const text = 'see https://docs.com/getting-started-tutorial#installation-and-setup-guide for details'
173
+ const d = detectSecrets(text)
174
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(false)
175
+ })
176
+
177
+ it('does NOT match a markdown link with long path + long anchor', () => {
178
+ const text = '[docs](https://docs.com/getting-started-tutorial#installation-and-setup-guide)'
179
+ const d = detectSecrets(text)
180
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(false)
181
+ })
182
+
183
+ it('does NOT match a GitHub permalink URL (long path + long heading anchor)', () => {
184
+ const text = 'See https://github.com/owner/repo/blob/main/README.md#installation-and-setup-guide for info.'
185
+ const d = detectSecrets(text)
186
+ expect(d.some((h) => h.rule_id === 'anthropic_oauth_code')).toBe(false)
187
+ })
188
+ })
189
+
190
+ // Test 2: Blocker 1 sequencing — structural check that deleteMessage is called
191
+ // inside the pendingReauthFlows intercept path, before setMessageReaction.
192
+ describe('pendingReauthFlows intercept — deleteMessage sequencing (Blocker 1)', () => {
193
+ const src = readFileSync(
194
+ new URL('../gateway/gateway.ts', import.meta.url),
195
+ 'utf8',
196
+ )
197
+
198
+ it('redacts the OAuth code message inside the pendingReauthFlows intercept', () => {
199
+ // Locate the pendingReauthFlows intercept block. Was previously
200
+ // checked by greppinng for `bot.api.deleteMessage(...)` and
201
+ // `setMessageReaction(...)` literals, but #488 consolidated all 6
202
+ // auth-code paste paths through `redactAuthCodeMessage`. The pin
203
+ // is now: the intercept block must call the helper.
204
+ const interceptIdx = src.indexOf('// Auth-code intercept')
205
+ expect(interceptIdx).toBeGreaterThan(0)
206
+
207
+ // Find the end of this intercept block — the next blank line after
208
+ // the redaction call. Bounds the window so we don't accidentally
209
+ // match a downstream auth-code path's redaction.
210
+ const window = src.slice(interceptIdx, interceptIdx + 2000)
211
+ // Allow the optional 4th `log` argument added in #561 (diagnostic
212
+ // sink for redaction failures) — required is the first three args.
213
+ // `bot.api` may be cast (e.g. `bot.api as never`) for the local
214
+ // BotApi-vs-grammy-Api type mismatch cleanup in #623; `msgId` may
215
+ // be narrowed (`msgId ?? null`).
216
+ expect(window).toMatch(/redactAuthCodeMessage\(bot\.api(?:\s+as\s+\w+)?,\s*chat_id,\s*msgId(?:\s*\?\?\s*null)?(?:,\s*[^)]+)?\)/)
217
+ })
218
+
219
+ it('redaction lands AFTER the success/error reply renders', () => {
220
+ // Sequencing pin: the user-visible reply (success or error) must
221
+ // be queued before the redaction so the user sees the auth result
222
+ // even if their original message disappears mid-render. Same
223
+ // ordering the helper preserves — fire-and-forget redaction
224
+ // happens after `await switchroomReply(...)`.
225
+ const interceptIdx = src.indexOf('// Auth-code intercept')
226
+ const window = src.slice(interceptIdx, interceptIdx + 2000)
227
+ const replyIdx = window.indexOf('switchroomReply(ctx,')
228
+ const redactIdx = window.indexOf('redactAuthCodeMessage(')
229
+ expect(replyIdx).toBeGreaterThan(0)
230
+ expect(redactIdx).toBeGreaterThan(0)
231
+ expect(replyIdx).toBeLessThan(redactIdx)
232
+ })
233
+ })
234
+
235
+ // Test 3: Flag consumption — awaitingAuthCodeAt is NOT cleared on a non-detection
236
+ // inbound (a stray "ok" within the 5-min window should not disarm Channel B).
237
+ describe('awaitingAuthCodeAt flag — consumption only on actual detection', () => {
238
+ const src = readFileSync(
239
+ new URL('../gateway/gateway.ts', import.meta.url),
240
+ 'utf8',
241
+ )
242
+
243
+ it('delete(chat_id) does NOT appear at the top of the isAuthFlowContext block (no early consume)', () => {
244
+ // The old bug: delete fired unconditionally inside `if (isAuthFlowContext)`.
245
+ // After the fix, there must be no `awaitingAuthCodeAt.delete` within
246
+ // the isAuthFlowContext guard block itself — only in the downstream branches.
247
+ const contextIdx = src.indexOf('const isAuthFlowContext =')
248
+ expect(contextIdx).toBeGreaterThan(0)
249
+ // Grab the isAuthFlowContext if-block (ends at the next blank line after the log line)
250
+ const logLineEnd = src.indexOf('\n', src.indexOf('[secret-detect] auth-flow context rule active', contextIdx))
251
+ const guardBlock = src.slice(contextIdx, logLineEnd + 5)
252
+ // Must NOT contain a delete call in the guard itself
253
+ expect(guardBlock).not.toMatch(/awaitingAuthCodeAt\.delete/)
254
+ })
255
+
256
+ it('awaitingAuthCodeAt.delete appears inside the Channel B fallback branch (pipeRes.stored === 0)', () => {
257
+ // Verify the consume is co-located with the actual auth-flow handling
258
+ const fallbackIdx = src.indexOf('Channel B fallback: pattern didn\'t fire')
259
+ expect(fallbackIdx).toBeGreaterThan(0)
260
+ // Within 400 chars after the comment, delete must appear
261
+ const window = src.slice(fallbackIdx, fallbackIdx + 400)
262
+ expect(window).toMatch(/awaitingAuthCodeAt\.delete\(chat_id\)/)
263
+ })
264
+
265
+ it('awaitingAuthCodeAt.delete appears inside the no-passphrase hasHigh branch', () => {
266
+ const noPpIdx = src.indexOf('No passphrase cached — detect, but defer')
267
+ expect(noPpIdx).toBeGreaterThan(0)
268
+ // Window widened — see the matching note on the
269
+ // "checks isAuthFlowContext in the no-passphrase path" test.
270
+ const window = src.slice(noPpIdx, noPpIdx + 1200)
271
+ // Conditional consume: only fires if isAuthFlowContext
272
+ expect(window).toMatch(/if \(isAuthFlowContext\)/)
273
+ expect(window).toMatch(/awaitingAuthCodeAt\.delete\(chat_id\)/)
274
+ })
275
+ })
276
+
277
+ // Test 4: Armer-outside-catch — awaitingAuthCodeAt.set is before the try block,
278
+ // so if switchroomReply throws, Channel B is still armed.
279
+ describe('awaitingAuthCodeAt.set — arming is unconditional (outside catch)', () => {
280
+ const src = readFileSync(
281
+ new URL('../gateway/gateway.ts', import.meta.url),
282
+ 'utf8',
283
+ )
284
+
285
+ it('awaitingAuthCodeAt.set appears BEFORE switchroomReply inside the formatted.url block', () => {
286
+ const urlBlockIdx = src.indexOf('if (formatted.url)')
287
+ expect(urlBlockIdx).toBeGreaterThan(0)
288
+ const urlBlock = src.slice(urlBlockIdx, urlBlockIdx + 800)
289
+ const setIdx = urlBlock.indexOf('awaitingAuthCodeAt.set(')
290
+ const replyIdx = urlBlock.indexOf("'📋 Paste the browser code here ↓'")
291
+ expect(setIdx).toBeGreaterThan(0)
292
+ expect(replyIdx).toBeGreaterThan(0)
293
+ // The .set must come BEFORE the ForceReply switchroomReply call
294
+ expect(setIdx).toBeLessThan(replyIdx)
295
+ })
296
+
297
+ it('awaitingAuthCodeAt.set is NOT inside the inner try block', () => {
298
+ // The inner try starts with "await switchroomReply(ctx, '📋 Paste..."
299
+ // The .set should appear before that try keyword in the formatted.url block
300
+ const urlBlockIdx = src.indexOf('if (formatted.url)')
301
+ const urlBlock = src.slice(urlBlockIdx, urlBlockIdx + 800)
302
+ const setIdx = urlBlock.indexOf('awaitingAuthCodeAt.set(')
303
+ // Find the try block that wraps the ForceReply call
304
+ const innerTryIdx = urlBlock.indexOf('try {', setIdx)
305
+ // The inner try (ForceReply try block) must come AFTER the .set call
306
+ expect(innerTryIdx).toBeGreaterThan(setIdx)
307
+ })
308
+ })
@@ -0,0 +1,123 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest'
2
+ import { runPipeline } from '../secret-detect/pipeline.js'
3
+ import { setAuditSink } from '../secret-detect/audit.js'
4
+ import type { VaultWriteFn, VaultListFn } from '../secret-detect/vault-write.js'
5
+
6
+ function mkFakeVault(): {
7
+ write: VaultWriteFn
8
+ list: VaultListFn
9
+ store: Map<string, string>
10
+ } {
11
+ const store = new Map<string, string>()
12
+ const write: VaultWriteFn = (slug, value) => {
13
+ store.set(slug, value)
14
+ return { ok: true, output: 'ok' }
15
+ }
16
+ const list: VaultListFn = () => ({ ok: true, keys: [...store.keys()] })
17
+ return { write, list, store }
18
+ }
19
+
20
+ describe('pipeline.runPipeline', () => {
21
+ const captured: string[] = []
22
+ beforeEach(() => {
23
+ captured.length = 0
24
+ setAuditSink((line) => captured.push(line))
25
+ })
26
+ afterEach(() => setAuditSink(null))
27
+
28
+ it('stores a high-confidence hit and rewrites the prompt', () => {
29
+ const { write, list, store } = mkFakeVault()
30
+ const text = 'hey here is my key: sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22 thanks'
31
+ const res = runPipeline({
32
+ chat_id: '-100',
33
+ message_id: 5,
34
+ text,
35
+ passphrase: 'pw',
36
+ vaultWrite: write,
37
+ vaultList: list,
38
+ })
39
+ expect(res.stored).toHaveLength(1)
40
+ expect(res.rewritten_text).toContain('[secret stored as vault:')
41
+ expect(res.rewritten_text).not.toContain('sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22')
42
+ // The raw secret made it to the vault under the generated slug.
43
+ expect([...store.values()]).toContain('sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22')
44
+ // Audit emitted once with action=stored.
45
+ const storedLogs = captured.filter((l) => l.includes('"action":"stored"'))
46
+ expect(storedLogs).toHaveLength(1)
47
+ // Raw value never in logs.
48
+ expect(captured.some((l) => l.includes('Apq13yqRnPzx4MxK0TfAbY98Qw22'))).toBe(false)
49
+ })
50
+
51
+ it('stages ambiguous hits without writing to the vault', () => {
52
+ const { write, list, store } = mkFakeVault()
53
+ const text = 'my_password=B4k9NzQ1mT5vR8wP2xY7jH3fL6cD0sA'
54
+ const res = runPipeline({
55
+ chat_id: '-100',
56
+ message_id: 6,
57
+ text,
58
+ passphrase: 'pw',
59
+ vaultWrite: write,
60
+ vaultList: list,
61
+ })
62
+ expect(res.stored).toHaveLength(0)
63
+ expect(res.ambiguous.length).toBeGreaterThan(0)
64
+ // Nothing stored.
65
+ expect(store.size).toBe(0)
66
+ // Text unchanged.
67
+ expect(res.rewritten_text).toBe(text)
68
+ // Audit action=ambiguous.
69
+ expect(captured.some((l) => l.includes('"action":"ambiguous"'))).toBe(true)
70
+ })
71
+
72
+ it('treats suppressed high-confidence hits as ambiguous', () => {
73
+ const { write, list, store } = mkFakeVault()
74
+ const text = 'test sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22'
75
+ const res = runPipeline({
76
+ chat_id: 'c',
77
+ message_id: 1,
78
+ text,
79
+ passphrase: 'pw',
80
+ vaultWrite: write,
81
+ vaultList: list,
82
+ })
83
+ expect(res.stored).toHaveLength(0)
84
+ expect(res.ambiguous.length).toBeGreaterThan(0)
85
+ expect(store.size).toBe(0)
86
+ })
87
+
88
+ it('avoids slug collisions when writing multiple hits', () => {
89
+ const { write, list, store } = mkFakeVault()
90
+ store.set('anthropic_api_key_20260423', 'preexisting')
91
+ const text =
92
+ 'first: sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22 second: sk-ant-BqZ13yqRnPzx4MxK0TfAbY98Qw22'
93
+ const res = runPipeline({
94
+ chat_id: 'c',
95
+ message_id: 2,
96
+ text,
97
+ passphrase: 'pw',
98
+ vaultWrite: write,
99
+ vaultList: list,
100
+ })
101
+ expect(res.stored).toHaveLength(2)
102
+ const slugs = res.stored.map((s) => s.actual_slug)
103
+ // All unique and none collide with the preexisting key.
104
+ expect(new Set(slugs).size).toBe(slugs.length)
105
+ expect(slugs).not.toContain('anthropic_api_key_20260423')
106
+ })
107
+
108
+ it('reports failures without crashing', () => {
109
+ const failingWrite: VaultWriteFn = () => ({ ok: false, output: 'vault busy' })
110
+ const list: VaultListFn = () => ({ ok: true, keys: [] })
111
+ const res = runPipeline({
112
+ chat_id: 'c',
113
+ message_id: 3,
114
+ text: 'key is sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22',
115
+ passphrase: 'pw',
116
+ vaultWrite: failingWrite,
117
+ vaultList: list,
118
+ })
119
+ expect(res.stored).toHaveLength(0)
120
+ expect(res.failed).toHaveLength(1)
121
+ expect(captured.some((l) => l.includes('"action":"failed"'))).toBe(true)
122
+ })
123
+ })
@@ -0,0 +1,101 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import {
3
+ detectViaSecretlint,
4
+ detectSecretsAsync,
5
+ } from '../secret-detect/index.js'
6
+
7
+ // All three fixtures are assembled at runtime so the source file never
8
+ // contains a contiguous token pattern. Matches the corresponding
9
+ // secretlint regex when evaluated; evades GitHub Push Protection's
10
+ // static-text scan. See CLAUDE.md "Secrets in tests".
11
+ const SLACK_FIXTURE = ['xoxb', '0000000000', '0000000000000', 'FIXTURE0NOTAREALTOKEN000'].join('-')
12
+ const GITHUB_FIXTURE = 'ghp' + '_' + '16C7e42F292c6912E7710c838347Ae178B4a'
13
+ const NPM_FIXTURE = 'npm' + '_' + 'AbCdEfGhIjKlMnOpQrStUvWxYz0123456789'
14
+
15
+ describe('secretlint-source.detectViaSecretlint', () => {
16
+ it('catches a realistic-looking Slack bot token', async () => {
17
+ const text = 'Slack: ' + SLACK_FIXTURE
18
+ const hits = await detectViaSecretlint(text)
19
+ expect(hits.length).toBeGreaterThan(0)
20
+ const slack = hits.find((h) => h.rule_id.includes('slack'))
21
+ expect(slack).toBeDefined()
22
+ expect(slack!.confidence).toBe('high')
23
+ expect(slack!.suppressed).toBe(false)
24
+ // rule_id normalized from @secretlint/secretlint-rule-slack → secretlint_slack
25
+ expect(slack!.rule_id).toMatch(/^secretlint_/)
26
+ expect(slack!.rule_id).toContain('slack')
27
+ // Matched text should be the actual token bytes.
28
+ expect(slack!.matched_text.startsWith('xoxb-')).toBe(true)
29
+ // Slug derived from rule_id + date (rule_id fallback path).
30
+ expect(slack!.suggested_slug).toMatch(/^secretlint_slack_\d{8}/)
31
+ })
32
+
33
+ it('catches a GitHub personal access token', async () => {
34
+ const text = 'token=' + GITHUB_FIXTURE + ' rest of message'
35
+ const hits = await detectViaSecretlint(text)
36
+ const gh = hits.find((h) => h.rule_id.includes('github'))
37
+ expect(gh).toBeDefined()
38
+ expect(gh!.confidence).toBe('high')
39
+ expect(gh!.matched_text.startsWith('ghp_')).toBe(true)
40
+ expect(gh!.rule_id).toContain('github')
41
+ })
42
+
43
+ it('catches an NPM access token', async () => {
44
+ const text = 'NPM_TOKEN=' + NPM_FIXTURE
45
+ const hits = await detectViaSecretlint(text)
46
+ const npm = hits.find((h) => h.rule_id.includes('npm'))
47
+ expect(npm).toBeDefined()
48
+ expect(npm!.confidence).toBe('high')
49
+ expect(npm!.matched_text.startsWith('npm_')).toBe(true)
50
+ })
51
+
52
+ it('returns empty for empty input', async () => {
53
+ expect(await detectViaSecretlint('')).toEqual([])
54
+ })
55
+
56
+ it('returns empty for text with no secrets', async () => {
57
+ expect(await detectViaSecretlint('hello how are you today')).toEqual([])
58
+ })
59
+
60
+ it('marks nearby test/mock markers as suppressed', async () => {
61
+ const text = 'test example: ' + SLACK_FIXTURE
62
+ const hits = await detectViaSecretlint(text)
63
+ const slack = hits.find((h) => h.rule_id.includes('slack'))
64
+ expect(slack).toBeDefined()
65
+ expect(slack!.suppressed).toBe(true)
66
+ })
67
+ })
68
+
69
+ describe('detectSecretsAsync merge', () => {
70
+ it('merges Secretlint hits with vendored pattern hits, deduped by range', async () => {
71
+ // Slack token that matches both the vendored anchored pattern AND Secretlint.
72
+ const text = 'a ' + SLACK_FIXTURE + ' end'
73
+ const hits = await detectSecretsAsync(text)
74
+ // One entry for the Slack token — not two. Vendored wins on ties.
75
+ const slackHits = hits.filter(
76
+ (h) => h.matched_text.startsWith('xoxb-'),
77
+ )
78
+ expect(slackHits).toHaveLength(1)
79
+ // Vendored rule id wins on exact-range ties (listed first in merge).
80
+ expect(slackHits[0]!.rule_id).toBe('slack_token')
81
+ })
82
+
83
+ it('adds Secretlint-only hits for providers the vendored list misses', async () => {
84
+ // Shopify is covered by Secretlint preset-recommend but not by our
85
+ // vendored ANCHORED_PATTERNS.
86
+ const text = 'SHOPIFY=shpss_1234567890abcdef1234567890abcdef and go'
87
+ const hits = await detectSecretsAsync(text)
88
+ const shopify = hits.find((h) => h.matched_text.startsWith('shpss_'))
89
+ expect(shopify).toBeDefined()
90
+ expect(shopify!.rule_id).toMatch(/secretlint_shopify/)
91
+ })
92
+
93
+ it('produces unique slugs across the merged detection list', async () => {
94
+ const text =
95
+ 'tok1=' + GITHUB_FIXTURE +
96
+ ' and tok2=' + SLACK_FIXTURE
97
+ const hits = await detectSecretsAsync(text)
98
+ const slugs = hits.map((h) => h.suggested_slug)
99
+ expect(new Set(slugs).size).toBe(slugs.length)
100
+ })
101
+ })
@@ -0,0 +1,45 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { StagingMap } from '../secret-detect/staging.js'
3
+ import type { Detection } from '../secret-detect/index.js'
4
+
5
+ function mkDetection(slug = 'FOO'): Detection {
6
+ return {
7
+ rule_id: 'kv_entropy',
8
+ matched_text: 'abc',
9
+ start: 0,
10
+ end: 3,
11
+ confidence: 'ambiguous',
12
+ suppressed: false,
13
+ suggested_slug: slug,
14
+ }
15
+ }
16
+
17
+ describe('StagingMap', () => {
18
+ it('round-trips a set/get', () => {
19
+ const map = new StagingMap(5_000)
20
+ map.set({ chat_id: 'c', message_id: 1, detection: mkDetection(), staged_at: Date.now() })
21
+ const found = map.get('c', 1)
22
+ expect(found).toBeDefined()
23
+ expect(found!.detection.suggested_slug).toBe('FOO')
24
+ })
25
+ it('expires entries past the TTL', () => {
26
+ const map = new StagingMap(10)
27
+ map.set({ chat_id: 'c', message_id: 1, detection: mkDetection(), staged_at: Date.now() - 1_000 })
28
+ expect(map.get('c', 1)).toBeUndefined()
29
+ })
30
+ it('latestForChat returns the newest non-expired entry', () => {
31
+ const map = new StagingMap(60_000)
32
+ const now = Date.now()
33
+ map.set({ chat_id: 'c', message_id: 1, detection: mkDetection('A'), staged_at: now - 3000 })
34
+ map.set({ chat_id: 'c', message_id: 2, detection: mkDetection('B'), staged_at: now - 2000 })
35
+ map.set({ chat_id: 'c', message_id: 3, detection: mkDetection('C'), staged_at: now - 1000 })
36
+ const latest = map.latestForChat('c')
37
+ expect(latest?.detection.suggested_slug).toBe('C')
38
+ })
39
+ it('delete removes the entry', () => {
40
+ const map = new StagingMap(5_000)
41
+ map.set({ chat_id: 'c', message_id: 1, detection: mkDetection(), staged_at: Date.now() })
42
+ expect(map.delete('c', 1)).toBe(true)
43
+ expect(map.get('c', 1)).toBeUndefined()
44
+ })
45
+ })
@@ -0,0 +1,67 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { detectSecrets } from '../secret-detect/index.js'
3
+ import { runPipeline } from '../secret-detect/pipeline.js'
4
+ import type { VaultWriteFn, VaultListFn } from '../secret-detect/vault-write.js'
5
+
6
+ /**
7
+ * Regression: a suppressor hit (test/mock/example/dummy/fixture nearby)
8
+ * must NEVER silent-allow a structured-pattern match. The asymmetric
9
+ * risk model is: a false-negative leaks a real credential into the
10
+ * agent's session log, a false-positive just briefly redacts a fake
11
+ * one and the user can `ignore` / `forget` to dismiss.
12
+ *
13
+ * The contract:
14
+ * 1. detectSecrets() returns the detection with `suppressed: true`,
15
+ * not an empty list.
16
+ * 2. runPipeline() routes suppressed-high hits into the `ambiguous`
17
+ * bucket (NOT `stored`, NOT silently dropped).
18
+ *
19
+ * Both layers are exercised here so future refactors can't regress
20
+ * this without breaking a test.
21
+ */
22
+ describe('suppressor: never silent-allows on structured matches', () => {
23
+ const phrasings = [
24
+ 'this is a test, here is sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22',
25
+ 'mock token: sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22',
26
+ 'example: sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22',
27
+ 'dummy sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22',
28
+ 'fixture sk-ant-Apq13yqRnPzx4MxK0TfAbY98Qw22',
29
+ ]
30
+
31
+ for (const text of phrasings) {
32
+ it(`detectSecrets surfaces suppressed=true for: ${text.slice(0, 32)}…`, () => {
33
+ const detections = detectSecrets(text)
34
+ expect(detections.length).toBeGreaterThan(0)
35
+ const hit = detections.find((d) => d.rule_id === 'anthropic_api_key')
36
+ expect(hit).toBeDefined()
37
+ expect(hit!.suppressed).toBe(true)
38
+ // confidence is still 'high' — suppressed is the orthogonal flag
39
+ // that downgrades it into the ambiguous tier.
40
+ expect(hit!.confidence).toBe('high')
41
+ })
42
+
43
+ it(`runPipeline routes the suppressed hit to ambiguous (not stored, not dropped) for: ${text.slice(0, 32)}…`, () => {
44
+ const store = new Map<string, string>()
45
+ const write: VaultWriteFn = (slug, value) => {
46
+ store.set(slug, value)
47
+ return { ok: true, output: 'ok' }
48
+ }
49
+ const list: VaultListFn = () => ({ ok: true, keys: [...store.keys()] })
50
+ const res = runPipeline({
51
+ chat_id: 'c',
52
+ message_id: 1,
53
+ text,
54
+ passphrase: 'pw',
55
+ vaultWrite: write,
56
+ vaultList: list,
57
+ })
58
+ // Critical: suppressed hit must NOT silent-pass.
59
+ expect(res.ambiguous.length).toBeGreaterThan(0)
60
+ // Critical: suppressed hit must NOT auto-store.
61
+ expect(res.stored).toHaveLength(0)
62
+ expect(store.size).toBe(0)
63
+ // Text unchanged — the user gets to decide.
64
+ expect(res.rewritten_text).toBe(text)
65
+ })
66
+ }
67
+ })