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,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human-readable labels for tool_use events on the progress card.
|
|
3
|
+
*
|
|
4
|
+
* Each function takes the tool's `input` object (as Claude Code records it
|
|
5
|
+
* in the session JSONL) and returns a short suffix to append to the tool
|
|
6
|
+
* name, e.g. `toolLabel('Read', { file_path: '/abs/foo.ts' })` → `'foo.ts'`.
|
|
7
|
+
*
|
|
8
|
+
* Goals:
|
|
9
|
+
* - Short enough to fit on one Telegram line without wrapping on mobile
|
|
10
|
+
* - Recognisable — paths shown as basename only; commands truncated at
|
|
11
|
+
* ~40 chars / first newline; queries quoted; hostnames for URLs
|
|
12
|
+
* - Safe: all outputs pass through the renderer's HTML escape, and
|
|
13
|
+
* inputs that look malformed fall back to empty string
|
|
14
|
+
*
|
|
15
|
+
* Keep this file tiny and dependency-free — it's in the hot path of
|
|
16
|
+
* every render.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const MAX_LABEL_CHARS = 60
|
|
20
|
+
const MAX_BASH_CHARS = 40
|
|
21
|
+
/**
|
|
22
|
+
* Cap for human-readable `description` fields (Bash, fallback). Set
|
|
23
|
+
* larger than MAX_BASH_CHARS because descriptions are agent-authored
|
|
24
|
+
* English prose intended for humans — letting them wrap a couple of
|
|
25
|
+
* mobile lines is fine; aggressive truncation hides intent.
|
|
26
|
+
*/
|
|
27
|
+
const MAX_DESCRIPTION_CHARS = 160
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Basename of a path — just the trailing segment. `/a/b/c.ts` → `c.ts`.
|
|
31
|
+
* We used to shorten to "project/last-two-segments" but user feedback
|
|
32
|
+
* asked for a cleaner look in the checklist; the path's directory rarely
|
|
33
|
+
* adds useful information when the user is watching tool calls scroll by.
|
|
34
|
+
*/
|
|
35
|
+
function basename(p: string): string {
|
|
36
|
+
if (!p) return ''
|
|
37
|
+
const parts = p.split('/').filter(Boolean)
|
|
38
|
+
return parts.length > 0 ? parts[parts.length - 1] : p
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Shorten a Grep `path` argument. Prefer "<parent>/<dir>/" form for
|
|
43
|
+
* directories so the hint is recognisable (e.g. "src/" rather than just
|
|
44
|
+
* "src" is ambiguous vs. a file). Returns the basename for files.
|
|
45
|
+
*/
|
|
46
|
+
function shortenGrepPath(p: string): string {
|
|
47
|
+
if (!p) return 'repo'
|
|
48
|
+
const hadTrailingSlash = /\/+$/.test(p)
|
|
49
|
+
const trimmed = p.replace(/\/+$/, '')
|
|
50
|
+
const parts = trimmed.split('/').filter(Boolean)
|
|
51
|
+
if (parts.length === 0) return 'repo'
|
|
52
|
+
const last = parts[parts.length - 1]
|
|
53
|
+
if (hadTrailingSlash) return `${last}/`
|
|
54
|
+
// Dotfiles like `.env`, `.gitignore`, `.npmrc` — a leading dot with no
|
|
55
|
+
// further dot — are files, not directories. The old heuristic ("no dot
|
|
56
|
+
// → dir") mislabeled them as directories.
|
|
57
|
+
if (last.startsWith('.') && !last.slice(1).includes('.')) return last
|
|
58
|
+
// Otherwise: no extension → treat as a directory hint.
|
|
59
|
+
if (!last.includes('.')) return `${last}/`
|
|
60
|
+
return last
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Extract a hostname from a URL. Falls back to the original string on
|
|
65
|
+
* malformed input.
|
|
66
|
+
*/
|
|
67
|
+
function hostFromUrl(u: string): string {
|
|
68
|
+
if (!u) return ''
|
|
69
|
+
try {
|
|
70
|
+
return new URL(u).host
|
|
71
|
+
} catch {
|
|
72
|
+
// Not a valid URL — just return the raw input, truncated.
|
|
73
|
+
return truncate(u)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function truncate(s: string, n = MAX_LABEL_CHARS): string {
|
|
78
|
+
if (s.length <= n) return s
|
|
79
|
+
return s.slice(0, n - 1) + '…'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Strip HTML tags from a preview string. MCP tools like `stream_reply`
|
|
84
|
+
* accept Telegram-HTML text as input; when we use that text as a label
|
|
85
|
+
* preview, the raw `<b>`/`<i>`/etc. markers would pass through
|
|
86
|
+
* `escapeHtml` in the renderer and show up as visible `<b>` on screen.
|
|
87
|
+
* Dropping tags here keeps the preview human-readable.
|
|
88
|
+
*
|
|
89
|
+
* Requires an ASCII letter (or `/`) immediately after `<` so comparison
|
|
90
|
+
* operators in plain-text queries (`"find x < 5 and y > 3"`) survive
|
|
91
|
+
* unmolested. A naive `/<[^>]+>/g` would otherwise eat everything
|
|
92
|
+
* between the two brackets.
|
|
93
|
+
*/
|
|
94
|
+
function stripHtml(s: string): string {
|
|
95
|
+
return s.replace(/<\/?[a-zA-Z][^>]*>/g, '')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function firstLine(s: string): string {
|
|
99
|
+
const idx = s.indexOf('\n')
|
|
100
|
+
return idx === -1 ? s : s.slice(0, idx)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Return true when the label produced by `toolLabel(tool, input)` came
|
|
105
|
+
* from a human-authored `description` field rather than a raw fallback
|
|
106
|
+
* (filename, command string, hostname, etc.). The progress card uses this
|
|
107
|
+
* flag to suppress the tool-name prefix — "Check commit state" reads
|
|
108
|
+
* better than "Bash Check commit state".
|
|
109
|
+
*
|
|
110
|
+
* Rules:
|
|
111
|
+
* - Bash / BashOutput → true when `input.description` is a non-empty string
|
|
112
|
+
* - Task / Agent → true when `input.description` is a non-empty string
|
|
113
|
+
* - All other tools → false (keep the "ToolName label" concat)
|
|
114
|
+
*
|
|
115
|
+
* WebFetch and WebSearch are intentionally left as false because the
|
|
116
|
+
* tool name provides important context ("WebFetch example.com" makes more
|
|
117
|
+
* sense than just "example.com").
|
|
118
|
+
*/
|
|
119
|
+
export function isHumanDescription(
|
|
120
|
+
tool: string,
|
|
121
|
+
input?: Record<string, unknown>,
|
|
122
|
+
): boolean {
|
|
123
|
+
if (!input || typeof input !== 'object') return false
|
|
124
|
+
const description =
|
|
125
|
+
typeof input['description'] === 'string' ? input['description'] : undefined
|
|
126
|
+
switch (tool) {
|
|
127
|
+
case 'Bash':
|
|
128
|
+
case 'BashOutput':
|
|
129
|
+
case 'Task':
|
|
130
|
+
case 'Agent':
|
|
131
|
+
return typeof description === 'string' && description.trim().length > 0
|
|
132
|
+
default:
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Return a display suffix for `tool` given its `input`, without the tool
|
|
139
|
+
* name itself. Caller renders `${tool} ${suffix}` (space-separated; no
|
|
140
|
+
* colon) — the checklist format the progress card uses.
|
|
141
|
+
*
|
|
142
|
+
* The optional `preamble` is the most recent short `text` content block
|
|
143
|
+
* the model emitted just before this `tool_use` in the same assistant
|
|
144
|
+
* message — the model's natural "I'll check foo.ts" narration. For the
|
|
145
|
+
* file/search tools (Read/Write/Edit/Grep/Glob/NotebookEdit) we prefer
|
|
146
|
+
* that prose over the filename/pattern fallback when it's short enough
|
|
147
|
+
* to fit on one mobile line (single-line, ≤160 chars). Multi-line or
|
|
148
|
+
* longer text is treated as a narrative step, not a per-tool preamble,
|
|
149
|
+
* and the fallback label wins. Bash/BashOutput prefer their own
|
|
150
|
+
* `input.description` first but fall back to preamble when it's absent
|
|
151
|
+
* (then the raw command). Task/Agent ignore preamble entirely — their
|
|
152
|
+
* `input.description` / `subagent_type` is always set by the harness.
|
|
153
|
+
*/
|
|
154
|
+
export function toolLabel(
|
|
155
|
+
tool: string,
|
|
156
|
+
input?: Record<string, unknown>,
|
|
157
|
+
preamble?: string,
|
|
158
|
+
): string {
|
|
159
|
+
if (!input || typeof input !== 'object') return ''
|
|
160
|
+
const str = (k: string): string | undefined =>
|
|
161
|
+
typeof input[k] === 'string' ? (input[k] as string) : undefined
|
|
162
|
+
|
|
163
|
+
const preambleLabel = (): string | null => {
|
|
164
|
+
if (!preamble) return null
|
|
165
|
+
if (preamble.includes('\n')) return null
|
|
166
|
+
const trimmed = preamble.trim()
|
|
167
|
+
if (!trimmed) return null
|
|
168
|
+
if (trimmed.length > MAX_DESCRIPTION_CHARS) return null
|
|
169
|
+
return trimmed
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
switch (tool) {
|
|
173
|
+
case 'Read':
|
|
174
|
+
case 'Write':
|
|
175
|
+
case 'NotebookEdit':
|
|
176
|
+
case 'Edit': {
|
|
177
|
+
const pre = preambleLabel()
|
|
178
|
+
if (pre) return pre
|
|
179
|
+
return truncate(basename(str('file_path') ?? ''))
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
case 'Bash':
|
|
183
|
+
case 'BashOutput': {
|
|
184
|
+
// Priority order (highest to lowest):
|
|
185
|
+
// 1. input.description — agent-authored, human-readable phrase
|
|
186
|
+
// 2. preamble — model's preceding text narration ("Checking the logs")
|
|
187
|
+
// (same single-line + length gate as file tools)
|
|
188
|
+
// 3. raw command, truncated to MAX_BASH_CHARS
|
|
189
|
+
const description = str('description')
|
|
190
|
+
if (description) return truncate(firstLine(description), MAX_DESCRIPTION_CHARS)
|
|
191
|
+
const pre = preambleLabel()
|
|
192
|
+
if (pre) return pre
|
|
193
|
+
const cmd = str('command') ?? str('bash_id') ?? ''
|
|
194
|
+
return truncate(firstLine(cmd), MAX_BASH_CHARS)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
case 'KillShell':
|
|
198
|
+
return truncate(str('shell_id') ?? '')
|
|
199
|
+
|
|
200
|
+
case 'Glob': {
|
|
201
|
+
const pre = preambleLabel()
|
|
202
|
+
if (pre) return pre
|
|
203
|
+
return truncate(str('pattern') ?? '')
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
case 'Grep': {
|
|
207
|
+
const pre = preambleLabel()
|
|
208
|
+
if (pre) return pre
|
|
209
|
+
const pat = str('pattern') ?? ''
|
|
210
|
+
if (!pat) return ''
|
|
211
|
+
const path = str('path')
|
|
212
|
+
const where = shortenGrepPath(path ?? '')
|
|
213
|
+
return truncate(`"${pat}" (in ${where})`)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
case 'WebFetch':
|
|
217
|
+
return truncate(hostFromUrl(str('url') ?? ''))
|
|
218
|
+
|
|
219
|
+
case 'WebSearch': {
|
|
220
|
+
const q = str('query') ?? ''
|
|
221
|
+
return q ? truncate(`"${q}"`) : ''
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
case 'Task':
|
|
225
|
+
case 'Agent': {
|
|
226
|
+
const desc = str('description') ?? str('subagent_type') ?? ''
|
|
227
|
+
return truncate(desc)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
case 'TodoWrite':
|
|
231
|
+
case 'TaskCreate':
|
|
232
|
+
case 'TaskUpdate':
|
|
233
|
+
case 'TaskList':
|
|
234
|
+
case 'TaskGet':
|
|
235
|
+
case 'TaskStop':
|
|
236
|
+
case 'TaskOutput':
|
|
237
|
+
return ''
|
|
238
|
+
|
|
239
|
+
case 'Skill':
|
|
240
|
+
return truncate(str('skill') ?? '')
|
|
241
|
+
|
|
242
|
+
case 'SlashCommand':
|
|
243
|
+
return truncate(str('command') ?? '')
|
|
244
|
+
|
|
245
|
+
case 'ToolSearch': {
|
|
246
|
+
const q = str('query') ?? ''
|
|
247
|
+
if (!q) return ''
|
|
248
|
+
// "select:Foo,Bar" — the model is loading schemas for named tools.
|
|
249
|
+
// Strip the prefix and show just the names so the checklist reads
|
|
250
|
+
// "ToolSearch Loading schema: Foo, Bar" rather than echoing the raw
|
|
251
|
+
// colon-delimited string.
|
|
252
|
+
const selectMatch = q.match(/^\s*select\s*:\s*(.+)$/i)
|
|
253
|
+
if (selectMatch) {
|
|
254
|
+
const names = selectMatch[1]
|
|
255
|
+
.split(',')
|
|
256
|
+
.map((n) => n.trim())
|
|
257
|
+
.filter((n) => n.length > 0)
|
|
258
|
+
.join(', ')
|
|
259
|
+
return truncate(`Loading schema: ${names}`)
|
|
260
|
+
}
|
|
261
|
+
return truncate(`Searching tools: ${q}`)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
default:
|
|
265
|
+
// MCP tools (`mcp__<server>__<action>`) share a single prefix and a
|
|
266
|
+
// handful of common shapes. Dispatch them here before the generic
|
|
267
|
+
// key-sweep fallback, which would otherwise echo raw query strings.
|
|
268
|
+
if (tool.startsWith('mcp__')) {
|
|
269
|
+
const description = str('description')
|
|
270
|
+
if (description) return truncate(firstLine(stripHtml(description)), MAX_DESCRIPTION_CHARS)
|
|
271
|
+
const label = mcpBaseLabel(tool)
|
|
272
|
+
const query = str('query') ?? str('text') ?? str('name')
|
|
273
|
+
if (label && query) {
|
|
274
|
+
// Reserve room for the " (…)" wrapping so the total label stays
|
|
275
|
+
// under MAX_LABEL_CHARS. 4 chars of framing: " (" + "…" + ")".
|
|
276
|
+
const budget = Math.max(8, MAX_LABEL_CHARS - label.length - 4)
|
|
277
|
+
const preview = truncate(firstLine(stripHtml(query)), budget)
|
|
278
|
+
return `${label} (${preview})`
|
|
279
|
+
}
|
|
280
|
+
if (label) return truncate(label)
|
|
281
|
+
// No derivable base label — fall through to the generic sweep.
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Unknown tool — try common keys in priority order. `description`
|
|
285
|
+
// is checked first because it's the agent's human-readable summary
|
|
286
|
+
// (when present) and beats raw command/path strings.
|
|
287
|
+
for (const k of ['description', 'file_path', 'path', 'url', 'query', 'pattern', 'command']) {
|
|
288
|
+
const v = str(k)
|
|
289
|
+
if (v != null && v.length > 0) {
|
|
290
|
+
if (k === 'file_path' || k === 'path') return truncate(basename(v))
|
|
291
|
+
if (k === 'url') return truncate(hostFromUrl(v))
|
|
292
|
+
if (k === 'description') return truncate(firstLine(v), MAX_DESCRIPTION_CHARS)
|
|
293
|
+
return truncate(firstLine(v))
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return ''
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Derive a "<Server>: <action>" label from an `mcp__<server>__<action>`
|
|
302
|
+
* tool name. Returns the empty string when the name doesn't match the
|
|
303
|
+
* expected shape so callers can fall back to the generic sweep.
|
|
304
|
+
*
|
|
305
|
+
* Servers sometimes ship with noisy machine names (e.g.
|
|
306
|
+
* `switchroom-telegram`) — we map a small allowlist to friendlier
|
|
307
|
+
* labels, and otherwise capitalise the first letter and keep the rest
|
|
308
|
+
* verbatim so unknown servers still render cleanly.
|
|
309
|
+
*/
|
|
310
|
+
function mcpBaseLabel(tool: string): string {
|
|
311
|
+
if (!tool.startsWith('mcp__')) return ''
|
|
312
|
+
const parts = tool.slice('mcp__'.length).split('__')
|
|
313
|
+
if (parts.length < 2) return ''
|
|
314
|
+
const rawServer = parts[0]
|
|
315
|
+
// Action may itself contain `__` in theory; preserve anything after
|
|
316
|
+
// the first separator verbatim. In practice actions are single tokens
|
|
317
|
+
// like `recall` or `stream_reply`.
|
|
318
|
+
const action = parts.slice(1).join('__')
|
|
319
|
+
if (!rawServer || !action) return ''
|
|
320
|
+
return `${prettifyServer(rawServer)}: ${action}`
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function prettifyServer(name: string): string {
|
|
324
|
+
const LABELS: Record<string, string> = {
|
|
325
|
+
'switchroom-telegram': 'Telegram',
|
|
326
|
+
}
|
|
327
|
+
if (LABELS[name]) return LABELS[name]
|
|
328
|
+
if (!name) return name
|
|
329
|
+
return name.charAt(0).toUpperCase() + name.slice(1)
|
|
330
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool-name classification helpers.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code prefixes every MCP tool name with `mcp__<server-key>__` where
|
|
5
|
+
* `<server-key>` is whatever name the host's `.mcp.json` used to register
|
|
6
|
+
* this plugin. The key is user-chosen and historical agents still use
|
|
7
|
+
* `clerk-telegram` while new installs use `switchroom-telegram` (and forks
|
|
8
|
+
* may pick yet other names). Matching a single hardcoded prefix would
|
|
9
|
+
* silently break the orphaned-reply backstop and status-reaction
|
|
10
|
+
* suppression for anyone whose config didn't match — which is how bug
|
|
11
|
+
* #TG-IDLE-LEAK regressed on 2026-04-14.
|
|
12
|
+
*
|
|
13
|
+
* Extracted from server.ts so the classification can be unit-tested
|
|
14
|
+
* without importing the whole MCP-server module (which executes
|
|
15
|
+
* side-effects at import: Bot creation, env-var validation, etc).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const TELEGRAM_TOOL_PREFIX_RE = /^mcp__[^_].*?telegram__/
|
|
19
|
+
|
|
20
|
+
function stripPrefix(toolName: string): string | null {
|
|
21
|
+
if (!TELEGRAM_TOOL_PREFIX_RE.test(toolName)) return null
|
|
22
|
+
return toolName.replace(TELEGRAM_TOOL_PREFIX_RE, '')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* True if `toolName` is this plugin's `reply` or `stream_reply` tool
|
|
27
|
+
* published under ANY registration key (`clerk-telegram`,
|
|
28
|
+
* `switchroom-telegram`, a custom fork, …). Used by the session-tail
|
|
29
|
+
* handler to set `currentTurnReplyCalled` — when this returns false for
|
|
30
|
+
* a real reply call, turn_end mistakenly runs the orphaned-reply
|
|
31
|
+
* backstop and duplicates the message.
|
|
32
|
+
*/
|
|
33
|
+
export function isTelegramReplyTool(toolName: string): boolean {
|
|
34
|
+
const suffix = stripPrefix(toolName)
|
|
35
|
+
return suffix === 'reply' || suffix === 'stream_reply'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* True if `toolName` is any Telegram surface tool whose own handler
|
|
40
|
+
* owns the status-reaction lifecycle for the turn (reply, stream_reply,
|
|
41
|
+
* edit_message, react). The session-tail skips driving a tool reaction
|
|
42
|
+
* for these — the handler itself will fire `setDone()` when the API
|
|
43
|
+
* call completes.
|
|
44
|
+
*/
|
|
45
|
+
export function isTelegramSurfaceTool(toolName: string): boolean {
|
|
46
|
+
const suffix = stripPrefix(toolName)
|
|
47
|
+
return (
|
|
48
|
+
suffix === 'reply'
|
|
49
|
+
|| suffix === 'stream_reply'
|
|
50
|
+
|| suffix === 'edit_message'
|
|
51
|
+
|| suffix === 'react'
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn-flush prose recovery for #51.
|
|
3
|
+
*
|
|
4
|
+
* The gateway's `currentTurnCapturedText` accumulator gates on
|
|
5
|
+
* `currentSessionChatId != null`, while the progress-card driver's
|
|
6
|
+
* `ingest` uses the `chatId` from the IPC envelope (chatHint). When those
|
|
7
|
+
* two views of "is this turn one we're tracking" disagree — e.g., text
|
|
8
|
+
* arrives before enqueue's chatId is captured, or after a mid-turn reset
|
|
9
|
+
* — the progress card renders the assistant prose as narrative steps but
|
|
10
|
+
* `capturedText` stays empty, so `decideTurnFlush` returns `'empty-text'`
|
|
11
|
+
* and the turn-flush backstop never sends the prose to Telegram. The
|
|
12
|
+
* user sees a step bullet on the card and nothing in their chat.
|
|
13
|
+
*
|
|
14
|
+
* This helper bridges the gap: at turn_end, if the gateway has no
|
|
15
|
+
* captured text, peek the progress-card state and recover the assistant
|
|
16
|
+
* prose from the narrative steps. Pure for testability — the gateway
|
|
17
|
+
* is responsible for actually wiring the recovered text into the flush
|
|
18
|
+
* decision.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { ProgressCardState } from './progress-card.js'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Returns the joined assistant prose recorded as narrative steps in the
|
|
25
|
+
* progress-card state, trimmed. Empty string when the state has no
|
|
26
|
+
* narratives (or is undefined).
|
|
27
|
+
*/
|
|
28
|
+
export function recoverProseFromProgressCard(
|
|
29
|
+
state: ProgressCardState | undefined,
|
|
30
|
+
): string {
|
|
31
|
+
if (state == null) return ''
|
|
32
|
+
// Defensive: older state shapes (e.g. partial persisted state, mocks
|
|
33
|
+
// in tests) may lack the `narratives` field. Don't throw.
|
|
34
|
+
if (!Array.isArray(state.narratives)) return ''
|
|
35
|
+
const parts: string[] = []
|
|
36
|
+
for (const n of state.narratives) {
|
|
37
|
+
if (typeof n.text === 'string' && n.text.length > 0) parts.push(n.text)
|
|
38
|
+
}
|
|
39
|
+
return parts.join('\n').trim()
|
|
40
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turn-end flush safety net.
|
|
3
|
+
*
|
|
4
|
+
* Purpose: if a Claude turn ends without the model calling the `reply` or
|
|
5
|
+
* `stream_reply` tool, we still want the user to see the model's final
|
|
6
|
+
* assistant text in Telegram. The live Telegram-plugin gateway tracks the
|
|
7
|
+
* current turn's state (chatId, whether the reply tool was called, and the
|
|
8
|
+
* captured assistant text). At turn_end we call `decideTurnFlush` to decide
|
|
9
|
+
* whether to deterministically flush that captured text via the normal
|
|
10
|
+
* outbound send path.
|
|
11
|
+
*
|
|
12
|
+
* The decision is pure — the caller is responsible for actually sending.
|
|
13
|
+
* Keeping the policy in one unit-testable function is the whole point:
|
|
14
|
+
* the suppress cases (silent-reply markers, empty text, sub-agent turns,
|
|
15
|
+
* system-initiated turns with no inbound user message, the feature flag)
|
|
16
|
+
* are easy to audit and extend.
|
|
17
|
+
*
|
|
18
|
+
* The feature flag `SWITCHROOM_TG_TURN_FLUSH_SAFETY` is enabled by default
|
|
19
|
+
* and can be set to `0` / `false` / `off` to disable without a rebuild.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const SILENT_MARKERS = new Set(['NO_REPLY', 'HEARTBEAT_OK'])
|
|
23
|
+
// Small buffer so `NO_REPLY.` with a stray period still counts as silent.
|
|
24
|
+
const SILENT_MARKER_MAX_LEN = Math.max(
|
|
25
|
+
...Array.from(SILENT_MARKERS, m => m.length),
|
|
26
|
+
) + 2
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Exact-match (case-insensitive, whitespace-trimmed) check for the silent
|
|
30
|
+
* reply sentinels NO_REPLY and HEARTBEAT_OK. Mirrors server.ts
|
|
31
|
+
* `isSilentReplyMarker` intentionally — keeping a local copy avoids a
|
|
32
|
+
* circular-import dependency on server.ts (which has heavy top-level
|
|
33
|
+
* side effects).
|
|
34
|
+
*
|
|
35
|
+
* Trailing-punctuation tolerance: a single trailing non-alphanumeric character
|
|
36
|
+
* (e.g. `NO_REPLY.`) is stripped before matching so accidental punctuation
|
|
37
|
+
* from model output doesn't prevent suppression. Substring matches (e.g.
|
|
38
|
+
* `the agent suggested NO_REPLY earlier`) are still rejected because the
|
|
39
|
+
* length guard rejects anything longer than SILENT_MARKER_MAX_LEN.
|
|
40
|
+
*/
|
|
41
|
+
export function isSilentFlushMarker(text: string | undefined): boolean {
|
|
42
|
+
if (typeof text !== 'string') return false
|
|
43
|
+
let trimmed = text.trim()
|
|
44
|
+
if (trimmed.length === 0) return false
|
|
45
|
+
if (trimmed.length > SILENT_MARKER_MAX_LEN) return false
|
|
46
|
+
// Strip a single trailing non-word character to handle "NO_REPLY." etc.
|
|
47
|
+
if (trimmed.length > 0 && /\W$/.test(trimmed)) {
|
|
48
|
+
trimmed = trimmed.slice(0, -1)
|
|
49
|
+
}
|
|
50
|
+
return SILENT_MARKERS.has(trimmed.toUpperCase())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type FlushDecision =
|
|
54
|
+
| { kind: 'flush'; text: string }
|
|
55
|
+
| { kind: 'skip'; reason: FlushSkipReason }
|
|
56
|
+
|
|
57
|
+
export type FlushSkipReason =
|
|
58
|
+
| 'flag-disabled'
|
|
59
|
+
| 'reply-called'
|
|
60
|
+
| 'no-inbound-chat'
|
|
61
|
+
| 'empty-text'
|
|
62
|
+
| 'silent-marker'
|
|
63
|
+
|
|
64
|
+
export interface FlushDecisionInput {
|
|
65
|
+
/** Inbound chat the turn was servicing. `null` means system-initiated /
|
|
66
|
+
* sub-agent — never flush those, they have their own outbound lifecycle. */
|
|
67
|
+
chatId: string | null
|
|
68
|
+
/** True when the model called `reply` / `stream_reply` at least once for
|
|
69
|
+
* this turn. */
|
|
70
|
+
replyCalled: boolean
|
|
71
|
+
/** Raw text content blocks accumulated from assistant events across the
|
|
72
|
+
* turn. Joined + trimmed internally. */
|
|
73
|
+
capturedText: string[]
|
|
74
|
+
/** Feature flag — defaults to true. Pass `false` to force skip everywhere. */
|
|
75
|
+
flushEnabled?: boolean
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Pure decision: should the gateway deterministically send the model's
|
|
80
|
+
* captured assistant text at turn_end? Returns `{kind: 'flush', text}` with
|
|
81
|
+
* the joined text when yes, otherwise `{kind: 'skip', reason}`.
|
|
82
|
+
*
|
|
83
|
+
* Ordering of checks is deliberate: cheapest/strongest first so logs
|
|
84
|
+
* attribute a skip to the most specific cause.
|
|
85
|
+
*/
|
|
86
|
+
export function decideTurnFlush(input: FlushDecisionInput): FlushDecision {
|
|
87
|
+
const flushEnabled = input.flushEnabled !== false
|
|
88
|
+
if (!flushEnabled) return { kind: 'skip', reason: 'flag-disabled' }
|
|
89
|
+
if (input.replyCalled) return { kind: 'skip', reason: 'reply-called' }
|
|
90
|
+
if (input.chatId == null) return { kind: 'skip', reason: 'no-inbound-chat' }
|
|
91
|
+
const joined = input.capturedText.join('\n').trim()
|
|
92
|
+
if (joined.length === 0) return { kind: 'skip', reason: 'empty-text' }
|
|
93
|
+
if (isSilentFlushMarker(joined)) return { kind: 'skip', reason: 'silent-marker' }
|
|
94
|
+
return { kind: 'flush', text: joined }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Resolve the feature-flag env var. Default: enabled. Set
|
|
99
|
+
* SWITCHROOM_TG_TURN_FLUSH_SAFETY to `0`, `false`, `off`, or `no` to disable.
|
|
100
|
+
*/
|
|
101
|
+
export function isTurnFlushSafetyEnabled(
|
|
102
|
+
env: Record<string, string | undefined> = process.env,
|
|
103
|
+
): boolean {
|
|
104
|
+
const raw = env.SWITCHROOM_TG_TURN_FLUSH_SAFETY
|
|
105
|
+
if (raw == null) return true
|
|
106
|
+
const v = raw.trim().toLowerCase()
|
|
107
|
+
if (v === '0' || v === 'false' || v === 'off' || v === 'no') return false
|
|
108
|
+
return true
|
|
109
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-turn silent-gap tracker for streaming observability.
|
|
3
|
+
*
|
|
4
|
+
* Tracks the longest contiguous interval within a turn where no user-visible
|
|
5
|
+
* signal was sent. Signals include: progress-card edits, status-reaction
|
|
6
|
+
* transitions, answer-lane updates, and fresh sendMessage calls.
|
|
7
|
+
*
|
|
8
|
+
* Keyed by chatId+threadId so concurrent turns in different chats don't
|
|
9
|
+
* collide. Designed to be fully standalone (no grammy/bot dependency) so
|
|
10
|
+
* it's testable with deterministic time injection via vi.useFakeTimers().
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* signalTracker.reset(key, now) // at turn start
|
|
14
|
+
* signalTracker.noteSignal(key, now) // on every user-visible signal
|
|
15
|
+
* signalTracker.getLongestGap(key) // at turn_end
|
|
16
|
+
* signalTracker.clear(key) // after emitting (cleanup)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export interface TurnSignalState {
|
|
20
|
+
/** The time the current gap started (i.e., the last signal time). */
|
|
21
|
+
lastSignalAt: number
|
|
22
|
+
/** The longest gap observed so far (ms). */
|
|
23
|
+
longestGapMs: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Module-scoped map: `"chatId:threadId"` → state. Using a module-level map
|
|
28
|
+
* keeps the tracker lightweight and avoids passing state through every
|
|
29
|
+
* call-site while remaining mockable in tests via the exported functions.
|
|
30
|
+
*/
|
|
31
|
+
const state = new Map<string, TurnSignalState>()
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Begin tracking a new turn. Records `now` as the initial signal time and
|
|
35
|
+
* resets the gap accumulator. Call at the start of each fresh turn.
|
|
36
|
+
*/
|
|
37
|
+
export function reset(key: string, now: number): void {
|
|
38
|
+
state.set(key, { lastSignalAt: now, longestGapMs: 0 })
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Record a user-visible signal. Measures the gap since the last signal and
|
|
43
|
+
* updates `longestGapMs` if this gap is larger.
|
|
44
|
+
*/
|
|
45
|
+
export function noteSignal(key: string, now: number): void {
|
|
46
|
+
const entry = state.get(key)
|
|
47
|
+
if (entry == null) return
|
|
48
|
+
const gap = now - entry.lastSignalAt
|
|
49
|
+
if (gap > entry.longestGapMs) entry.longestGapMs = gap
|
|
50
|
+
entry.lastSignalAt = now
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns the longest gap observed during the current turn (ms).
|
|
55
|
+
* Returns 0 if no tracking state exists for this key.
|
|
56
|
+
*/
|
|
57
|
+
export function getLongestGap(key: string): number {
|
|
58
|
+
return state.get(key)?.longestGapMs ?? 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns the last signal time for this key, or undefined if not tracked.
|
|
63
|
+
* Useful for computing a trailing gap at turn_end before calling clear().
|
|
64
|
+
*/
|
|
65
|
+
export function getLastSignalAt(key: string): number | undefined {
|
|
66
|
+
return state.get(key)?.lastSignalAt
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Remove state for this key. Call after emitting the turn_signal_gap metric.
|
|
71
|
+
*/
|
|
72
|
+
export function clear(key: string): void {
|
|
73
|
+
state.delete(key)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Exposed for tests — clears all tracked state. */
|
|
77
|
+
export function __resetAllForTests(): void {
|
|
78
|
+
state.clear()
|
|
79
|
+
}
|