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.
- package/LICENSE +21 -0
- package/README.md +447 -0
- package/bin/autoaccept.exp +81 -0
- package/bin/boot-self-test.sh +149 -0
- package/bin/bridge-watchdog.sh +967 -0
- package/bin/handoff-briefing.sh +206 -0
- package/bin/run-hook.sh +228 -0
- package/bin/switchroom.ts +4 -0
- package/bin/timezone-hook.sh +67 -0
- package/bin/user-profile-refresh-hook.sh +38 -0
- package/bin/workspace-dynamic-hook.sh +142 -0
- package/bin/workspace-stable-hook.sh +57 -0
- package/dist/cli/autoaccept-poll.js +118 -0
- package/dist/cli/switchroom.js +48557 -0
- package/package.json +95 -0
- package/profiles/_base/settings.json.hbs +15 -0
- package/profiles/_base/start.sh.hbs +383 -0
- package/profiles/_shared/telegram-style.md.hbs +140 -0
- package/profiles/coding/CLAUDE.md.hbs +57 -0
- package/profiles/coding/skills/architecture/SKILL.md +70 -0
- package/profiles/coding/skills/code-review/SKILL.md +58 -0
- package/profiles/coding/workspace/SOUL.md.hbs +25 -0
- package/profiles/default/CLAUDE.md +238 -0
- package/profiles/default/CLAUDE.md.hbs +113 -0
- package/profiles/default/workspace/CLAUDE.md.hbs +126 -0
- package/profiles/default/workspace/HEARTBEAT.md.hbs +40 -0
- package/profiles/default/workspace/IDENTITY.md.hbs +32 -0
- package/profiles/default/workspace/MEMORY.md.hbs +29 -0
- package/profiles/default/workspace/SOUL.md.hbs +61 -0
- package/profiles/default/workspace/TOOLS.md.hbs +29 -0
- package/profiles/default/workspace/USER.md.hbs +52 -0
- package/profiles/default/workspace/memory/.gitkeep +0 -0
- package/profiles/executive-assistant/CLAUDE.md.hbs +51 -0
- package/profiles/executive-assistant/skills/daily-briefing/SKILL.md +55 -0
- package/profiles/executive-assistant/skills/meeting-prep/SKILL.md +58 -0
- package/profiles/executive-assistant/workspace/SOUL.md.hbs +25 -0
- package/profiles/health-coach/CLAUDE.md.hbs +45 -0
- package/profiles/health-coach/skills/check-in/SKILL.md +41 -0
- package/profiles/health-coach/skills/weekly-review/SKILL.md +53 -0
- package/profiles/health-coach/workspace/SOUL.md.hbs +25 -0
- package/skills/buildkite-agent-infrastructure/SKILL.md +302 -0
- package/skills/buildkite-agent-infrastructure/agents/openai.yaml +6 -0
- package/skills/buildkite-agent-infrastructure/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-agent-infrastructure/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-agent-infrastructure/references/audit-logging.md +87 -0
- package/skills/buildkite-agent-infrastructure/references/graphql-mutations.md +690 -0
- package/skills/buildkite-agent-infrastructure/references/instance-shapes.md +38 -0
- package/skills/buildkite-agent-infrastructure/references/pipeline-templates.md +73 -0
- package/skills/buildkite-agent-infrastructure/references/self-hosted-agents.md +137 -0
- package/skills/buildkite-agent-infrastructure/references/sso-saml.md +92 -0
- package/skills/buildkite-agent-runtime/SKILL.md +476 -0
- package/skills/buildkite-agent-runtime/agents/openai.yaml +6 -0
- package/skills/buildkite-agent-runtime/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-agent-runtime/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-agent-runtime/references/flag-reference.md +417 -0
- package/skills/buildkite-agent-runtime/references/patterns-and-recipes.md +555 -0
- package/skills/buildkite-api/SKILL.md +285 -0
- package/skills/buildkite-api/agents/openai.yaml +6 -0
- package/skills/buildkite-api/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-api/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-api/references/graphql-reference.md +195 -0
- package/skills/buildkite-api/references/patterns.md +44 -0
- package/skills/buildkite-api/references/webhooks.md +161 -0
- package/skills/buildkite-cli/SKILL.md +379 -0
- package/skills/buildkite-cli/agents/openai.yaml +6 -0
- package/skills/buildkite-cli/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-cli/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-cli/references/command-reference.md +181 -0
- package/skills/buildkite-migration/SKILL.md +182 -0
- package/skills/buildkite-pipelines/SKILL.md +464 -0
- package/skills/buildkite-pipelines/agents/openai.yaml +6 -0
- package/skills/buildkite-pipelines/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-pipelines/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-pipelines/examples/basic-pipeline.yml +24 -0
- package/skills/buildkite-pipelines/examples/optimized-pipeline.yml +100 -0
- package/skills/buildkite-pipelines/references/advanced-patterns.md +286 -0
- package/skills/buildkite-pipelines/references/retry-and-error-codes.md +131 -0
- package/skills/buildkite-pipelines/references/step-types-reference.md +225 -0
- package/skills/buildkite-secure-delivery/SKILL.md +168 -0
- package/skills/buildkite-secure-delivery/agents/openai.yaml +6 -0
- package/skills/buildkite-secure-delivery/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-secure-delivery/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-secure-delivery/references/oidc-cloud-providers.md +83 -0
- package/skills/buildkite-secure-delivery/references/package-publishing.md +100 -0
- package/skills/buildkite-test-engine/SKILL.md +239 -0
- package/skills/buildkite-test-engine/agents/openai.yaml +6 -0
- package/skills/buildkite-test-engine/assets/buildkite-icon-large.png +0 -0
- package/skills/buildkite-test-engine/assets/buildkite-icon-small.png +0 -0
- package/skills/buildkite-test-engine/examples/bktec-splitting.yml +16 -0
- package/skills/buildkite-test-engine/examples/collector-pipeline.yml +11 -0
- package/skills/buildkite-test-engine/references/collectors.md +198 -0
- package/skills/buildkite-test-engine/references/splitting-examples.md +93 -0
- package/skills/docx/LICENSE.txt +30 -0
- package/skills/docx/SKILL.md +590 -0
- package/skills/docx/VENDORED.md +32 -0
- package/skills/docx/scripts/__init__.py +1 -0
- package/skills/docx/scripts/accept_changes.py +135 -0
- package/skills/docx/scripts/comment.py +318 -0
- package/skills/docx/scripts/office/helpers/__init__.py +0 -0
- package/skills/docx/scripts/office/helpers/merge_runs.py +199 -0
- package/skills/docx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/skills/docx/scripts/office/pack.py +159 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/docx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/skills/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/docx/scripts/office/soffice.py +183 -0
- package/skills/docx/scripts/office/unpack.py +132 -0
- package/skills/docx/scripts/office/validate.py +111 -0
- package/skills/docx/scripts/office/validators/__init__.py +15 -0
- package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-313.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/base.cpython-313.pyc +0 -0
- package/skills/docx/scripts/office/validators/base.py +847 -0
- package/skills/docx/scripts/office/validators/docx.py +446 -0
- package/skills/docx/scripts/office/validators/pptx.py +275 -0
- package/skills/docx/scripts/office/validators/redlining.py +247 -0
- package/skills/docx/scripts/templates/comments.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/skills/docx/scripts/templates/people.xml +3 -0
- package/skills/file-bug/SKILL.md +129 -0
- package/skills/humanizer/LICENSE +21 -0
- package/skills/humanizer/SKILL.md +559 -0
- package/skills/humanizer/VENDORED.md +38 -0
- package/skills/humanizer-calibrate/SKILL.md +144 -0
- package/skills/mcp-builder/LICENSE.txt +202 -0
- package/skills/mcp-builder/SKILL.md +236 -0
- package/skills/mcp-builder/VENDORED.md +32 -0
- package/skills/mcp-builder/reference/evaluation.md +602 -0
- package/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
- package/skills/mcp-builder/reference/node_mcp_server.md +970 -0
- package/skills/mcp-builder/reference/python_mcp_server.md +719 -0
- package/skills/mcp-builder/scripts/connections.py +151 -0
- package/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/skills/pdf/LICENSE.txt +30 -0
- package/skills/pdf/SKILL.md +314 -0
- package/skills/pdf/VENDORED.md +32 -0
- package/skills/pdf/forms.md +294 -0
- package/skills/pdf/reference.md +612 -0
- package/skills/pdf/scripts/check_bounding_boxes.py +65 -0
- package/skills/pdf/scripts/check_fillable_fields.py +11 -0
- package/skills/pdf/scripts/convert_pdf_to_images.py +33 -0
- package/skills/pdf/scripts/create_validation_image.py +37 -0
- package/skills/pdf/scripts/extract_form_field_info.py +122 -0
- package/skills/pdf/scripts/extract_form_structure.py +115 -0
- package/skills/pdf/scripts/fill_fillable_fields.py +98 -0
- package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
- package/skills/pptx/LICENSE.txt +30 -0
- package/skills/pptx/SKILL.md +232 -0
- package/skills/pptx/VENDORED.md +32 -0
- package/skills/pptx/editing.md +205 -0
- package/skills/pptx/pptxgenjs.md +420 -0
- package/skills/pptx/scripts/__init__.py +0 -0
- package/skills/pptx/scripts/add_slide.py +195 -0
- package/skills/pptx/scripts/clean.py +286 -0
- package/skills/pptx/scripts/office/helpers/__init__.py +0 -0
- package/skills/pptx/scripts/office/helpers/merge_runs.py +199 -0
- package/skills/pptx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/skills/pptx/scripts/office/pack.py +159 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/pptx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/pptx/scripts/office/soffice.py +183 -0
- package/skills/pptx/scripts/office/unpack.py +132 -0
- package/skills/pptx/scripts/office/validate.py +111 -0
- package/skills/pptx/scripts/office/validators/__init__.py +15 -0
- package/skills/pptx/scripts/office/validators/base.py +847 -0
- package/skills/pptx/scripts/office/validators/docx.py +446 -0
- package/skills/pptx/scripts/office/validators/pptx.py +275 -0
- package/skills/pptx/scripts/office/validators/redlining.py +247 -0
- package/skills/pptx/scripts/thumbnail.py +289 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +485 -0
- package/skills/skill-creator/VENDORED.md +32 -0
- package/skills/skill-creator/agents/analyzer.md +274 -0
- package/skills/skill-creator/agents/comparator.md +202 -0
- package/skills/skill-creator/agents/grader.md +223 -0
- package/skills/skill-creator/assets/eval_review.html +146 -0
- package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/skill-creator/references/schemas.md +430 -0
- package/skills/skill-creator/scripts/__init__.py +0 -0
- package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/skill-creator/scripts/generate_report.py +326 -0
- package/skills/skill-creator/scripts/improve_description.py +247 -0
- package/skills/skill-creator/scripts/package_skill.py +136 -0
- package/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/skills/skill-creator/scripts/run_eval.py +310 -0
- package/skills/skill-creator/scripts/run_loop.py +328 -0
- package/skills/skill-creator/scripts/utils.py +47 -0
- package/skills/switchroom-architecture/SKILL.md +60 -0
- package/skills/switchroom-architecture/cascade.md +112 -0
- package/skills/switchroom-architecture/sub-agents.md +87 -0
- package/skills/switchroom-architecture/telegram.md +94 -0
- package/skills/switchroom-cli/SKILL.md +274 -0
- package/skills/switchroom-health/SKILL.md +101 -0
- package/skills/switchroom-install/SKILL.md +116 -0
- package/skills/switchroom-manage/SKILL.md +90 -0
- package/skills/switchroom-status/SKILL.md +69 -0
- package/skills/switchroom-status/scripts/status.sh +69 -0
- package/skills/telegram-test-harness/SKILL.md +191 -0
- package/skills/token-helpers/SKILL.md +73 -0
- package/skills/token-helpers/scripts/google-cal-token.sh +62 -0
- package/skills/token-helpers/scripts/ms-graph-token.sh +70 -0
- package/skills/webapp-testing/LICENSE.txt +202 -0
- package/skills/webapp-testing/SKILL.md +96 -0
- package/skills/webapp-testing/VENDORED.md +32 -0
- package/skills/webapp-testing/examples/console_logging.py +35 -0
- package/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/skills/webapp-testing/scripts/with_server.py +106 -0
- package/skills/xlsx/LICENSE.txt +30 -0
- package/skills/xlsx/SKILL.md +292 -0
- package/skills/xlsx/VENDORED.md +32 -0
- package/skills/xlsx/scripts/office/helpers/__init__.py +0 -0
- package/skills/xlsx/scripts/office/helpers/merge_runs.py +199 -0
- package/skills/xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
- package/skills/xlsx/scripts/office/pack.py +159 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
- package/skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/xlsx/scripts/office/soffice.py +183 -0
- package/skills/xlsx/scripts/office/unpack.py +132 -0
- package/skills/xlsx/scripts/office/validate.py +111 -0
- package/skills/xlsx/scripts/office/validators/__init__.py +15 -0
- package/skills/xlsx/scripts/office/validators/base.py +847 -0
- package/skills/xlsx/scripts/office/validators/docx.py +446 -0
- package/skills/xlsx/scripts/office/validators/pptx.py +275 -0
- package/skills/xlsx/scripts/office/validators/redlining.py +247 -0
- package/skills/xlsx/scripts/recalc.py +184 -0
- package/telegram-plugin/.claude-plugin/plugin.json +20 -0
- package/telegram-plugin/.mcp.json +14 -0
- package/telegram-plugin/LICENSE +21 -0
- package/telegram-plugin/README.md +352 -0
- package/telegram-plugin/active-pins-sweep.ts +204 -0
- package/telegram-plugin/active-pins.ts +146 -0
- package/telegram-plugin/active-reactions-sweep.ts +79 -0
- package/telegram-plugin/active-reactions.ts +134 -0
- package/telegram-plugin/admin-commands/dispatch.test.ts +149 -0
- package/telegram-plugin/admin-commands/index.ts +106 -0
- package/telegram-plugin/answer-stream.ts +565 -0
- package/telegram-plugin/ask-user.ts +179 -0
- package/telegram-plugin/attachment-path.ts +80 -0
- package/telegram-plugin/auth-code-redact.ts +83 -0
- package/telegram-plugin/auth-dashboard.ts +1104 -0
- package/telegram-plugin/auth-slot-parser.ts +497 -0
- package/telegram-plugin/auto-fallback-dispatcher.ts +68 -0
- package/telegram-plugin/auto-fallback.ts +348 -0
- package/telegram-plugin/bridge/bridge.ts +687 -0
- package/telegram-plugin/bridge/ipc-client.ts +326 -0
- package/telegram-plugin/bun.lock +218 -0
- package/telegram-plugin/card-format.ts +62 -0
- package/telegram-plugin/channel-envelope-safety.test.ts +56 -0
- package/telegram-plugin/channel-envelope-safety.ts +56 -0
- package/telegram-plugin/chat-lock.ts +65 -0
- package/telegram-plugin/context-exhaustion.ts +38 -0
- package/telegram-plugin/credits-watch.ts +220 -0
- package/telegram-plugin/dist/bridge/bridge.js +24758 -0
- package/telegram-plugin/dist/foreman/foreman.js +30723 -0
- package/telegram-plugin/dist/gateway/gateway.js +46497 -0
- package/telegram-plugin/dist/server.js +24551 -0
- package/telegram-plugin/dm-command-gate.ts +56 -0
- package/telegram-plugin/docs/gateway-server-split.md +133 -0
- package/telegram-plugin/docs/multi-agent-card-design.md +847 -0
- package/telegram-plugin/docs/pinned-progress-card-reliability.md +144 -0
- package/telegram-plugin/docs/stream-json-daemon-mode.md +477 -0
- package/telegram-plugin/docs/waiting-ux-spec.md +233 -0
- package/telegram-plugin/draft-stream.ts +442 -0
- package/telegram-plugin/draft-transport.ts +72 -0
- package/telegram-plugin/first-paint.ts +246 -0
- package/telegram-plugin/fleet-state.ts +246 -0
- package/telegram-plugin/foreman/foreman-create-flow.ts +202 -0
- package/telegram-plugin/foreman/foreman-handlers.ts +493 -0
- package/telegram-plugin/foreman/foreman.ts +1130 -0
- package/telegram-plugin/foreman/setup-flow.ts +345 -0
- package/telegram-plugin/foreman/setup-state.ts +239 -0
- package/telegram-plugin/foreman/state.ts +203 -0
- package/telegram-plugin/format.ts +685 -0
- package/telegram-plugin/gateway/access-validator.test.ts +95 -0
- package/telegram-plugin/gateway/access-validator.ts +37 -0
- package/telegram-plugin/gateway/boot-card.ts +582 -0
- package/telegram-plugin/gateway/boot-probes.ts +863 -0
- package/telegram-plugin/gateway/boot-reason.ts +51 -0
- package/telegram-plugin/gateway/boot-sweep-filter.test.ts +54 -0
- package/telegram-plugin/gateway/boot-sweep-filter.ts +32 -0
- package/telegram-plugin/gateway/clean-shutdown-marker.ts +183 -0
- package/telegram-plugin/gateway/disconnect-flush.ts +109 -0
- package/telegram-plugin/gateway/gateway.ts +10202 -0
- package/telegram-plugin/gateway/inbound-coalesce.ts +147 -0
- package/telegram-plugin/gateway/inject-handler.test.ts +221 -0
- package/telegram-plugin/gateway/inject-handler.ts +190 -0
- package/telegram-plugin/gateway/ipc-protocol.ts +151 -0
- package/telegram-plugin/gateway/ipc-server.ts +494 -0
- package/telegram-plugin/gateway/pid-file.ts +103 -0
- package/telegram-plugin/gateway/poll-health.ts +156 -0
- package/telegram-plugin/gateway/preamble-suppressor.ts +154 -0
- package/telegram-plugin/gateway/quota-cache.ts +125 -0
- package/telegram-plugin/gateway/resolve-calling-subagent.ts +78 -0
- package/telegram-plugin/gateway/restart-watchdog.ts +200 -0
- package/telegram-plugin/gateway/session-marker.ts +83 -0
- package/telegram-plugin/gateway/shutdown-drain.ts +162 -0
- package/telegram-plugin/gateway/startup-mutex.ts +285 -0
- package/telegram-plugin/gateway/startup-network-retry.ts +142 -0
- package/telegram-plugin/gateway/turn-active-marker.ts +176 -0
- package/telegram-plugin/gateway/unhandled-rejection-policy.ts +78 -0
- package/telegram-plugin/handoff-continuity.ts +200 -0
- package/telegram-plugin/history.ts +468 -0
- package/telegram-plugin/hooks/hooks.json +58 -0
- package/telegram-plugin/hooks/secret-guard-pretool.mjs +208 -0
- package/telegram-plugin/hooks/secret-scrub-stop.mjs +98 -0
- package/telegram-plugin/hooks/silent-end-interrupt-stop.mjs +111 -0
- package/telegram-plugin/hooks/subagent-tracker-posttool.mjs +296 -0
- package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +261 -0
- package/telegram-plugin/html-sanitize.ts +244 -0
- package/telegram-plugin/idle-footer.ts +65 -0
- package/telegram-plugin/inline-keyboard-callbacks.ts +166 -0
- package/telegram-plugin/interrupt-marker.ts +66 -0
- package/telegram-plugin/issues-card.ts +371 -0
- package/telegram-plugin/issues-watcher.ts +125 -0
- package/telegram-plugin/model-unavailable.ts +325 -0
- package/telegram-plugin/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/telegram-plugin/operator-events-history.ts +94 -0
- package/telegram-plugin/operator-events.fixtures.json +161 -0
- package/telegram-plugin/operator-events.ts +421 -0
- package/telegram-plugin/package.json +55 -0
- package/telegram-plugin/permission-rule.ts +133 -0
- package/telegram-plugin/permission-title.ts +117 -0
- package/telegram-plugin/pin-event-log.ts +76 -0
- package/telegram-plugin/plugin-logger.ts +136 -0
- package/telegram-plugin/progress-card-driver.ts +2697 -0
- package/telegram-plugin/progress-card-pin-manager.ts +589 -0
- package/telegram-plugin/progress-card-pin-watchdog.ts +98 -0
- package/telegram-plugin/progress-card.ts +1409 -0
- package/telegram-plugin/pty-partial-handler.ts +247 -0
- package/telegram-plugin/pty-tail.ts +730 -0
- package/telegram-plugin/quota-check.ts +474 -0
- package/telegram-plugin/recent-outbound-dedup.ts +169 -0
- package/telegram-plugin/registry/api-registry.test.ts +201 -0
- package/telegram-plugin/registry/subagents-bugs.test.ts +454 -0
- package/telegram-plugin/registry/subagents-schema.ts +509 -0
- package/telegram-plugin/registry/subagents.test.ts +476 -0
- package/telegram-plugin/registry/turns-schema.test.ts +101 -0
- package/telegram-plugin/registry/turns-schema.ts +417 -0
- package/telegram-plugin/retry-api-call.ts +172 -0
- package/telegram-plugin/scripts/build.mjs +78 -0
- package/telegram-plugin/secret-detect/audit.ts +66 -0
- package/telegram-plugin/secret-detect/chunker.ts +37 -0
- package/telegram-plugin/secret-detect/entropy.ts +20 -0
- package/telegram-plugin/secret-detect/gitleaks-loader.ts +74 -0
- package/telegram-plugin/secret-detect/gitleaks.toml +27 -0
- package/telegram-plugin/secret-detect/index.ts +218 -0
- package/telegram-plugin/secret-detect/kv-scanner.ts +60 -0
- package/telegram-plugin/secret-detect/mask.ts +13 -0
- package/telegram-plugin/secret-detect/patterns.ts +115 -0
- package/telegram-plugin/secret-detect/pipeline.ts +144 -0
- package/telegram-plugin/secret-detect/rewrite.ts +26 -0
- package/telegram-plugin/secret-detect/secretlint-source.ts +95 -0
- package/telegram-plugin/secret-detect/slug.ts +44 -0
- package/telegram-plugin/secret-detect/staging.ts +85 -0
- package/telegram-plugin/secret-detect/suppressor.ts +34 -0
- package/telegram-plugin/secret-detect/url-redact.ts +60 -0
- package/telegram-plugin/secret-detect/vault-write.ts +56 -0
- package/telegram-plugin/server.js +41795 -0
- package/telegram-plugin/server.ts +171 -0
- package/telegram-plugin/session-tail.ts +884 -0
- package/telegram-plugin/shared/bot-runtime.ts +324 -0
- package/telegram-plugin/silent-reply.ts +58 -0
- package/telegram-plugin/slot-banner-driver.ts +147 -0
- package/telegram-plugin/slot-banner.ts +86 -0
- package/telegram-plugin/start.js +26 -0
- package/telegram-plugin/startup-reset.ts +45 -0
- package/telegram-plugin/status-reactions.ts +332 -0
- package/telegram-plugin/steering.ts +155 -0
- package/telegram-plugin/sticker-aliases.ts +249 -0
- package/telegram-plugin/stream-controller.ts +311 -0
- package/telegram-plugin/stream-reply-handler.ts +664 -0
- package/telegram-plugin/streaming-metrics.ts +134 -0
- package/telegram-plugin/streaming-report.ts +204 -0
- package/telegram-plugin/subagent-watcher.ts +880 -0
- package/telegram-plugin/telegram-button-constraints.ts +191 -0
- package/telegram-plugin/telegraph.ts +381 -0
- package/telegram-plugin/tests/HARNESS.md +340 -0
- package/telegram-plugin/tests/_progress-card-harness.ts +105 -0
- package/telegram-plugin/tests/active-pins-boot-reaper.test.ts +211 -0
- package/telegram-plugin/tests/active-pins-sweep.test.ts +309 -0
- package/telegram-plugin/tests/active-pins.test.ts +187 -0
- package/telegram-plugin/tests/active-reactions-sweep.test.ts +116 -0
- package/telegram-plugin/tests/active-reactions.test.ts +198 -0
- package/telegram-plugin/tests/answer-stream-dedup.test.ts +352 -0
- package/telegram-plugin/tests/answer-stream-silent-markers.test.ts +236 -0
- package/telegram-plugin/tests/answer-stream.test.ts +878 -0
- package/telegram-plugin/tests/ask-user.test.ts +203 -0
- package/telegram-plugin/tests/attachment-path.test.ts +199 -0
- package/telegram-plugin/tests/auth-account-identity-surface.test.ts +118 -0
- package/telegram-plugin/tests/auth-code-auto-capture.test.ts +144 -0
- package/telegram-plugin/tests/auth-code-redact.test.ts +248 -0
- package/telegram-plugin/tests/auth-dashboard-edge-cases.test.ts +260 -0
- package/telegram-plugin/tests/auth-dashboard-restart-flow.test.ts +140 -0
- package/telegram-plugin/tests/auth-dashboard-v3b.test.ts +559 -0
- package/telegram-plugin/tests/auth-dashboard.test.ts +1045 -0
- package/telegram-plugin/tests/auth-login-url-button.test.ts +122 -0
- package/telegram-plugin/tests/auth-slot-commands.test.ts +640 -0
- package/telegram-plugin/tests/auto-fallback-dispatcher.e2e.test.ts +183 -0
- package/telegram-plugin/tests/auto-fallback.test.ts +381 -0
- package/telegram-plugin/tests/boot-card-account-quota.test.ts +137 -0
- package/telegram-plugin/tests/boot-card-dedupe.test.ts +154 -0
- package/telegram-plugin/tests/boot-card-probe-target.test.ts +194 -0
- package/telegram-plugin/tests/boot-card-reason.test.ts +103 -0
- package/telegram-plugin/tests/boot-card-render.test.ts +219 -0
- package/telegram-plugin/tests/boot-probes.test.ts +451 -0
- package/telegram-plugin/tests/bot-api.harness.ts +116 -0
- package/telegram-plugin/tests/bot-runtime.test.ts +190 -0
- package/telegram-plugin/tests/bridge-anonymous-refuse.test.ts +60 -0
- package/telegram-plugin/tests/context-exhaustion.test.ts +114 -0
- package/telegram-plugin/tests/credits-watch.test.ts +221 -0
- package/telegram-plugin/tests/dm-command-gate.test.ts +176 -0
- package/telegram-plugin/tests/draft-stream.test.ts +752 -0
- package/telegram-plugin/tests/draft-transport.test.ts +141 -0
- package/telegram-plugin/tests/e2e.test.ts +436 -0
- package/telegram-plugin/tests/fake-bot-api.test.ts +213 -0
- package/telegram-plugin/tests/fake-bot-api.ts +617 -0
- package/telegram-plugin/tests/false-restart-banner.test.ts +253 -0
- package/telegram-plugin/tests/first-paint.test.ts +257 -0
- package/telegram-plugin/tests/fixtures/pty-tail-tmux-fragment.bin +6 -0
- package/telegram-plugin/tests/fixtures/service-log-current-claude-code.bin +3624 -0
- package/telegram-plugin/tests/fleet-state-watcher.test.ts +101 -0
- package/telegram-plugin/tests/fleet-state.test.ts +185 -0
- package/telegram-plugin/tests/foreman-create-flow.test.ts +359 -0
- package/telegram-plugin/tests/foreman-handlers.test.ts +347 -0
- package/telegram-plugin/tests/foreman-state.test.ts +164 -0
- package/telegram-plugin/tests/foreman-write-ops.test.ts +214 -0
- package/telegram-plugin/tests/gateway-409-retry-banner.test.ts +173 -0
- package/telegram-plugin/tests/gateway-boot-marker-clear.test.ts +72 -0
- package/telegram-plugin/tests/gateway-bridge.test.ts +811 -0
- package/telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts +414 -0
- package/telegram-plugin/tests/gateway-disconnect-flush.test.ts +144 -0
- package/telegram-plugin/tests/gateway-message-validator.test.ts +133 -0
- package/telegram-plugin/tests/gateway-no-reply-single-emit.test.ts +103 -0
- package/telegram-plugin/tests/gateway-secret-detect.test.ts +127 -0
- package/telegram-plugin/tests/gateway-startup-mutex.test.ts +284 -0
- package/telegram-plugin/tests/gateway-startup-network-retry.test.ts +185 -0
- package/telegram-plugin/tests/gateway-startup-reset.test.ts +72 -0
- package/telegram-plugin/tests/gateway-update-placeholder-dispatch.test.ts +125 -0
- package/telegram-plugin/tests/handoff-continuity.test.ts +249 -0
- package/telegram-plugin/tests/harness-ordering-invariants.test.ts +243 -0
- package/telegram-plugin/tests/harness-parse-mode-validation.test.ts +114 -0
- package/telegram-plugin/tests/history.test.ts +364 -0
- package/telegram-plugin/tests/html-balanced.ts +63 -0
- package/telegram-plugin/tests/html-sanitize.test.ts +146 -0
- package/telegram-plugin/tests/idle-footer-wiring.test.ts +88 -0
- package/telegram-plugin/tests/idle-footer.test.ts +66 -0
- package/telegram-plugin/tests/inbound-coalesce.test.ts +127 -0
- package/telegram-plugin/tests/inline-keyboard-callbacks.test.ts +150 -0
- package/telegram-plugin/tests/interrupt-marker.test.ts +126 -0
- package/telegram-plugin/tests/ipc-protocol.test.ts +218 -0
- package/telegram-plugin/tests/ipc-server-anonymous-refuse.test.ts +82 -0
- package/telegram-plugin/tests/ipc-server-client.test.ts +323 -0
- package/telegram-plugin/tests/ipc-server-race.test.ts +183 -0
- package/telegram-plugin/tests/ipc-server-validate-operator.test.ts +91 -0
- package/telegram-plugin/tests/ipc-server-validate-pty-partial.test.ts +64 -0
- package/telegram-plugin/tests/ipc-server-validate-update-placeholder.test.ts +77 -0
- package/telegram-plugin/tests/ipc-validator.test.ts +274 -0
- package/telegram-plugin/tests/issues-card.test.ts +495 -0
- package/telegram-plugin/tests/issues-watcher.test.ts +165 -0
- package/telegram-plugin/tests/model-unavailable.test.ts +303 -0
- package/telegram-plugin/tests/multi-turn-continuity.test.ts +159 -0
- package/telegram-plugin/tests/operator-events-history.test.ts +125 -0
- package/telegram-plugin/tests/operator-events-session-tail.test.ts +192 -0
- package/telegram-plugin/tests/operator-events.test.ts +331 -0
- package/telegram-plugin/tests/outbound-ordering.test.ts +293 -0
- package/telegram-plugin/tests/parse-mode-rotation.test.ts +164 -0
- package/telegram-plugin/tests/permission-rule.test.ts +121 -0
- package/telegram-plugin/tests/permission-title.test.ts +106 -0
- package/telegram-plugin/tests/pin-event-log.test.ts +124 -0
- package/telegram-plugin/tests/plugin-logger.test.ts +97 -0
- package/telegram-plugin/tests/poll-health.test.ts +86 -0
- package/telegram-plugin/tests/preamble-suppressor.test.ts +285 -0
- package/telegram-plugin/tests/progress-card-api-failure-during-deferred.test.ts +73 -0
- package/telegram-plugin/tests/progress-card-close-paths-converge.test.ts +272 -0
- package/telegram-plugin/tests/progress-card-cross-turn.test.ts +258 -0
- package/telegram-plugin/tests/progress-card-dispose-preservepending.test.ts +81 -0
- package/telegram-plugin/tests/progress-card-draft-flag.test.ts +80 -0
- package/telegram-plugin/tests/progress-card-driver-eviction.test.ts +215 -0
- package/telegram-plugin/tests/progress-card-driver-fleet-shadow.test.ts +123 -0
- package/telegram-plugin/tests/progress-card-driver-force-complete-parent-done.test.ts +76 -0
- package/telegram-plugin/tests/progress-card-edit-timestamps-budget.test.ts +62 -0
- package/telegram-plugin/tests/progress-card-memory-bounds.test.ts +84 -0
- package/telegram-plugin/tests/progress-card-pin-failure-paths.test.ts +139 -0
- package/telegram-plugin/tests/progress-card-pin-manager.test.ts +773 -0
- package/telegram-plugin/tests/progress-card-pin-race-fast-turn.test.ts +66 -0
- package/telegram-plugin/tests/progress-card-pin-sidecar-partial-write.test.ts +64 -0
- package/telegram-plugin/tests/progress-card-pin-watchdog.test.ts +190 -0
- package/telegram-plugin/tests/progress-card-sigterm-pin-flush.test.ts +146 -0
- package/telegram-plugin/tests/progress-update.test.ts +236 -0
- package/telegram-plugin/tests/protocol-fixtures.test.ts +59 -0
- package/telegram-plugin/tests/protocol-fixtures.ts +198 -0
- package/telegram-plugin/tests/pty-partial-handler.test.ts +326 -0
- package/telegram-plugin/tests/pty-tail-real-fixture.test.ts +114 -0
- package/telegram-plugin/tests/pty-tail-tmux-fragment.test.ts +71 -0
- package/telegram-plugin/tests/pty-tail.test.ts +525 -0
- package/telegram-plugin/tests/quota-cache.test.ts +187 -0
- package/telegram-plugin/tests/quota-check.test.ts +622 -0
- package/telegram-plugin/tests/races.test.ts +842 -0
- package/telegram-plugin/tests/real-gateway-f1-ladder-integrity.test.ts +123 -0
- package/telegram-plugin/tests/real-gateway-f2-instant-draft.test.ts +82 -0
- package/telegram-plugin/tests/real-gateway-f3-late-card.test.ts +114 -0
- package/telegram-plugin/tests/real-gateway-harness.ts +699 -0
- package/telegram-plugin/tests/real-gateway-i6-turn-flush-replay-dedup.test.ts +313 -0
- package/telegram-plugin/tests/real-gateway-ipc-lifecycle.test.ts +299 -0
- package/telegram-plugin/tests/real-gateway-spec.test.ts +487 -0
- package/telegram-plugin/tests/real-gateway.smoke.test.ts +101 -0
- package/telegram-plugin/tests/recent-outbound-dedup.test.ts +192 -0
- package/telegram-plugin/tests/registry-turns.test.ts +432 -0
- package/telegram-plugin/tests/reply-terminal-reaction.test.ts +149 -0
- package/telegram-plugin/tests/resolve-calling-subagent.test.ts +269 -0
- package/telegram-plugin/tests/restart-watchdog.test.ts +224 -0
- package/telegram-plugin/tests/retry-api-call.test.ts +287 -0
- package/telegram-plugin/tests/secret-detect-audit.test.ts +58 -0
- package/telegram-plugin/tests/secret-detect-fail-closed.test.ts +83 -0
- package/telegram-plugin/tests/secret-detect-gitleaks.test.ts +32 -0
- package/telegram-plugin/tests/secret-detect-oauth-code.test.ts +308 -0
- package/telegram-plugin/tests/secret-detect-pipeline.test.ts +123 -0
- package/telegram-plugin/tests/secret-detect-secretlint.test.ts +101 -0
- package/telegram-plugin/tests/secret-detect-staging.test.ts +45 -0
- package/telegram-plugin/tests/secret-detect-suppressor-no-silent-allow.test.ts +67 -0
- package/telegram-plugin/tests/secret-detect.test.ts +223 -0
- package/telegram-plugin/tests/secret-guard-pretool.test.ts +194 -0
- package/telegram-plugin/tests/send-typing-action-validation.test.ts +61 -0
- package/telegram-plugin/tests/session-tail-capped.test.ts +285 -0
- package/telegram-plugin/tests/session-tail.test.ts +524 -0
- package/telegram-plugin/tests/setup-flow.test.ts +510 -0
- package/telegram-plugin/tests/setup-state.test.ts +146 -0
- package/telegram-plugin/tests/silent-reply-guard.test.ts +122 -0
- package/telegram-plugin/tests/slot-banner-driver.e2e.test.ts +350 -0
- package/telegram-plugin/tests/slot-banner.test.ts +74 -0
- package/telegram-plugin/tests/snapshot-serializer.ts +79 -0
- package/telegram-plugin/tests/spawn-detached-cgroup-escape.test.ts +51 -0
- package/telegram-plugin/tests/status-accent.test.ts +186 -0
- package/telegram-plugin/tests/status-reactions-allowed-filter.test.ts +132 -0
- package/telegram-plugin/tests/status-reactions.test.ts +314 -0
- package/telegram-plugin/tests/steering.test.ts +282 -0
- package/telegram-plugin/tests/sticker-aliases.test.ts +232 -0
- package/telegram-plugin/tests/stream-controller-html-fallback.test.ts +127 -0
- package/telegram-plugin/tests/stream-controller.test.ts +262 -0
- package/telegram-plugin/tests/stream-reply-error-paths.test.ts +208 -0
- package/telegram-plugin/tests/stream-reply-handler.test.ts +1292 -0
- package/telegram-plugin/tests/streaming-e2e.test.ts +389 -0
- package/telegram-plugin/tests/streaming-metrics.test.ts +201 -0
- package/telegram-plugin/tests/streaming-orchestration.test.ts +756 -0
- package/telegram-plugin/tests/subagent-registry-bugs.test.ts +725 -0
- package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +213 -0
- package/telegram-plugin/tests/subagent-watcher-parent-marker.test.ts +274 -0
- package/telegram-plugin/tests/subagent-watcher-stall-notification.test.ts +243 -0
- package/telegram-plugin/tests/subagent-watcher.test.ts +877 -0
- package/telegram-plugin/tests/subagents-schema-init-order.test.ts +109 -0
- package/telegram-plugin/tests/sync-chat-running-subagents.test.ts +116 -0
- package/telegram-plugin/tests/telegram-button-constraints.test.ts +194 -0
- package/telegram-plugin/tests/telegram-format.test.ts +1093 -0
- package/telegram-plugin/tests/telegraph.test.ts +246 -0
- package/telegram-plugin/tests/tool-labels.test.ts +383 -0
- package/telegram-plugin/tests/turn-active-marker.test.ts +195 -0
- package/telegram-plugin/tests/turn-end-regressions.test.ts +489 -0
- package/telegram-plugin/tests/turn-flush-card-takeover.test.ts +218 -0
- package/telegram-plugin/tests/turn-flush-dedup-controller.test.ts +144 -0
- package/telegram-plugin/tests/turn-flush-prose-recovery.test.ts +78 -0
- package/telegram-plugin/tests/turn-flush-safety.test.ts +189 -0
- package/telegram-plugin/tests/turn-signal-tracker.test.ts +107 -0
- package/telegram-plugin/tests/turns-writer.test.ts +323 -0
- package/telegram-plugin/tests/two-zone-bg-carry-full-lifecycle.test.ts +131 -0
- package/telegram-plugin/tests/two-zone-bg-detection.test.ts +120 -0
- package/telegram-plugin/tests/two-zone-bg-done-when-all-terminal.test.ts +114 -0
- package/telegram-plugin/tests/two-zone-bg-early-turn-end.test.ts +87 -0
- package/telegram-plugin/tests/two-zone-bg-survives-next-turn.test.ts +211 -0
- package/telegram-plugin/tests/two-zone-card-cap.test.ts +62 -0
- package/telegram-plugin/tests/two-zone-card-fleet-row.test.ts +101 -0
- package/telegram-plugin/tests/two-zone-card-header-phases.test.ts +68 -0
- package/telegram-plugin/tests/two-zone-card-html-balance.test.ts +110 -0
- package/telegram-plugin/tests/two-zone-card-lifecycle.test.ts +128 -0
- package/telegram-plugin/tests/two-zone-card-sanitise.test.ts +58 -0
- package/telegram-plugin/tests/two-zone-card-snapshot.test.ts +133 -0
- package/telegram-plugin/tests/two-zone-concurrent-turns-isolation.test.ts +155 -0
- package/telegram-plugin/tests/two-zone-phasefor-precedence.test.ts +117 -0
- package/telegram-plugin/tests/two-zone-snapshot-extras.test.ts +143 -0
- package/telegram-plugin/tests/two-zone-stuck-edit-throttle.test.ts +149 -0
- package/telegram-plugin/tests/two-zone-stuck-header-escalation.test.ts +101 -0
- package/telegram-plugin/tests/two-zone-stuck-per-member.test.ts +114 -0
- package/telegram-plugin/tests/two-zone-stuck-recovery.test.ts +105 -0
- package/telegram-plugin/tests/typing-wrap.test.ts +141 -0
- package/telegram-plugin/tests/unhandled-rejection-policy.test.ts +147 -0
- package/telegram-plugin/tests/update-factory-edited-and-reactions.test.ts +108 -0
- package/telegram-plugin/tests/update-factory.ts +305 -0
- package/telegram-plugin/tests/vault-grant-wizard.test.ts +84 -0
- package/telegram-plugin/tests/vault-grants-revoke.test.ts +265 -0
- package/telegram-plugin/tests/vault-subcommands.test.ts +234 -0
- package/telegram-plugin/tests/voice-transcribe.test.ts +196 -0
- package/telegram-plugin/tests/waiting-ux-harness.ts +381 -0
- package/telegram-plugin/tests/waiting-ux.e2e.test.ts +233 -0
- package/telegram-plugin/tests/welcome-text.test.ts +407 -0
- package/telegram-plugin/tool-error-filter.ts +89 -0
- package/telegram-plugin/tool-labels.ts +330 -0
- package/telegram-plugin/tool-names.ts +53 -0
- package/telegram-plugin/turn-flush-prose-recovery.ts +40 -0
- package/telegram-plugin/turn-flush-safety.ts +109 -0
- package/telegram-plugin/turn-signal-tracker.ts +79 -0
- package/telegram-plugin/two-zone-card.ts +249 -0
- package/telegram-plugin/typing-wrap.ts +92 -0
- package/telegram-plugin/voice-transcribe.ts +166 -0
- 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.
|