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,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #654 regression tests — deterministic double-message fix via card
|
|
3
|
+
* takeover.
|
|
4
|
+
*
|
|
5
|
+
* Bug: when an agent's turn took longer than `initialDelayMs` (60s) AND
|
|
6
|
+
* the agent emitted assistant text without calling `reply` /
|
|
7
|
+
* `stream_reply` (turn-flush path), the user saw TWO outbound Telegram
|
|
8
|
+
* messages — the pinned progress card AND the turn-flush bubble — for
|
|
9
|
+
* one logical reply.
|
|
10
|
+
*
|
|
11
|
+
* Root cause: the gateway's turn-flush path issued a fresh
|
|
12
|
+
* `bot.api.sendMessage` even when a progress card was already on screen
|
|
13
|
+
* for that turn. The driver's `forceCompleteTurn` couldn't help because
|
|
14
|
+
* once the deferred-emit timer had fired, no path existed to retract
|
|
15
|
+
* the posted card — `flush()` would only edit it to "Done".
|
|
16
|
+
*
|
|
17
|
+
* Fix: add a `takeOverCard` method to the driver that:
|
|
18
|
+
* - cancels the pending deferred-emit timer if not yet fired
|
|
19
|
+
* - sets `cardTakenOver = true` so subsequent `flush()` calls
|
|
20
|
+
* short-circuit (no further "Done" edit)
|
|
21
|
+
* - returns `{ wasEmitted, turnKey }` so the caller (turn-flush)
|
|
22
|
+
* can look up the pinned messageId and rewrite it in place via
|
|
23
|
+
* `editMessageText` instead of creating a second message.
|
|
24
|
+
*
|
|
25
|
+
* The harness gap that hid the bug: no existing test wired a real
|
|
26
|
+
* driver into a long-turn scenario. `turn-flush-safety.test.ts`
|
|
27
|
+
* covered `decideTurnFlush()` only; `real-gateway-i6` covered turn-
|
|
28
|
+
* flush replay/dedup but never modeled a card already on screen.
|
|
29
|
+
*
|
|
30
|
+
* These tests pin the driver-level contract. The gateway integration
|
|
31
|
+
* is exercised in the bridged scenario at the bottom of this file.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { describe, it, expect } from 'vitest'
|
|
35
|
+
import { createProgressDriver } from '../progress-card-driver.js'
|
|
36
|
+
import type { SessionEvent } from '../session-tail.js'
|
|
37
|
+
|
|
38
|
+
function harness(opts?: { initialDelayMs?: number }) {
|
|
39
|
+
let now = 1000
|
|
40
|
+
const timers: Array<{ fireAt: number; fn: () => void; ref: number; repeat?: number }> = []
|
|
41
|
+
let nextRef = 0
|
|
42
|
+
const emits: Array<{
|
|
43
|
+
chatId: string
|
|
44
|
+
threadId?: string
|
|
45
|
+
turnKey: string
|
|
46
|
+
html: string
|
|
47
|
+
done: boolean
|
|
48
|
+
isFirstEmit: boolean
|
|
49
|
+
}> = []
|
|
50
|
+
|
|
51
|
+
const driver = createProgressDriver({
|
|
52
|
+
emit: (a) => emits.push(a),
|
|
53
|
+
minIntervalMs: 0,
|
|
54
|
+
coalesceMs: 0,
|
|
55
|
+
initialDelayMs: opts?.initialDelayMs ?? 60_000,
|
|
56
|
+
promoteAfterMs: 999_999,
|
|
57
|
+
now: () => now,
|
|
58
|
+
setTimeout: (fn, ms) => {
|
|
59
|
+
const ref = nextRef++
|
|
60
|
+
timers.push({ fireAt: now + ms, fn, ref })
|
|
61
|
+
return { ref }
|
|
62
|
+
},
|
|
63
|
+
clearTimeout: (handle) => {
|
|
64
|
+
const target = (handle as { ref: number }).ref
|
|
65
|
+
const idx = timers.findIndex((t) => t.ref === target)
|
|
66
|
+
if (idx !== -1) timers.splice(idx, 1)
|
|
67
|
+
},
|
|
68
|
+
setInterval: (fn, ms) => {
|
|
69
|
+
const ref = nextRef++
|
|
70
|
+
timers.push({ fireAt: now + ms, fn, ref, repeat: ms })
|
|
71
|
+
return { ref }
|
|
72
|
+
},
|
|
73
|
+
clearInterval: (handle) => {
|
|
74
|
+
const target = (handle as { ref: number }).ref
|
|
75
|
+
const idx = timers.findIndex((t) => t.ref === target)
|
|
76
|
+
if (idx !== -1) timers.splice(idx, 1)
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const advance = (ms: number): void => {
|
|
81
|
+
now += ms
|
|
82
|
+
for (;;) {
|
|
83
|
+
timers.sort((a, b) => a.fireAt - b.fireAt)
|
|
84
|
+
const next = timers[0]
|
|
85
|
+
if (!next || next.fireAt > now) break
|
|
86
|
+
if (next.repeat != null) {
|
|
87
|
+
next.fireAt += next.repeat
|
|
88
|
+
next.fn()
|
|
89
|
+
} else {
|
|
90
|
+
timers.shift()
|
|
91
|
+
next.fn()
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { driver, emits, advance }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let nextMsgId = 1
|
|
100
|
+
function enqueue(chatId: string, text = 'q', threadId: string | null = null): SessionEvent {
|
|
101
|
+
return {
|
|
102
|
+
kind: 'enqueue',
|
|
103
|
+
chatId,
|
|
104
|
+
messageId: String(nextMsgId++),
|
|
105
|
+
threadId,
|
|
106
|
+
rawContent: `<channel chat_id="${chatId}">${text}</channel>`,
|
|
107
|
+
} as unknown as SessionEvent
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
describe('takeOverCard — #654 regression', () => {
|
|
111
|
+
it('returns wasEmitted=false when card has not yet emitted (pre-60s turn)', () => {
|
|
112
|
+
// Fast-turn case: turn-flush fires before the deferred-emit timer.
|
|
113
|
+
// Driver suppresses the card; turn-flush sends fresh.
|
|
114
|
+
const { driver } = harness({ initialDelayMs: 60_000 })
|
|
115
|
+
driver.ingest(enqueue('c1'), 'c1')
|
|
116
|
+
// Don't advance — timer still pending.
|
|
117
|
+
|
|
118
|
+
const result = driver.takeOverCard({ chatId: 'c1' })
|
|
119
|
+
expect(result.wasEmitted).toBe(false)
|
|
120
|
+
expect(result.turnKey).not.toBeNull()
|
|
121
|
+
expect(typeof result.turnKey).toBe('string')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('returns wasEmitted=true when deferred-emit timer has fired (the #654 path)', () => {
|
|
125
|
+
// Slow-turn case: the card has been emitted to the chat. takeOverCard
|
|
126
|
+
// signals that the caller should edit-in-place rather than send fresh.
|
|
127
|
+
const { driver, emits, advance } = harness({ initialDelayMs: 60_000 })
|
|
128
|
+
driver.ingest(
|
|
129
|
+
enqueue('c1'),
|
|
130
|
+
'c1',
|
|
131
|
+
)
|
|
132
|
+
advance(60_000)
|
|
133
|
+
expect(emits.length).toBeGreaterThan(0) // card emitted
|
|
134
|
+
|
|
135
|
+
const result = driver.takeOverCard({ chatId: 'c1' })
|
|
136
|
+
expect(result.wasEmitted).toBe(true)
|
|
137
|
+
expect(typeof result.turnKey).toBe('string')
|
|
138
|
+
expect(result.turnKey).toContain('c1')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('cancels the pending deferred-emit timer (no late card emission)', () => {
|
|
142
|
+
// After takeOverCard cancels the timer, advancing past the original
|
|
143
|
+
// delay must NOT produce a card emit.
|
|
144
|
+
const { driver, emits, advance } = harness({ initialDelayMs: 60_000 })
|
|
145
|
+
driver.ingest(
|
|
146
|
+
enqueue('c1'),
|
|
147
|
+
'c1',
|
|
148
|
+
)
|
|
149
|
+
expect(emits.length).toBe(0) // suppressed by initial delay
|
|
150
|
+
|
|
151
|
+
driver.takeOverCard({ chatId: 'c1' })
|
|
152
|
+
advance(120_000) // way past 60s
|
|
153
|
+
|
|
154
|
+
expect(emits.length).toBe(0) // timer was cancelled — no late emit
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('blocks subsequent flushes — driver.ingest(turn_end) does NOT emit a "Done" edit', () => {
|
|
158
|
+
// The bug case: after card is on screen, gateway calls takeOverCard,
|
|
159
|
+
// then session-tail dispatches turn_end which the driver ingests.
|
|
160
|
+
// Without the cardTakenOver guard, turn_end would call flush(forceDone)
|
|
161
|
+
// → editMessageText("Done") — wasted edit. With the guard, no emit.
|
|
162
|
+
const { driver, emits, advance } = harness({ initialDelayMs: 60_000 })
|
|
163
|
+
driver.ingest(
|
|
164
|
+
enqueue('c1'),
|
|
165
|
+
'c1',
|
|
166
|
+
)
|
|
167
|
+
advance(60_000)
|
|
168
|
+
const emitsAfterCard = emits.length
|
|
169
|
+
expect(emitsAfterCard).toBeGreaterThan(0)
|
|
170
|
+
|
|
171
|
+
driver.takeOverCard({ chatId: 'c1' })
|
|
172
|
+
|
|
173
|
+
// Now simulate the driver receiving turn_end (as session-tail would
|
|
174
|
+
// dispatch synchronously upstream of the gateway's turn-flush block).
|
|
175
|
+
driver.ingest(
|
|
176
|
+
{ kind: 'turn_end', durationMs: 70_000 } as unknown as SessionEvent,
|
|
177
|
+
'c1',
|
|
178
|
+
)
|
|
179
|
+
expect(emits.length).toBe(emitsAfterCard) // no additional edits
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('idempotent — second call returns same shape, no double-cancel side-effects', () => {
|
|
183
|
+
const { driver, emits, advance } = harness({ initialDelayMs: 60_000 })
|
|
184
|
+
driver.ingest(
|
|
185
|
+
enqueue('c1'),
|
|
186
|
+
'c1',
|
|
187
|
+
)
|
|
188
|
+
advance(60_000)
|
|
189
|
+
const emitsAfter1 = emits.length
|
|
190
|
+
|
|
191
|
+
const r1 = driver.takeOverCard({ chatId: 'c1' })
|
|
192
|
+
const r2 = driver.takeOverCard({ chatId: 'c1' })
|
|
193
|
+
expect(r1).toEqual(r2)
|
|
194
|
+
expect(emits.length).toBe(emitsAfter1)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it('returns null turnKey when no active card exists for (chatId, threadId)', () => {
|
|
198
|
+
const { driver } = harness({ initialDelayMs: 60_000 })
|
|
199
|
+
const result = driver.takeOverCard({ chatId: 'never-enqueued' })
|
|
200
|
+
expect(result).toEqual({ wasEmitted: false, turnKey: null })
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('routes by chatId+threadId — separate chats do not clobber each other', () => {
|
|
204
|
+
const { driver } = harness({ initialDelayMs: 60_000 })
|
|
205
|
+
driver.ingest(enqueue('c1'), 'c1')
|
|
206
|
+
driver.ingest(enqueue('c2'), 'c2')
|
|
207
|
+
|
|
208
|
+
// Take over c1 — c2's card must remain untouched.
|
|
209
|
+
const r1 = driver.takeOverCard({ chatId: 'c1' })
|
|
210
|
+
expect(r1.turnKey).toContain('c1')
|
|
211
|
+
expect(r1.turnKey).not.toContain('c2')
|
|
212
|
+
|
|
213
|
+
// c2 still has its own active card, distinct turnKey.
|
|
214
|
+
const r2 = driver.takeOverCard({ chatId: 'c2' })
|
|
215
|
+
expect(r2.turnKey).toContain('c2')
|
|
216
|
+
expect(r2.turnKey).not.toContain('c1')
|
|
217
|
+
})
|
|
218
|
+
})
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug D — turn-flush dedup branch must NOT prematurely fire setDone on
|
|
3
|
+
* the status-reaction controller.
|
|
4
|
+
*
|
|
5
|
+
* Background. The gateway's turn_end handler has three exits:
|
|
6
|
+
* (1) `silent-marker` skip — drops streams, fires ctrl.setDone(), purges.
|
|
7
|
+
* (2) `flush` — schedules an async IIFE that waits 500ms and either:
|
|
8
|
+
* (2a) suppresses the flush because `getRecentOutboundCount > 0`
|
|
9
|
+
* (the reply tool already sent something), OR
|
|
10
|
+
* (2b) fires the captured text via bot.api.sendMessage as a backstop.
|
|
11
|
+
* (3) main path — ctrl.setDone(), purge, telemetry.
|
|
12
|
+
*
|
|
13
|
+
* Path (2a) used to call `backstopCtrl.setDone()` on a 500ms-lagged read
|
|
14
|
+
* of local history — not a confirmation that anything actually reached
|
|
15
|
+
* Telegram. With Bug Z's fix, stream_reply(done=true) on the default
|
|
16
|
+
* lane fires `endStatusReaction('done')` AFTER `stream.finalize()`
|
|
17
|
+
* resolves (meaning the final draft edit landed in Telegram). So the
|
|
18
|
+
* authoritative 👍 source is the post-finalize callback, not the
|
|
19
|
+
* dedup-branch heuristic.
|
|
20
|
+
*
|
|
21
|
+
* This test pins the contract for the dedup branch: when
|
|
22
|
+
* `getRecentOutboundCount > 0`, the dedup branch must NOT fire setDone
|
|
23
|
+
* on the controller. The controller's terminal transition is left to
|
|
24
|
+
* the stream_reply post-finalize callback (already exercised in
|
|
25
|
+
* stream-reply-handler.test.ts).
|
|
26
|
+
*
|
|
27
|
+
* The gateway IIFE is too entangled to import directly. Rather than
|
|
28
|
+
* refactor the entire turn_end handler for testability in this PR, we
|
|
29
|
+
* model the dedup-branch logic as a pure function below and pin the
|
|
30
|
+
* post-fix invariant. If the gateway is ever refactored to extract
|
|
31
|
+
* this branch, the same assertions apply unchanged.
|
|
32
|
+
*/
|
|
33
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
34
|
+
|
|
35
|
+
interface MockController {
|
|
36
|
+
setDone: () => void
|
|
37
|
+
setError: () => void
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface DedupBranchDeps {
|
|
41
|
+
getRecentOutboundCount: (chatId: string, withinSec: number) => number
|
|
42
|
+
purgeReactionTracking: (key: string) => void
|
|
43
|
+
ctrl: MockController | null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Extract of the gateway turn-flush IIFE's dedup branch. Mirrors the
|
|
48
|
+
* code at `telegram-plugin/gateway/gateway.ts` lines ~3365-3376
|
|
49
|
+
* (post-fix). Returns true if the flush should be suppressed.
|
|
50
|
+
*/
|
|
51
|
+
function applyDedupBranch(
|
|
52
|
+
chatId: string,
|
|
53
|
+
statusKeyValue: string,
|
|
54
|
+
deps: DedupBranchDeps,
|
|
55
|
+
): boolean {
|
|
56
|
+
const recentCount = deps.getRecentOutboundCount(chatId, 2)
|
|
57
|
+
if (recentCount > 0) {
|
|
58
|
+
// Bug D fix: do NOT fire setDone here. The post-finalize callback
|
|
59
|
+
// in stream-reply-handler.ts owns the terminal 👍 transition.
|
|
60
|
+
deps.purgeReactionTracking(statusKeyValue)
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
return false
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
describe('Bug D — turn-flush dedup branch (post-fix)', () => {
|
|
67
|
+
it('suppresses flush when recentCount > 0 AND does NOT prematurely fire setDone', () => {
|
|
68
|
+
const setDone = vi.fn()
|
|
69
|
+
const setError = vi.fn()
|
|
70
|
+
const purgeReactionTracking = vi.fn()
|
|
71
|
+
const getRecentOutboundCount = vi.fn(() => 1) // dedup case: 1 outbound landed within 2s
|
|
72
|
+
|
|
73
|
+
const suppressed = applyDedupBranch(
|
|
74
|
+
'-100',
|
|
75
|
+
'-100:_',
|
|
76
|
+
{
|
|
77
|
+
getRecentOutboundCount,
|
|
78
|
+
purgeReactionTracking,
|
|
79
|
+
ctrl: { setDone, setError },
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
expect(suppressed).toBe(true)
|
|
84
|
+
expect(getRecentOutboundCount).toHaveBeenCalledWith('-100', 2)
|
|
85
|
+
expect(purgeReactionTracking).toHaveBeenCalledWith('-100:_')
|
|
86
|
+
// Critical: the controller is NOT touched here. Bug Z's
|
|
87
|
+
// post-finalize callback in stream-reply-handler.ts is what
|
|
88
|
+
// transitions the controller to terminal 👍 — and only after the
|
|
89
|
+
// final draft edit confirmedly lands in Telegram.
|
|
90
|
+
expect(setDone).not.toHaveBeenCalled()
|
|
91
|
+
expect(setError).not.toHaveBeenCalled()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('falls through (returns false) when recentCount == 0 — backstop send required', () => {
|
|
95
|
+
// The other branch path: no recent outbound, so the IIFE will
|
|
96
|
+
// proceed to bot.api.sendMessage and (on success) call setDone
|
|
97
|
+
// there. This test pins that the dedup branch does NOT short-
|
|
98
|
+
// circuit when there's nothing to dedup against.
|
|
99
|
+
const setDone = vi.fn()
|
|
100
|
+
const purgeReactionTracking = vi.fn()
|
|
101
|
+
const getRecentOutboundCount = vi.fn(() => 0)
|
|
102
|
+
|
|
103
|
+
const suppressed = applyDedupBranch(
|
|
104
|
+
'-200',
|
|
105
|
+
'-200:_',
|
|
106
|
+
{
|
|
107
|
+
getRecentOutboundCount,
|
|
108
|
+
purgeReactionTracking,
|
|
109
|
+
ctrl: { setDone, setError: vi.fn() },
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
expect(suppressed).toBe(false)
|
|
114
|
+
expect(getRecentOutboundCount).toHaveBeenCalledWith('-200', 2)
|
|
115
|
+
// Neither side-effect should fire — the IIFE's backstop-send arm
|
|
116
|
+
// owns those (purge in the finally block, setDone after sendMessage
|
|
117
|
+
// resolves).
|
|
118
|
+
expect(purgeReactionTracking).not.toHaveBeenCalled()
|
|
119
|
+
expect(setDone).not.toHaveBeenCalled()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('handles a missing controller gracefully (no throw)', () => {
|
|
123
|
+
// Defence-in-depth: the IIFE captures `backstopCtrl = ctrl` which
|
|
124
|
+
// may be null if no status-reaction was ever queued for this
|
|
125
|
+
// chat+thread. The guard previously read `if (backstopCtrl)
|
|
126
|
+
// backstopCtrl.setDone()`. With setDone removed entirely this is a
|
|
127
|
+
// non-issue, but pin the invariant anyway.
|
|
128
|
+
const purgeReactionTracking = vi.fn()
|
|
129
|
+
const getRecentOutboundCount = vi.fn(() => 5)
|
|
130
|
+
|
|
131
|
+
expect(() =>
|
|
132
|
+
applyDedupBranch(
|
|
133
|
+
'-300',
|
|
134
|
+
'-300:_',
|
|
135
|
+
{
|
|
136
|
+
getRecentOutboundCount,
|
|
137
|
+
purgeReactionTracking,
|
|
138
|
+
ctrl: null,
|
|
139
|
+
},
|
|
140
|
+
),
|
|
141
|
+
).not.toThrow()
|
|
142
|
+
expect(purgeReactionTracking).toHaveBeenCalledWith('-300:_')
|
|
143
|
+
})
|
|
144
|
+
})
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the prose-recovery helper used by the turn-flush backstop
|
|
3
|
+
* to bridge the divergence between the gateway's `capturedText`
|
|
4
|
+
* accumulator and the progress-card driver's narrative state. See #51.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from 'vitest'
|
|
8
|
+
import type { ProgressCardState, NarrativeStep } from '../progress-card.js'
|
|
9
|
+
import { recoverProseFromProgressCard } from '../turn-flush-prose-recovery.js'
|
|
10
|
+
|
|
11
|
+
function narrative(id: number, text: string): NarrativeStep {
|
|
12
|
+
return { id, text, state: 'done', startedAt: 0, toolCount: 0 }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function stateWith(narratives: NarrativeStep[]): ProgressCardState {
|
|
16
|
+
return {
|
|
17
|
+
turnStartedAt: 0,
|
|
18
|
+
items: [],
|
|
19
|
+
stage: 'idle',
|
|
20
|
+
thinking: false,
|
|
21
|
+
narratives,
|
|
22
|
+
subAgents: new Map(),
|
|
23
|
+
pendingAgentSpawns: new Map(),
|
|
24
|
+
} as unknown as ProgressCardState
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe('recoverProseFromProgressCard', () => {
|
|
28
|
+
it('returns empty string for undefined state', () => {
|
|
29
|
+
expect(recoverProseFromProgressCard(undefined)).toBe('')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('returns empty string when there are no narratives', () => {
|
|
33
|
+
expect(recoverProseFromProgressCard(stateWith([]))).toBe('')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('returns empty string when the narratives field is missing', () => {
|
|
37
|
+
// Defensive: partial state (e.g. older persisted shape) must not throw.
|
|
38
|
+
const partial = { turnStartedAt: 0, items: [], stage: 'idle', thinking: false } as unknown as ProgressCardState
|
|
39
|
+
expect(recoverProseFromProgressCard(partial)).toBe('')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('joins narrative text in order, newline-separated', () => {
|
|
43
|
+
const state = stateWith([
|
|
44
|
+
narrative(1, 'Reading the file.'),
|
|
45
|
+
narrative(2, 'Found the issue.'),
|
|
46
|
+
narrative(3, 'Patching gateway.ts.'),
|
|
47
|
+
])
|
|
48
|
+
expect(recoverProseFromProgressCard(state)).toBe(
|
|
49
|
+
'Reading the file.\nFound the issue.\nPatching gateway.ts.',
|
|
50
|
+
)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('skips empty-string narratives but preserves order of the rest', () => {
|
|
54
|
+
const state = stateWith([
|
|
55
|
+
narrative(1, 'first'),
|
|
56
|
+
narrative(2, ''),
|
|
57
|
+
narrative(3, 'third'),
|
|
58
|
+
])
|
|
59
|
+
expect(recoverProseFromProgressCard(state)).toBe('first\nthird')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('trims surrounding whitespace from the joined result', () => {
|
|
63
|
+
const state = stateWith([narrative(1, ' prose with edges ')])
|
|
64
|
+
expect(recoverProseFromProgressCard(state)).toBe('prose with edges')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('recovers the original incident — single narrative line that should have flushed', () => {
|
|
68
|
+
// Mirrors the #45/#51 incident transcript: the assistant emitted
|
|
69
|
+
// prose-as-step but never called reply. Recovery must surface that
|
|
70
|
+
// text so the flush backstop can send it.
|
|
71
|
+
const state = stateWith([
|
|
72
|
+
narrative(1, 'Just the caption swap — the Klanker body stays.'),
|
|
73
|
+
])
|
|
74
|
+
expect(recoverProseFromProgressCard(state)).toBe(
|
|
75
|
+
'Just the caption swap — the Klanker body stays.',
|
|
76
|
+
)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit coverage for the gateway-side turn-end flush safety net.
|
|
3
|
+
*
|
|
4
|
+
* The fix restores a deterministic "if the model produced assistant text
|
|
5
|
+
* but never called reply/stream_reply, send that text to Telegram at
|
|
6
|
+
* turn_end" rule, after it was silently gated off in the gateway by an
|
|
7
|
+
* earlier `progressDriver == null` condition. Ken hit this live three
|
|
8
|
+
* times in a row — turns ended with visible reasoning in the transcript
|
|
9
|
+
* but no Telegram bubble.
|
|
10
|
+
*
|
|
11
|
+
* These tests pin the pure decision function. The actual send path in
|
|
12
|
+
* gateway.ts is the same one used by the `reply` tool, so if this policy
|
|
13
|
+
* returns `{kind: 'flush', text}` we know the message will reach the chat.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { describe, it, expect } from 'vitest'
|
|
17
|
+
import {
|
|
18
|
+
decideTurnFlush,
|
|
19
|
+
isSilentFlushMarker,
|
|
20
|
+
isTurnFlushSafetyEnabled,
|
|
21
|
+
} from '../turn-flush-safety.js'
|
|
22
|
+
|
|
23
|
+
describe('decideTurnFlush', () => {
|
|
24
|
+
it('(a) does NOT flush when the reply tool was called', () => {
|
|
25
|
+
const decision = decideTurnFlush({
|
|
26
|
+
chatId: '100',
|
|
27
|
+
replyCalled: true,
|
|
28
|
+
capturedText: ['here is the answer'],
|
|
29
|
+
})
|
|
30
|
+
expect(decision).toEqual({ kind: 'skip', reason: 'reply-called' })
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('(b) flushes when the turn produced text but the reply tool was never called', () => {
|
|
34
|
+
const decision = decideTurnFlush({
|
|
35
|
+
chatId: '200',
|
|
36
|
+
replyCalled: false,
|
|
37
|
+
capturedText: ['here is the answer', 'more detail'],
|
|
38
|
+
})
|
|
39
|
+
expect(decision).toEqual({
|
|
40
|
+
kind: 'flush',
|
|
41
|
+
text: 'here is the answer\nmore detail',
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('(c) HEARTBEAT_OK is a silent marker — flush suppressed', () => {
|
|
46
|
+
const decision = decideTurnFlush({
|
|
47
|
+
chatId: '300',
|
|
48
|
+
replyCalled: false,
|
|
49
|
+
capturedText: ['HEARTBEAT_OK'],
|
|
50
|
+
})
|
|
51
|
+
expect(decision).toEqual({ kind: 'skip', reason: 'silent-marker' })
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('NO_REPLY is a silent marker — flush suppressed', () => {
|
|
55
|
+
const decision = decideTurnFlush({
|
|
56
|
+
chatId: '301',
|
|
57
|
+
replyCalled: false,
|
|
58
|
+
capturedText: ['NO_REPLY'],
|
|
59
|
+
})
|
|
60
|
+
expect(decision).toEqual({ kind: 'skip', reason: 'silent-marker' })
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('silent markers match case-insensitively with whitespace trim', () => {
|
|
64
|
+
expect(
|
|
65
|
+
decideTurnFlush({
|
|
66
|
+
chatId: '302',
|
|
67
|
+
replyCalled: false,
|
|
68
|
+
capturedText: [' heartbeat_ok '],
|
|
69
|
+
}),
|
|
70
|
+
).toEqual({ kind: 'skip', reason: 'silent-marker' })
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('(d) background sub-agent turn (chatId == null) is NOT flushed', () => {
|
|
74
|
+
// Sub-agent turns never populate `currentSessionChatId` — we surface
|
|
75
|
+
// that here as `chatId: null` and the decision must be skip.
|
|
76
|
+
const decision = decideTurnFlush({
|
|
77
|
+
chatId: null,
|
|
78
|
+
replyCalled: false,
|
|
79
|
+
capturedText: ['child agent result'],
|
|
80
|
+
})
|
|
81
|
+
expect(decision).toEqual({ kind: 'skip', reason: 'no-inbound-chat' })
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('empty captured text is NOT flushed', () => {
|
|
85
|
+
expect(
|
|
86
|
+
decideTurnFlush({
|
|
87
|
+
chatId: '400',
|
|
88
|
+
replyCalled: false,
|
|
89
|
+
capturedText: [],
|
|
90
|
+
}),
|
|
91
|
+
).toEqual({ kind: 'skip', reason: 'empty-text' })
|
|
92
|
+
expect(
|
|
93
|
+
decideTurnFlush({
|
|
94
|
+
chatId: '400',
|
|
95
|
+
replyCalled: false,
|
|
96
|
+
capturedText: ['', ' ', '\n'],
|
|
97
|
+
}),
|
|
98
|
+
).toEqual({ kind: 'skip', reason: 'empty-text' })
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('feature flag off disables flush even on a legitimate orphan', () => {
|
|
102
|
+
const decision = decideTurnFlush({
|
|
103
|
+
chatId: '500',
|
|
104
|
+
replyCalled: false,
|
|
105
|
+
capturedText: ['an answer'],
|
|
106
|
+
flushEnabled: false,
|
|
107
|
+
})
|
|
108
|
+
expect(decision).toEqual({ kind: 'skip', reason: 'flag-disabled' })
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('flushEnabled defaults to true when omitted', () => {
|
|
112
|
+
const decision = decideTurnFlush({
|
|
113
|
+
chatId: '600',
|
|
114
|
+
replyCalled: false,
|
|
115
|
+
capturedText: ['some answer'],
|
|
116
|
+
})
|
|
117
|
+
expect(decision.kind).toBe('flush')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('prioritises flag-disabled over every other skip reason', () => {
|
|
121
|
+
expect(
|
|
122
|
+
decideTurnFlush({
|
|
123
|
+
chatId: null,
|
|
124
|
+
replyCalled: true,
|
|
125
|
+
capturedText: [],
|
|
126
|
+
flushEnabled: false,
|
|
127
|
+
}),
|
|
128
|
+
).toEqual({ kind: 'skip', reason: 'flag-disabled' })
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('prioritises reply-called over chatId/empty checks', () => {
|
|
132
|
+
expect(
|
|
133
|
+
decideTurnFlush({
|
|
134
|
+
chatId: null,
|
|
135
|
+
replyCalled: true,
|
|
136
|
+
capturedText: [],
|
|
137
|
+
}),
|
|
138
|
+
).toEqual({ kind: 'skip', reason: 'reply-called' })
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
describe('isSilentFlushMarker', () => {
|
|
143
|
+
it('recognises NO_REPLY and HEARTBEAT_OK exactly', () => {
|
|
144
|
+
expect(isSilentFlushMarker('NO_REPLY')).toBe(true)
|
|
145
|
+
expect(isSilentFlushMarker('HEARTBEAT_OK')).toBe(true)
|
|
146
|
+
expect(isSilentFlushMarker('no_reply')).toBe(true)
|
|
147
|
+
expect(isSilentFlushMarker(' HEARTBEAT_OK ')).toBe(true)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('does NOT match prose containing the marker', () => {
|
|
151
|
+
expect(isSilentFlushMarker('the model said NO_REPLY earlier')).toBe(false)
|
|
152
|
+
expect(isSilentFlushMarker('HEARTBEAT_OK; shutting down')).toBe(false)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('does not match undefined/empty', () => {
|
|
156
|
+
expect(isSilentFlushMarker(undefined)).toBe(false)
|
|
157
|
+
expect(isSilentFlushMarker('')).toBe(false)
|
|
158
|
+
expect(isSilentFlushMarker(' ')).toBe(false)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('tolerates a single trailing non-word character (#299 review feedback)', () => {
|
|
162
|
+
expect(isSilentFlushMarker('NO_REPLY.')).toBe(true)
|
|
163
|
+
expect(isSilentFlushMarker('NO_REPLY!')).toBe(true)
|
|
164
|
+
expect(isSilentFlushMarker('HEARTBEAT_OK,')).toBe(true)
|
|
165
|
+
expect(isSilentFlushMarker(' HEARTBEAT_OK. ')).toBe(true)
|
|
166
|
+
// Two trailing punctuation chars → not stripped, no match
|
|
167
|
+
expect(isSilentFlushMarker('NO_REPLY!!')).toBe(false)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
describe('isTurnFlushSafetyEnabled', () => {
|
|
172
|
+
it('defaults to true when the env var is absent', () => {
|
|
173
|
+
expect(isTurnFlushSafetyEnabled({})).toBe(true)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('disables on explicit false-y values', () => {
|
|
177
|
+
for (const v of ['0', 'false', 'off', 'no', 'FALSE', ' OFF ']) {
|
|
178
|
+
expect(isTurnFlushSafetyEnabled({ SWITCHROOM_TG_TURN_FLUSH_SAFETY: v }))
|
|
179
|
+
.toBe(false)
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('stays enabled for anything else (including "1", "true", unknown)', () => {
|
|
184
|
+
for (const v of ['1', 'true', 'on', 'yes', 'anything']) {
|
|
185
|
+
expect(isTurnFlushSafetyEnabled({ SWITCHROOM_TG_TURN_FLUSH_SAFETY: v }))
|
|
186
|
+
.toBe(true)
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
})
|