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,847 @@
1
+ # Multi-Agent Progress Card — Design
2
+
3
+ Status: DRAFT (design only — no code in this PR)
4
+ Audience: implementation worker, reviewer
5
+ Author: design pass by `assistant` agent
6
+ Date: 2026-04-14
7
+
8
+ ---
9
+
10
+ ## 0. TL;DR
11
+
12
+ Today the progress card shows the parent agent's tool sequence inline, and each
13
+ `Agent(...)` dispatch collapses to a single line `🔧 Agent: <description>` that
14
+ flips `✅` whenever the parent receives the matching `tool_result`. When Ken
15
+ fans out 2–4 background sub-agents in parallel, those minutes-long lines reveal
16
+ nothing about what's actually happening.
17
+
18
+ This design proposes a **single-card, two-section layout**:
19
+
20
+ ```
21
+ ⚙️ Working… · ⏱ 02:14
22
+ 💬 <user request, truncated>
23
+ ─ ─ ─
24
+ [Main]
25
+ 🔧 Bash git status (12s)
26
+ ✅ Read MANIFEST.md
27
+ 🤖 Agent: design ux ← (2 sub-agents)
28
+
29
+ [Sub-agents · 2 running, 1 done]
30
+ 🤖 design ux · ⏱ 01:48
31
+ └ 🔧 Read DESIGN.md (8s)
32
+ 🤖 audit deps · ⏱ 00:42
33
+ └ 🔧 Bash npm ls (12s)
34
+ ✅ scan secrets · 00:31 · 6 tools
35
+ ```
36
+
37
+ Hard recommendations:
38
+
39
+ 1. **Flat per-agent sections, NOT a tree.** One section for `Main`, one section
40
+ for `Sub-agents`. Each sub-agent is a 2-line block (header + current activity).
41
+ Trees on Telegram mobile look terrible past one indent level.
42
+ 2. **One source of truth: the projects-dir watcher.** Extend `session-tail.ts`
43
+ to additionally watch `<sessionId>/subagents/agent-*.jsonl`. Each sub-agent
44
+ gets its own tail, projecting events tagged with an `agentId`.
45
+ 3. **Correlation via `promptId` + `prompt` text match.** Parent's `Agent`
46
+ `tool_use` has no `agentId` field; we match on `input.prompt` ↔ subagent's
47
+ first user message `content` string (both share `promptId`). Fallback: most
48
+ recently appeared subagent JSONL with no parent yet.
49
+ 4. **Sub-agents lifecycle: born on Agent tool_use, retired on Agent tool_result.**
50
+ The parent's `tool_result` is the authoritative "this sub-agent is done"
51
+ signal. Sub-JSONL `turn_end` is best-effort, not load-bearing.
52
+ 5. **No recursion.** Sub-sub-agents render as `(spawned 1 sub-agent)` text on
53
+ the parent sub-agent line. Not worth the rendering complexity.
54
+
55
+ LOC estimate: ~600 LOC of impl + ~400 LOC of new tests. Single feature flag
56
+ `PROGRESS_CARD_MULTI_AGENT=1` gates the new path; flag-off behavior is
57
+ byte-identical to today.
58
+
59
+ ---
60
+
61
+ ## 1. UX mockups
62
+
63
+ All character counts are measured AFTER HTML escape and INCLUDE all whitespace +
64
+ newlines. Telegram's `parse_mode=HTML` cap is 4096 characters of body text.
65
+ Mobile readability is judged at iPhone-portrait Telegram default font:
66
+ ~38–40 chars wide before soft-wrap on the SF Mono italic span used for `<i>`.
67
+
68
+ ### 1.1 — 1 main agent, 0 sub-agents, 4 tools done
69
+
70
+ ```
71
+ ⚙️ Working… · ⏱ 00:08
72
+ 💬 list files in /tmp and grep for foo
73
+ ─ ─ ─
74
+ ✅ Bash ls /tmp
75
+ ✅ Read /tmp/notes.md
76
+ ✅ Grep "foo" (in /tmp)
77
+ 🔧 Bash grep -rn foo /tmp (3s)
78
+ ```
79
+
80
+ Char count: ~205. Fits comfortably. Identical shape to today's card — the
81
+ multi-agent structure only kicks in when sub-agents exist.
82
+
83
+ ### 1.2 — 1 main agent + 2 parallel sub-agents, all mid-work
84
+
85
+ ```
86
+ ⚙️ Working… · ⏱ 01:12
87
+ 💬 design ux + audit deps in parallel
88
+ ─ ─ ─
89
+ [Main · 5 tools]
90
+ ✅ Read README.md
91
+ ✅ Bash git status
92
+ 🤖 Agent: design progress card ux (00:48)
93
+ 🤖 Agent: audit npm dependencies (00:42)
94
+ 🔧 Read package.json (2s)
95
+
96
+ [Sub-agents · 2 running]
97
+ 🤖 design progress card ux · ⏱ 00:48
98
+ └ 🔧 Read progress-card.ts (12s) · 4 tools
99
+ 🤖 audit npm dependencies · ⏱ 00:42
100
+ └ 🔧 Bash npm outdated (8s) · 6 tools
101
+ ```
102
+
103
+ Char count: ~510. The two-section split is the load-bearing UX choice.
104
+ The `[Main]` section keeps showing `🤖 Agent:` lines (preserving the parent's
105
+ linear narrative), and the `[Sub-agents]` section gives each sub-agent a
106
+ two-line block: `header` (description + elapsed) and `current activity`
107
+ (currently-running tool + tool count).
108
+
109
+ Why two lines per sub-agent and not one?
110
+ Single-line "🤖 design ux · 🔧 Read foo · 4 tools" reads clean on desktop but
111
+ collapses unreadably on mobile when the description is long ("Investigate
112
+ intermittent test failures in stream-controller suite" — 60+ chars). Two lines
113
+ gives the description its own line and uses a `└` continuation glyph for the
114
+ activity, which renders identically across mobile/desktop/web.
115
+
116
+ ### 1.3 — 4 sub-agents, mixed states, overflow case
117
+
118
+ ```
119
+ ⚙️ Working… · ⏱ 03:42
120
+ 💬 fan out four investigators
121
+ ─ ─ ─
122
+ [Main · 8 tools]
123
+ … (+3 more earlier steps)
124
+ ✅ Bash git log -10
125
+ 🤖 Agent: investigate flake A
126
+ 🤖 Agent: investigate flake B
127
+ 🤖 Agent: investigate flake C
128
+ 🤖 Agent: investigate flake D
129
+ 🔧 Read tsconfig.json (1s)
130
+
131
+ [Sub-agents · 2 running, 1 done, 1 failed]
132
+ ❌ flake C · 01:08 · 9 tools
133
+ ✅ flake A · 02:12 · 14 tools
134
+ 🤖 flake B · ⏱ 03:18
135
+ └ 🔧 Bash bun test races.test.ts (44s) · 11 tools
136
+ 🤖 flake D · ⏱ 02:55
137
+ └ 🔧 Read pty-tail.ts (3s) · 7 tools
138
+ ```
139
+
140
+ Char count: ~720. Completed/failed sub-agents collapse to a one-line summary
141
+ (emoji + short-name + duration + tool count). Running ones keep the two-line
142
+ block. Sort order: failed first (so the user sees red), then done, then running
143
+ ordered by start time. This sort is **stable** — sub-agents don't reorder
144
+ within their bucket between renders.
145
+
146
+ If we hit ~12 sub-agents on a single turn (theoretical extreme), we apply the
147
+ same overflow rule the main checklist already uses: keep all running + last 4
148
+ completed, collapse the rest into `… (+N more completed sub-agents)`. The cap
149
+ keeps total card body under ~1800 chars even in pathological cases.
150
+
151
+ ### 1.4 — turn_end with mixed success/failure
152
+
153
+ ```
154
+ ✅ Done · ⏱ 04:15
155
+ 💬 fan out four investigators
156
+ ─ ─ ─
157
+ [Main · 12 tools]
158
+ … (+8 more earlier steps)
159
+ ✅ Agent: investigate flake A
160
+ ❌ Agent: investigate flake C
161
+ ✅ Agent: investigate flake B
162
+ ✅ Agent: investigate flake D
163
+
164
+ [Sub-agents · 3 done, 1 failed]
165
+ ❌ flake C · 01:08 · 9 tools
166
+ ✅ flake A · 02:12 · 14 tools
167
+ ✅ flake B · 03:30 · 18 tools
168
+ ✅ flake D · 03:55 · 12 tools
169
+ ```
170
+
171
+ Char count: ~510. On `turn_end` we drop the running-sub-agent header section
172
+ entirely (no `[Sub-agents · N running, …]` since none are running), collapse
173
+ each sub-agent to one line, and the header swaps to `✅ Done`. This is the
174
+ final, archived form of the card.
175
+
176
+ ### 1.5 — single sub-agent, hide section header
177
+
178
+ When the parent has spawned exactly one sub-agent and it's still running, we
179
+ DROP the `[Sub-agents · 1 running]` section header and inline the sub-agent
180
+ block directly under the main checklist:
181
+
182
+ ```
183
+ ⚙️ Working… · ⏱ 00:48
184
+ 💬 ask the doc agent
185
+ ─ ─ ─
186
+ [Main · 2 tools]
187
+ ✅ Read CLAUDE.md
188
+ 🤖 Agent: claude code docs
189
+
190
+ 🤖 claude code docs · ⏱ 00:42
191
+ └ 🔧 WebFetch claude.ai/docs (8s) · 3 tools
192
+ ```
193
+
194
+ Char count: ~285. Saves a header line for the common case (1 background
195
+ investigator). The `[Main]` header appears whenever ANY sub-agent exists, so
196
+ the visual rhythm stays consistent.
197
+
198
+ ---
199
+
200
+ ## 2. Information architecture
201
+
202
+ ### 2.1 — Flat sections vs nested tree: pick **flat sections**
203
+
204
+ Considered:
205
+
206
+ - **Tree (indented sub-agent activity under each Agent line in main):** Looks
207
+ natural on desktop, breaks on mobile. Two-level indent eats 6+ chars of
208
+ width. Multiple sub-agents create vertical zigzag that's hard to scan.
209
+ - **Tabbed cards (one card per agent, send N messages):** Burns N × Telegram
210
+ edit budget. Out — exceeds the 20-edits-per-minute cap with 4 sub-agents
211
+ each emitting tool events.
212
+ - **Flat sections (chosen):** Two clearly-labeled blocks separated by a blank
213
+ line. Parent narrative stays linear and intact in `[Main]`; sub-agent
214
+ detail lives in `[Sub-agents]`. Easy to skim top-to-bottom on mobile.
215
+
216
+ Justification: matches how Ken describes his mental model — "main agent" and
217
+ "sub agents" as siblings, not parent/child.
218
+
219
+ ### 2.2 — Per sub-agent fields
220
+
221
+ Required:
222
+
223
+ - `description` — from parent's `Agent` `tool_use.input.description` (or
224
+ `subagent_type` if `description` is empty). Truncated to 50 chars.
225
+ - `state` — `running | done | failed`
226
+ - `elapsedMs` — wall clock since first event in subagent JSONL
227
+ - `toolCount` — number of `tool_use` blocks observed in subagent JSONL
228
+ - `currentTool` — name + label of the most recent still-running tool_use, or
229
+ null if between tools
230
+ - `currentToolElapsedMs` — for the `(8s)` annotation
231
+
232
+ Not rendered (kept in state for future use):
233
+
234
+ - `agentId` (correlation key, not shown to user)
235
+ - `subagentType` (e.g. "claude-code-guide")
236
+ - `model` (haiku vs sonnet — cute but noisy)
237
+
238
+ ### 2.3 — Ken's "main agent task list"
239
+
240
+ **Clarification:** the existing per-tool checklist IS the main agent's task
241
+ list. The new `[Main · N tools]` section is exactly today's checklist, with
242
+ the only behavioral change being that `Agent(...)` lines no longer flip to
243
+ `✅` instantly — they hold `🤖` while the sub-agent is running, and only
244
+ flip to `✅`/`❌` when the parent receives the corresponding `tool_result`.
245
+ This makes the parent narrative honest: today the `🔧 → ✅` flip happens
246
+ the moment Claude Code emits the placeholder, which is misleading.
247
+
248
+ ### 2.4 — Overflow strategy
249
+
250
+ Single rule, applied per section:
251
+
252
+ - `[Main]`: existing rule (last 12, with `… (+N more earlier steps)`).
253
+ - `[Sub-agents]`: keep ALL running, plus the last 4 done/failed. Collapse
254
+ earlier done/failed into `… (+N more completed sub-agents)`. No collapse if
255
+ total ≤ 6.
256
+
257
+ If the rendered card exceeds 3500 chars (safety margin under the 4096 cap),
258
+ truncate the `[Main]` `(label)` portions first (drop file path hints), then
259
+ reduce `[Main]` visible cap from 12 → 6, then collapse all done sub-agents
260
+ into a single rollup line. These three steps fit any plausibly-large turn.
261
+
262
+ ### 2.5 — Update cadence
263
+
264
+ Same as today, with one addition:
265
+
266
+ - Event-driven: every state transition (new tool_use, tool_result,
267
+ sub-agent born, sub-agent retired) schedules a flush via the existing
268
+ coalesce timer (`max(coalesceMs, minIntervalMs - sinceLast)`).
269
+ - Heartbeat: same 5s heartbeat; now considers a sub-agent state's
270
+ `currentToolElapsedMs` bucket too, so per-sub-agent `(Ns)` ticks visibly.
271
+ - New: **sub-agent event coalescing**. When the same sub-agent emits 3+ events
272
+ inside the coalesce window, only the LAST is rendered. This prevents a
273
+ burst of fast Reads in one sub-agent from monopolizing Telegram's edit
274
+ budget.
275
+
276
+ ---
277
+
278
+ ## 3. Data model
279
+
280
+ ### 3.1 — Types
281
+
282
+ ```ts
283
+ // progress-card.ts
284
+
285
+ export type AgentRole = 'main' | 'sub'
286
+ export type ItemState = 'pending' | 'running' | 'done' | 'failed'
287
+ export type Stage = 'plan' | 'run' | 'done'
288
+
289
+ export interface ChecklistItem {
290
+ readonly id: number
291
+ readonly toolUseId: string | null
292
+ readonly tool: string
293
+ readonly label: string
294
+ readonly state: ItemState
295
+ readonly startedAt: number
296
+ readonly finishedAt?: number
297
+ /**
298
+ * For Agent/Task tool_use only: the `agentId` of the spawned sub-agent
299
+ * once correlation succeeds. Null until correlation lands. Used by the
300
+ * renderer to keep the [Main] line in `🤖` (not `✅`) until the parent's
301
+ * tool_result arrives.
302
+ */
303
+ readonly spawnedAgentId?: string | null
304
+ }
305
+
306
+ export interface SubAgentState {
307
+ readonly agentId: string // subagent JSONL filename stem
308
+ readonly description: string // from parent Agent tool_use input
309
+ readonly subagentType?: string
310
+ /** Parent's tool_use_id ("toolu_…") that spawned this sub-agent. */
311
+ readonly parentToolUseId: string | null
312
+ readonly state: ItemState // running | done | failed
313
+ readonly startedAt: number
314
+ readonly finishedAt?: number
315
+ readonly toolCount: number
316
+ /** Latest still-running tool inside this sub-agent. */
317
+ readonly currentTool?: {
318
+ readonly tool: string
319
+ readonly label: string
320
+ readonly toolUseId: string
321
+ readonly startedAt: number
322
+ }
323
+ /**
324
+ * If this sub-agent itself spawned sub-sub-agents, count them so we can
325
+ * render "(spawned N)" inline. We do NOT recurse — keeping it simple.
326
+ */
327
+ readonly nestedSpawnCount: number
328
+ }
329
+
330
+ export interface ProgressCardState {
331
+ readonly turnStartedAt: number
332
+ readonly userRequest?: string
333
+ readonly items: ReadonlyArray<ChecklistItem> // main agent's checklist
334
+ readonly subAgents: ReadonlyMap<string, SubAgentState> // by agentId
335
+ /**
336
+ * Pending parent Agent tool_uses awaiting correlation to a sub-agent.
337
+ * Keyed by parentToolUseId. When a subagent JSONL appears with a
338
+ * matching first-user-message text, we move from pending → subAgents.
339
+ */
340
+ readonly pendingAgentSpawns: ReadonlyMap<string, {
341
+ parentToolUseId: string
342
+ description: string
343
+ promptText: string
344
+ startedAt: number
345
+ }>
346
+ readonly stage: Stage
347
+ readonly thinking: boolean
348
+ readonly latestText?: string
349
+ }
350
+ ```
351
+
352
+ ### 3.2 — Event types (additions to `SessionEvent`)
353
+
354
+ ```ts
355
+ export type SessionEvent =
356
+ | { kind: 'enqueue'; ... } // unchanged
357
+ | { kind: 'dequeue' } // unchanged
358
+ | { kind: 'thinking' } // unchanged
359
+ | { kind: 'tool_use'; ... } // unchanged
360
+ | { kind: 'tool_result'; ... } // unchanged
361
+ | { kind: 'text'; text: string } // unchanged
362
+ | { kind: 'turn_end'; durationMs: number } // unchanged
363
+ // NEW: sub-agent-scoped events. Carry agentId so the reducer routes
364
+ // them to the correct SubAgentState.
365
+ | { kind: 'sub_agent_started'; agentId: string; firstPromptText: string; subagentType?: string }
366
+ | { kind: 'sub_agent_tool_use'; agentId: string; toolUseId: string | null; toolName: string; input?: Record<string, unknown> }
367
+ | { kind: 'sub_agent_tool_result'; agentId: string; toolUseId: string; isError?: boolean }
368
+ | { kind: 'sub_agent_turn_end'; agentId: string }
369
+ | { kind: 'sub_agent_nested_spawn'; agentId: string } // sub-sub-agent observed; we don't render it but count it
370
+ ```
371
+
372
+ ### 3.3 — Reducer mapping
373
+
374
+ | Event | State change |
375
+ |---|---|
376
+ | `enqueue` | reset `initialState()`, set `turnStartedAt`, `userRequest`, `stage='plan'` |
377
+ | `tool_use` (name=`Agent` or `Task`) | append `ChecklistItem{state: running}`, store `pendingAgentSpawns[toolUseId] = {description, promptText: input.prompt}` |
378
+ | `tool_use` (other) | append `ChecklistItem{state: running}` (unchanged) |
379
+ | `tool_result` (matches Agent toolUseId) | flip main item to `done|failed`; if `subAgents` has entry with `parentToolUseId == toolUseId`, mark sub-agent `done|failed` and stop tracking |
380
+ | `tool_result` (other) | flip main item to `done|failed` (unchanged) |
381
+ | `sub_agent_started` | match `firstPromptText` against `pendingAgentSpawns` entries; on hit, move to `subAgents`, set `parentToolUseId`, `startedAt=now`, `state='running'`. Also set `items[i].spawnedAgentId` for the matching Agent line. On miss, create an "orphan" `SubAgentState` with `parentToolUseId=null`. |
382
+ | `sub_agent_tool_use` | for `subAgents[agentId]`: increment `toolCount`, set `currentTool` |
383
+ | `sub_agent_tool_result` | for `subAgents[agentId]`: clear `currentTool` if matching toolUseId; on `isError=true` keep the count but don't change agent-level state (per-tool errors don't fail the agent — only the parent tool_result does) |
384
+ | `sub_agent_turn_end` | for `subAgents[agentId]`: set `state='done'`, `finishedAt=now` (best-effort early signal; final state still set when parent's Agent tool_result lands) |
385
+ | `sub_agent_nested_spawn` | for `subAgents[agentId]`: `nestedSpawnCount++` |
386
+ | `turn_end` | close stragglers in items + subAgents, `stage='done'` |
387
+
388
+ ### 3.4 — Why correlation by prompt text, not by agentId
389
+
390
+ The parent's `Agent` `tool_use` has these fields: `id` (toolu_…), `name`,
391
+ `input.subagent_type`, `input.description`, `input.prompt`. **No agentId.** The
392
+ sub-agent JSONL filename embeds `agentId`. The first user message inside the
393
+ subagent JSONL contains exactly the `input.prompt` string (verified empirically
394
+ against `~/.claude/projects/-home-<user>/0887bb59-…`).
395
+
396
+ So the only deterministic correlation is:
397
+
398
+ ```
399
+ parent.input.prompt === subagent_jsonl[firstUserMessage].message.content
400
+ ```
401
+
402
+ Both also share `promptId`, but `promptId` is per-USER-TURN, not per-Agent-call.
403
+ A turn that spawns 4 parallel sub-agents will have 4 sub-agent JSONLs all
404
+ sharing the same `promptId`. Prompt-text match disambiguates within a turn.
405
+
406
+ Edge case: two parallel Agent calls with IDENTICAL prompt text (Ken running
407
+ "do X" twice as a duplicate). We fall back to FIFO assignment (first unmatched
408
+ pending spawn wins) and log a warning. Acceptable — duplicates are rare and
409
+ the visual cost is just "one sub-agent shows the wrong description for ~1s
410
+ until tool_result". No correctness harm.
411
+
412
+ ---
413
+
414
+ ## 4. Implementation plan
415
+
416
+ ### 4.1 — `session-tail.ts`: discover and tail subagent JSONLs
417
+
418
+ Today the tail watches the projects dir for `*.jsonl` and picks the
419
+ newest-mtime. New behavior:
420
+
421
+ 1. Continue watching `projectsDir` for the parent JSONL (unchanged path).
422
+ 2. NEW: also watch `projectsDir/<sessionId>/subagents/` (one dir per
423
+ active session). Discover sessionIds by stripping `.jsonl` from the
424
+ parent file.
425
+ 3. For each `agent-*.jsonl` file in any `subagents/` dir, attach a
426
+ per-file tailer (same machinery as the parent tail — cursor, partial
427
+ buffer, fs.watch + poll fallback). Identify it by `agentId` =
428
+ filename stem minus `agent-`.
429
+ 4. Project each line through `projectSubagentLine(line, agentId)` (new
430
+ function) which emits the new `sub_agent_*` events.
431
+ 5. On `subagents/` dir creation/deletion, the supervisor adds/removes
432
+ tails. Use `fs.watch(projectsDir, recursive: false)` for parent and
433
+ `fs.watch(subagentsDir)` per-subdir. Poll fallback every
434
+ `rescanIntervalMs` for safety (matches the existing pattern).
435
+
436
+ Why per-file tails (not one global "scan newest"): with N sub-agents writing
437
+ in parallel, mtime ping-pong is constant. Per-file cursors (already a fix in
438
+ PR #25 for parent vs sub-mtime ping-pong) generalize cleanly.
439
+
440
+ Cleanup: when the `currentChatId` ends a turn (`turn_end` lands), close all
441
+ attached subagent tailers. Do NOT close them on `sub_agent_turn_end` — the
442
+ sub-agent JSONL may still get tailing tool_results we want to capture
443
+ post-completion (rare but cheap to handle).
444
+
445
+ ### 4.2 — Parsing subagent JSONL events
446
+
447
+ Subagent JSONL line shapes (verified):
448
+
449
+ ```jsonc
450
+ // First line — sub-agent's "user" message (prompt from parent)
451
+ {"isSidechain": true, "agentId": "aac6...", "type": "user",
452
+ "message": {"role": "user", "content": "<prompt text>"}, ...}
453
+
454
+ // Subsequent assistant messages with tool_use
455
+ {"isSidechain": true, "agentId": "aac6...", "type": "assistant",
456
+ "message": {"content": [{"type": "tool_use", "id": "toolu_...", "name": "Read", "input": {...}}]}}
457
+
458
+ // tool_results
459
+ {"isSidechain": true, "agentId": "aac6...", "type": "user",
460
+ "message": {"content": [{"type": "tool_result", "tool_use_id": "toolu_...", "is_error": false}]}}
461
+ ```
462
+
463
+ `projectSubagentLine` mirrors `projectTranscriptLine` with three differences:
464
+ emits `sub_agent_*` event variants, ignores `enqueue`/`dequeue` (sub-agents
465
+ don't have queue ops), and emits `sub_agent_started` ONLY for the first
466
+ `type=user` message in the file (track via "have we emitted started yet?"
467
+ flag in the per-file tail state).
468
+
469
+ ### 4.3 — Correlation: parent Agent tool_use ↔ subagent JSONL
470
+
471
+ Parent's `Agent` tool_use carries `input.prompt`. Subagent's first user
472
+ message has `message.content` which is exactly that string.
473
+
474
+ Reducer logic (in pseudo-code):
475
+
476
+ ```
477
+ on sub_agent_started(agentId, firstPromptText):
478
+ for [parentToolUseId, pending] in pendingAgentSpawns:
479
+ if pending.promptText === firstPromptText:
480
+ subAgents.set(agentId, {parentToolUseId, description: pending.description, ...})
481
+ items.find(i => i.toolUseId === parentToolUseId).spawnedAgentId = agentId
482
+ pendingAgentSpawns.delete(parentToolUseId)
483
+ return
484
+ // No match — orphan. Could be a stale subagent JSONL from a prior
485
+ // session, or correlation failed. Render as "(unknown sub-agent)".
486
+ subAgents.set(agentId, {parentToolUseId: null, description: '(unknown)', ...})
487
+ ```
488
+
489
+ If the parent's `Agent` `tool_use` arrives BEFORE the subagent JSONL appears
490
+ (common — JSONL is created async by Claude Code), the entry sits in
491
+ `pendingAgentSpawns` and the `[Main]` line shows `🤖 Agent: <description>`
492
+ without sub-agent activity. When the subagent JSONL lands ~50–200ms later,
493
+ correlation completes and the `[Sub-agents]` block populates.
494
+
495
+ If subagent JSONL arrives BEFORE parent (race in the other direction —
496
+ unlikely but possible if fs.watch on parent JSONL is slow), the subagent
497
+ becomes an "orphan" temporarily. Re-correlation runs every time a new pending
498
+ spawn lands: when the parent `Agent` tool_use eventually arrives, we check
499
+ existing orphan `subAgents` entries for matching `firstPromptText` (we keep
500
+ the first prompt text as part of `SubAgentState` for this lookup) and adopt.
501
+
502
+ **Blocker check:** if Claude Code ever ships a release where `input.prompt`
503
+ is omitted from the parent's `Agent` tool_use (truncated, or replaced with
504
+ a hash), correlation breaks. Mitigation: add a `promptId`-based fallback
505
+ (group by promptId, FIFO assign). Both signals are cheap to keep.
506
+
507
+ ### 4.4 — Rate limit handling
508
+
509
+ Telegram allows ~1 edit/sec/chat, hard cap 20/min. The card is one message,
510
+ one chat. Today's coalesce + min-interval logic handles bursty parent events.
511
+ Multi-agent adds N parallel event sources, so:
512
+
513
+ 1. **Same coalesce timer for ALL agents.** A single per-chat timer collects
514
+ pending state mutations from any source (parent, sub-agent A, sub-agent B,
515
+ …) and fires one render. This is already how the driver works — sub-agent
516
+ events route through the same `ingest` path with the same `chatId`.
517
+ 2. **Edit-budget guardrail.** New: track edits emitted in the last 60s per
518
+ chat. If >18 in last 60s, switch to a 3s coalesce window until the rate
519
+ drops. The chosen "winner" event when over budget is just "the latest
520
+ render" (no event-level prioritization — render() reflects current state).
521
+ 3. **Heartbeat respects budget too** — heartbeat skips if rate is >18/min.
522
+
523
+ ### 4.5 — Sub-agent lifecycle close-out
524
+
525
+ Two signals exist:
526
+ - (a) Parent's `tool_result` for the Agent `tool_use` — authoritative.
527
+ - (b) Sub-agent JSONL `turn_end` — early hint, sub-agent finished its work
528
+ but parent hasn't received the response yet (~100ms gap).
529
+
530
+ Rule: **(a) is canonical.** Sub-agent flips to `done`/`failed` on (a). On (b),
531
+ we set a tentative `state='done'` (so the UI feels responsive) but do NOT
532
+ delete from `subAgents`. The parent `tool_result` finalizes (and can override
533
+ to `failed` if `isError=true`). This gives users instant "done" feedback
534
+ while keeping the parent as the source of truth.
535
+
536
+ Test invariants this enforces:
537
+ - A sub-agent that finished its work but whose parent Agent tool_result is
538
+ delayed renders as ✅ during the gap.
539
+ - If a sub-agent crashes mid-execution (no `turn_end` in subagent JSONL),
540
+ the parent's `tool_result` with `isError=true` flips it to ❌. Reliable
541
+ fallback.
542
+
543
+ ### 4.6 — Error handling
544
+
545
+ | Failure mode | Behavior |
546
+ |---|---|
547
+ | `subagents/` subdir doesn't exist | No-op. Watch parent dir for the subdir to be created. |
548
+ | Malformed subagent JSONL line | Skip (matches existing parent behavior). Log at debug. |
549
+ | Subagent JSONL appears with `agentId` we already track (re-attach) | Use per-file cursor map — same trick PR #25 uses for parent. |
550
+ | Parent Agent tool_use never gets a tool_result | At `turn_end`, the reducer's existing "close stragglers" loop flips both the main item AND the sub-agent to `done`. |
551
+ | Subagent JSONL missing entirely (Claude Code didn't write one) | The `pendingAgentSpawns` entry sits forever; rendered as `🤖 Agent: <desc>` with no sub-agent block. At `turn_end`, the line flips to `✅`. No `[Sub-agents]` block ever appears for that spawn. Acceptable degradation. |
552
+ | Correlation fails (prompt text mismatch) | Sub-agent renders in `[Sub-agents]` with `description='(uncorrelated)'`. Doesn't break the card. |
553
+ | `fs.watch` on subagents/ unreliable (WSL, network mounts) | Same poll fallback as parent (`rescanIntervalMs`). |
554
+
555
+ ---
556
+
557
+ ## 5. Test harness additions
558
+
559
+ All scenarios go in `tests/progress-card-harness.test.ts`. The harness's
560
+ `mkProjectsDir` already creates the right shape; add a helper
561
+ `mkSubagentJsonl(projectsDir, sessionId, agentId)` that ensures
562
+ `<projectsDir>/<sessionId>/subagents/agent-<agentId>.jsonl` exists.
563
+
564
+ New JSONL line builders:
565
+
566
+ ```ts
567
+ const subAgentUserLine = (agentId: string, promptText: string): string =>
568
+ JSON.stringify({
569
+ isSidechain: true, agentId, type: 'user',
570
+ message: { role: 'user', content: promptText },
571
+ }) + '\n'
572
+
573
+ const subAgentToolUseLine = (agentId: string, toolUseId: string, name: string, input: Record<string, unknown>): string =>
574
+ JSON.stringify({
575
+ isSidechain: true, agentId, type: 'assistant',
576
+ message: { content: [{ type: 'tool_use', id: toolUseId, name, input }] },
577
+ }) + '\n'
578
+
579
+ const subAgentToolResultLine = (agentId: string, toolUseId: string, isError = false): string =>
580
+ JSON.stringify({
581
+ isSidechain: true, agentId, type: 'user',
582
+ message: { content: [{ type: 'tool_result', tool_use_id: toolUseId, is_error: isError }] },
583
+ }) + '\n'
584
+
585
+ const parentAgentToolUseLine = (toolUseId: string, description: string, prompt: string): string =>
586
+ JSON.stringify({
587
+ type: 'assistant',
588
+ message: { content: [{
589
+ type: 'tool_use', id: toolUseId, name: 'Agent',
590
+ input: { subagent_type: 'researcher', description, prompt },
591
+ }] },
592
+ }) + '\n'
593
+ ```
594
+
595
+ ### 5.1 — Scenario: 4 parallel sub-agents, all correlate
596
+
597
+ Steps:
598
+ 1. Create parent JSONL `session-A.jsonl`, `subagents/` dir.
599
+ 2. Append parent enqueue.
600
+ 3. Append 4 parent `Agent` tool_uses with prompts P1..P4.
601
+ 4. Wait 50ms → assert `[Main]` shows 4 `🤖 Agent:` lines, no `[Sub-agents]`
602
+ block yet (no subagent JSONLs exist).
603
+ 5. Create 4 subagent JSONLs in random order; first line of each is the matching
604
+ prompt text.
605
+ 6. Wait 100ms → assert `[Sub-agents · 4 running]` block exists and each
606
+ sub-agent shows the right description (correlation worked).
607
+ 7. Append `Read` tool_use to each subagent JSONL → assert each row shows
608
+ `└ 🔧 Read …`.
609
+ 8. Append parent `tool_result` for all 4 Agent tool_uses → assert all
610
+ sub-agents flip to `✅` and `[Main]` lines flip to `✅ Agent:`.
611
+ 9. Append parent `turn_end` → assert one `done=true` edit, exactly.
612
+
613
+ ### 5.2 — Scenario: sub-agent finishes before parent tool_result
614
+
615
+ Steps:
616
+ 1. Single sub-agent setup as in 5.1.
617
+ 2. Subagent JSONL appends a `turn_duration` line (sub_agent_turn_end) BEFORE
618
+ parent appends the matching `tool_result`.
619
+ 3. Assert sub-agent shows `✅` after turn_end (early-success state).
620
+ 4. Append parent `tool_result` 200ms later → assert it stays `✅` and parent
621
+ `[Main]` line flips to `✅`.
622
+ 5. Reverse case: sub-agent `turn_end` first, then parent `tool_result` with
623
+ `isError=true` → assert sub-agent flips ✅ → ❌ (parent overrides).
624
+
625
+ ### 5.3 — Scenario: subagent JSONL appears AFTER parent tool_use (race)
626
+
627
+ Most common race in production — the parent tool_use is in the JSONL ~10ms
628
+ before Claude Code has flushed the subagent JSONL.
629
+
630
+ Steps:
631
+ 1. Append parent `Agent` tool_use.
632
+ 2. Wait 30ms (no subagent JSONL yet) → assert `[Main]` shows `🤖 Agent: …`,
633
+ no `[Sub-agents]` block.
634
+ 3. Create subagent JSONL with matching prompt text.
635
+ 4. Wait 100ms → assert correlation succeeds, `[Sub-agents]` block populated.
636
+
637
+ ### 5.4 — Scenario: subagent JSONL appears BEFORE parent tool_use (reverse race)
638
+
639
+ Steps:
640
+ 1. Create subagent JSONL with prompt text P1 (no parent Agent tool_use yet).
641
+ 2. Wait 50ms → assert `[Sub-agents]` block shows ONE entry with
642
+ `description='(uncorrelated)'`.
643
+ 3. Append parent `Agent` tool_use with prompt=P1.
644
+ 4. Wait 100ms → assert the `(uncorrelated)` entry adopts the description
645
+ from the parent and links to the `[Main]` Agent line.
646
+
647
+ ### 5.5 — Scenario: sub-sub-agent (recursion)
648
+
649
+ Steps:
650
+ 1. Sub-agent A is correlated and running.
651
+ 2. Sub-agent A's JSONL contains an `Agent` tool_use of its own (sub-A spawns
652
+ sub-B). A subagent JSONL `agent-B.jsonl` appears.
653
+ 3. Assert: `[Sub-agents]` shows sub-agent A with `(spawned 1 sub-agent)`
654
+ suffix on the description line. Sub-agent B is NOT rendered as a
655
+ top-level row. Tool count for A includes A's tool_uses but NOT B's.
656
+ 4. When sub-A's parent Agent tool_result arrives (yes, sub-agents themselves
657
+ wait for tool_result), no card-level state changes for sub-B (it's
658
+ invisible).
659
+
660
+ This locks in the "no recursion" rendering choice via tests.
661
+
662
+ ### 5.6 — Scenario: overflow, 12 sub-agents, 8 done
663
+
664
+ Steps:
665
+ 1. Spawn 12 sub-agents in sequence, complete 8, leave 4 running.
666
+ 2. Assert `[Sub-agents · 4 running, 4 done]` (header counts), shows
667
+ the 4 running + last 4 done explicitly, plus `… (+4 more completed
668
+ sub-agents)`.
669
+ 3. Assert total card body < 3500 chars.
670
+
671
+ ### 5.7 — Scenario: subagent JSONL is malformed mid-stream
672
+
673
+ Steps:
674
+ 1. Sub-agent A running normally.
675
+ 2. Append a garbled line (not valid JSON) to its JSONL.
676
+ 3. Append more valid lines.
677
+ 4. Assert: garbled line silently skipped, subsequent valid events still
678
+ processed.
679
+
680
+ ### 5.8 — Scenario: rate-limit budget cap
681
+
682
+ Steps:
683
+ 1. Use injected fake timers + a chat with a rapid burst of sub-agent
684
+ tool_uses (50 events in 5 seconds across 4 sub-agents).
685
+ 2. Assert `bot.edits.length <= 20` (Telegram cap respected) over a
686
+ 60-second window.
687
+
688
+ ---
689
+
690
+ ## 6. Open questions for Ken
691
+
692
+ Five genuine decisions that should be made before the worker starts:
693
+
694
+ **Q1 — Sort order in `[Sub-agents]` section.**
695
+ Proposed: failed → done → running (by start time). Alternative: pure
696
+ chronological (running mixed with done). Failed-first surfaces problems but
697
+ shuffles items between renders when one fails late.
698
+ *Default if no answer: failed → done → running.*
699
+
700
+ **Q2 — Show sub-agent's `subagent_type` (e.g. "researcher", "claude-code-guide")?**
701
+ Could append `· researcher` after the description. Useful for users
702
+ juggling many specialized agents; noisy if every agent is the same type.
703
+ *Default if no answer: omit.*
704
+
705
+ **Q3 — Recursion: render sub-sub-agents at all?**
706
+ Design assumes NO (just `(spawned N)` count on parent sub-agent line). If
707
+ Ken's sub-agents themselves spawn investigators, he might want a depth-2
708
+ tree. Cost: ~150 LOC + 3 more test scenarios + tighter overflow rules.
709
+ *Default if no answer: no, just count them.*
710
+
711
+ **Q4 — Should the `[Main]` Agent line still show when its sub-agent completes
712
+ before the parent receives the tool_result?**
713
+ Current proposal: stays `🤖` until parent's `tool_result` arrives (honest).
714
+ Alternative: flip to `✅` on `sub_agent_turn_end` (more responsive but
715
+ inconsistent with how every other tool line works).
716
+ *Default if no answer: stay `🤖` until parent tool_result.*
717
+
718
+ **Q5 — On `turn_end`, do we keep the `[Sub-agents]` block in the final
719
+ archived card, or collapse it into a single summary line?**
720
+ Proposed: keep it (full sub-agent breakdown is valuable retrospectively).
721
+ Alternative: replace with `[3 sub-agents · 47 tools total · 04:15]`.
722
+ *Default if no answer: keep the block.*
723
+
724
+ ---
725
+
726
+ ## 7. Rollout plan
727
+
728
+ ### 7.1 — Incremental ship
729
+
730
+ Suggested PR sequence:
731
+
732
+ **PR-A (foundation, ~250 LOC):**
733
+ - Add per-file subagent JSONL tailer plumbing in `session-tail.ts`.
734
+ - Project `sub_agent_*` events but DROP them in the driver (no behavior
735
+ change yet). Behind feature flag `PROGRESS_CARD_MULTI_AGENT=1`.
736
+ - Test 5.7 (malformed JSONL) lands.
737
+
738
+ **PR-B (correlation + state, ~200 LOC):**
739
+ - Reducer changes: `pendingAgentSpawns`, `subAgents` map, correlation
740
+ on `sub_agent_started`. Renderer unchanged (still drops the data).
741
+ - Tests 5.3 + 5.4 (race conditions) land.
742
+
743
+ **PR-C (renderer, ~150 LOC):**
744
+ - New `[Main]` / `[Sub-agents]` two-section render. Behind feature flag.
745
+ - Tests 5.1, 5.2, 5.5, 5.6 land.
746
+
747
+ **PR-D (rate limit + heartbeat refinements, ~100 LOC):**
748
+ - Per-chat edit budget tracking, sub-agent-aware heartbeat buckets.
749
+ - Test 5.8 lands.
750
+
751
+ **PR-E (flag flip):**
752
+ - Default `PROGRESS_CARD_MULTI_AGENT=1`. Documentation update.
753
+ - Old behavior kept under `PROGRESS_CARD_MULTI_AGENT=0` for one release
754
+ cycle, then removed.
755
+
756
+ ### 7.2 — Backwards compatibility
757
+
758
+ The PR #26 harness tests live entirely under the parent JSONL path. They
759
+ don't use sub-agents. With the feature flag OFF, behavior is byte-identical:
760
+
761
+ - `session-tail.ts`: when no `subagents/` subdir exists, the new code
762
+ paths are no-ops (existing tests in `progress-card-harness.test.ts`
763
+ unaffected).
764
+ - `progress-card-driver.ts`: when `subAgents` map is empty, render falls
765
+ back to the today's single-section layout (no `[Main]`/`[Sub-agents]`
766
+ headers).
767
+
768
+ The existing 3 harness tests should pass unmodified. Renderer golden tests
769
+ in `progress-card-golden.test.ts` will need golden updates ONLY for the
770
+ multi-agent scenarios (new tests, no existing golden affected).
771
+
772
+ ### 7.3 — Feature flag mechanism
773
+
774
+ Use the existing pattern (`process.env.<NAME> === '1'`), checked at driver
775
+ construction time, not per-event. Read once into a `multiAgent: boolean`
776
+ on the driver state. Old code path is fully reachable when the flag is
777
+ off — no shared mutable state changes shape.
778
+
779
+ ### 7.4 — Migration risks
780
+
781
+ - **Subagent JSONL flushing latency.** Claude Code 2.1.x flushes subagent
782
+ JSONLs every 100ms (same as parent). If a future release stops flushing
783
+ until subagent completion, our `[Sub-agents]` activity goes silent
784
+ during long sub-agent runs and the heartbeat is the only thing keeping
785
+ the card alive. Acceptable but worth monitoring.
786
+ - **`isSidechain: true` field stability.** We use this implicitly via
787
+ filename location, not the field itself, so a rename wouldn't affect us.
788
+ - **`agentId` filename format change.** If Claude Code ever moves to a
789
+ different naming scheme (`subagent-*.jsonl` instead of `agent-*.jsonl`),
790
+ we need a glob update in `session-tail.ts`. Single-line fix.
791
+
792
+ ---
793
+
794
+ ## Appendix A — render() pseudo-code
795
+
796
+ ```ts
797
+ function render(state: ProgressCardState, now: number): string {
798
+ if (state.turnStartedAt === 0) return '🤔 Waiting…'
799
+
800
+ const lines: string[] = []
801
+ const elapsed = formatDuration(now - state.turnStartedAt)
802
+ const headerIcon = state.stage === 'done' ? '✅' : '⚙️'
803
+ const headerLabel = state.stage === 'done' ? 'Done' : 'Working…'
804
+ lines.push(`${headerIcon} <b>${headerLabel}</b> · ⏱ ${elapsed}`)
805
+ if (state.userRequest) lines.push(`💬 ${escapeHtml(truncate(state.userRequest, 120))}`)
806
+ lines.push('─ ─ ─')
807
+
808
+ const hasSubAgents = state.subAgents.size > 0 || state.pendingAgentSpawns.size > 0
809
+
810
+ // [Main] section header only if multi-agent rendering is active
811
+ if (hasSubAgents) {
812
+ lines.push(`[Main · ${state.items.length} tools]`)
813
+ }
814
+
815
+ // Render main checklist (existing logic)
816
+ for (const item of applyVisibleCap(compactItems(state.items)).items) {
817
+ lines.push(renderMainItem(item, now, state.subAgents))
818
+ }
819
+
820
+ // Sub-agents section
821
+ if (state.subAgents.size > 0) {
822
+ lines.push('') // blank separator
823
+ const counts = countByState(state.subAgents)
824
+ lines.push(`[Sub-agents · ${formatCounts(counts)}]`)
825
+ for (const sa of sortSubAgents(state.subAgents)) {
826
+ lines.push(...renderSubAgent(sa, now))
827
+ }
828
+ }
829
+
830
+ if (state.stage !== 'done' && state.latestText) {
831
+ lines.push('')
832
+ lines.push(`💭 <i>${escapeHtml(truncate(state.latestText.trim(), 160))}</i>`)
833
+ }
834
+
835
+ return enforceCharBudget(lines.join('\n'), 3500)
836
+ }
837
+ ```
838
+
839
+ ## Appendix B — `enforceCharBudget` cascade
840
+
841
+ If body > limit:
842
+ 1. Drop file-path labels from `[Main]` items (keep tool name only).
843
+ 2. Reduce `[Main]` visible cap from 12 → 6.
844
+ 3. Collapse all done sub-agents into single `… (+N completed)` line.
845
+ 4. Last resort: truncate the whole card with `\n…\n[truncated for length]`.
846
+
847
+ Each step is deterministic and reversible if the next render has fewer items.