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,565 @@
|
|
|
1
|
+
import { isSilentFlushMarker } from './turn-flush-safety.js'
|
|
2
|
+
import {
|
|
3
|
+
DRAFT_METHOD_UNAVAILABLE_RE as _DRAFT_METHOD_UNAVAILABLE_RE,
|
|
4
|
+
DRAFT_CHAT_UNSUPPORTED_RE as _DRAFT_CHAT_UNSUPPORTED_RE,
|
|
5
|
+
shouldFallbackFromDraftTransport as _shouldFallbackFromDraftTransport,
|
|
6
|
+
allocateDraftId as _allocateDraftId,
|
|
7
|
+
__resetDraftIdForTests as _resetDraftIdForTests,
|
|
8
|
+
} from './draft-transport.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Answer-lane incremental streaming for long Telegram replies.
|
|
12
|
+
*
|
|
13
|
+
* This module implements the "narrative" liveness layer described in
|
|
14
|
+
* `reference/know-what-my-agent-is-doing.md`:
|
|
15
|
+
*
|
|
16
|
+
* ambient → 👀 ack reaction
|
|
17
|
+
* structured → progress card (existing, via stream-reply-handler.ts lane:'progress')
|
|
18
|
+
* narrative → THIS — incremental answer text appearing below the card as it arrives
|
|
19
|
+
*
|
|
20
|
+
* Design constraints honored:
|
|
21
|
+
* 1. Separate message ID from the progress card — never overwritten.
|
|
22
|
+
* 2. sendMessageDraft for DMs (detected by chatType='private'); regular
|
|
23
|
+
* sendMessage+editMessageText for groups/channels. Runtime fallback
|
|
24
|
+
* when draft API rejects (DRAFT_METHOD_UNAVAILABLE_RE / DRAFT_CHAT_UNSUPPORTED_RE).
|
|
25
|
+
* 3. minInitialChars (~50) — don't open the answer lane until enough text
|
|
26
|
+
* has arrived. Lowered 400 → 50 in #553 PR 3 so short replies
|
|
27
|
+
* ("yes", "done", "the answer is 42") become visible on the first
|
|
28
|
+
* text event instead of waiting for `stream_reply` materialize.
|
|
29
|
+
* 4. Turn-end materializes as a fresh sendMessage (push notification) NOT
|
|
30
|
+
* an edit-finalize — mirrors OpenClaw's materialize() pattern.
|
|
31
|
+
* 5. Supersession protection — when a new turn starts while a prior
|
|
32
|
+
* answer-lane edit is in flight, the late edit is identified as stale
|
|
33
|
+
* and orphaned (via generation counter), not applied to the new message.
|
|
34
|
+
*
|
|
35
|
+
* Key differences from the OpenClaw draft-stream.ts:
|
|
36
|
+
* - No grammy Bot dependency at this layer — callers inject typed send/edit
|
|
37
|
+
* callbacks so this module is fully testable without a real bot.
|
|
38
|
+
* - No finalizable-draft-lifecycle SDK — we implement the loop directly.
|
|
39
|
+
* - materialize() always sends a fresh message regardless of transport,
|
|
40
|
+
* to guarantee a push notification on turn completion.
|
|
41
|
+
*
|
|
42
|
+
* Draft-transport helpers (regex constants, shouldFallbackFromDraftTransport,
|
|
43
|
+
* allocateDraftId) live in draft-transport.ts and are re-exported here so
|
|
44
|
+
* existing callers that import from this module continue to work.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
export const MIN_INITIAL_CHARS = 50
|
|
48
|
+
export const DEFAULT_THROTTLE_MS = 1000
|
|
49
|
+
const TELEGRAM_MAX_CHARS = 4096
|
|
50
|
+
|
|
51
|
+
// Re-export shared constants so existing callers / tests keep working.
|
|
52
|
+
export const DRAFT_METHOD_UNAVAILABLE_RE = _DRAFT_METHOD_UNAVAILABLE_RE
|
|
53
|
+
export const DRAFT_CHAT_UNSUPPORTED_RE = _DRAFT_CHAT_UNSUPPORTED_RE
|
|
54
|
+
export { _shouldFallbackFromDraftTransport as shouldFallbackFromDraftTransport }
|
|
55
|
+
|
|
56
|
+
/** Called when a late sendMessage/edit resolves after a new turn has started. */
|
|
57
|
+
export type OnSupersededCallback = (params: {
|
|
58
|
+
messageId: number
|
|
59
|
+
textSnapshot: string
|
|
60
|
+
}) => void
|
|
61
|
+
|
|
62
|
+
export interface AnswerStreamConfig {
|
|
63
|
+
/** chatId for all API calls */
|
|
64
|
+
chatId: string
|
|
65
|
+
/** True if this is a DM — tries sendMessageDraft first */
|
|
66
|
+
isPrivateChat: boolean
|
|
67
|
+
/** Optional forum thread */
|
|
68
|
+
threadId?: number
|
|
69
|
+
/** Minimum chars before opening the answer lane. Default: MIN_INITIAL_CHARS */
|
|
70
|
+
minInitialChars?: number
|
|
71
|
+
/** Throttle window in ms. Default: DEFAULT_THROTTLE_MS */
|
|
72
|
+
throttleMs?: number
|
|
73
|
+
/** Optional quote-reply target for the initial sendMessage */
|
|
74
|
+
replyToMessageId?: number
|
|
75
|
+
|
|
76
|
+
// ── Transport callbacks ────────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* sendMessageDraft(chatId, draftId, text, params?). Optional — when absent,
|
|
79
|
+
* the answer stream falls back immediately to sendMessage+editMessageText.
|
|
80
|
+
*/
|
|
81
|
+
sendMessageDraft?: (
|
|
82
|
+
chatId: string,
|
|
83
|
+
draftId: number,
|
|
84
|
+
text: string,
|
|
85
|
+
params?: { message_thread_id?: number },
|
|
86
|
+
) => Promise<unknown>
|
|
87
|
+
sendMessage: (
|
|
88
|
+
chatId: string,
|
|
89
|
+
text: string,
|
|
90
|
+
params?: {
|
|
91
|
+
parse_mode?: 'HTML'
|
|
92
|
+
message_thread_id?: number
|
|
93
|
+
link_preview_options?: { is_disabled: boolean }
|
|
94
|
+
reply_parameters?: { message_id: number }
|
|
95
|
+
},
|
|
96
|
+
) => Promise<{ message_id: number }>
|
|
97
|
+
editMessageText: (
|
|
98
|
+
chatId: string,
|
|
99
|
+
messageId: number,
|
|
100
|
+
text: string,
|
|
101
|
+
params?: {
|
|
102
|
+
parse_mode?: 'HTML'
|
|
103
|
+
message_thread_id?: number
|
|
104
|
+
link_preview_options?: { is_disabled: boolean }
|
|
105
|
+
},
|
|
106
|
+
) => Promise<unknown>
|
|
107
|
+
deleteMessage?: (chatId: string, messageId: number) => Promise<unknown>
|
|
108
|
+
|
|
109
|
+
/** Called when a late edit/send resolves but this stream has been superseded. */
|
|
110
|
+
onSuperseded?: OnSupersededCallback
|
|
111
|
+
log?: (msg: string) => void
|
|
112
|
+
warn?: (msg: string) => void
|
|
113
|
+
/**
|
|
114
|
+
* Optional metric callback. Fires after each successful send/edit and on
|
|
115
|
+
* materialize. Injected by the gateway so tests can mock it with vi.fn().
|
|
116
|
+
* Acceptance #203: answer_lane_update / answer_lane_materialized events.
|
|
117
|
+
*/
|
|
118
|
+
onMetric?: (ev:
|
|
119
|
+
| { kind: 'answer_lane_update'; chatId: string; messageId: number | undefined; charCount: number; transport: 'draft' | 'message' | 'edit' }
|
|
120
|
+
| { kind: 'answer_lane_materialized'; chatId: string; messageId: number | undefined; suppressed?: boolean }
|
|
121
|
+
) => void
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* #646 — dedup hooks. Injected by the gateway so answer-stream materialize
|
|
125
|
+
* participates in the same dedup window as turn-flush and reply/stream_reply.
|
|
126
|
+
*
|
|
127
|
+
* checkDedup(text): returns true if the text was already sent recently for
|
|
128
|
+
* this chat (caller already knows chatId/threadId via closure). When true,
|
|
129
|
+
* materialize skips the send and returns undefined.
|
|
130
|
+
*
|
|
131
|
+
* recordDedup(text): called after a successful materialize send so subsequent
|
|
132
|
+
* turn-flush or reply tool calls with the same content get suppressed.
|
|
133
|
+
*
|
|
134
|
+
* Both callbacks are optional — when absent, the old behaviour is preserved.
|
|
135
|
+
*/
|
|
136
|
+
checkDedup?: (text: string) => boolean
|
|
137
|
+
recordDedup?: (text: string) => void
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* #648 — write answer-stream materializations to the SQLite history buffer
|
|
141
|
+
* so `mcp__switchroom-telegram__get_recent_messages` surfaces them. Without
|
|
142
|
+
* this, materialized messages were visible in Telegram but invisible to
|
|
143
|
+
* MCP forensics — that's the gap that let #646 slip past triage.
|
|
144
|
+
*
|
|
145
|
+
* Optional — when absent, behaviour is unchanged (no buffer write).
|
|
146
|
+
*/
|
|
147
|
+
recordOutbound?: (args: { messageId: number; text: string }) => void
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface AnswerStreamHandle {
|
|
151
|
+
/**
|
|
152
|
+
* Push a new full-text snapshot. Throttled to ~1 send/edit per throttleMs.
|
|
153
|
+
* No-op if minInitialChars hasn't been reached yet.
|
|
154
|
+
*/
|
|
155
|
+
update(text: string): void
|
|
156
|
+
/**
|
|
157
|
+
* Finalize: send the accumulated text as a fresh sendMessage for push
|
|
158
|
+
* notification. Returns the final message_id, or undefined if nothing was
|
|
159
|
+
* buffered. Idempotent after first call.
|
|
160
|
+
*/
|
|
161
|
+
materialize(): Promise<number | undefined>
|
|
162
|
+
/**
|
|
163
|
+
* Force-start a new generation: resets internal state so the next update
|
|
164
|
+
* creates a new message instead of editing. Use when a new turn starts
|
|
165
|
+
* while this stream is still in flight.
|
|
166
|
+
*/
|
|
167
|
+
forceNewMessage(): void
|
|
168
|
+
/** Current message_id if one has been sent, else undefined. */
|
|
169
|
+
messageId(): number | undefined
|
|
170
|
+
/** Stop the stream — cancels pending throttled edits. */
|
|
171
|
+
stop(): void
|
|
172
|
+
/**
|
|
173
|
+
* Stop the stream AND delete any preliminary message that was already sent.
|
|
174
|
+
* Used when the reply/stream_reply tool takes over as the authoritative
|
|
175
|
+
* answer surface: the answer-lane preview must be retracted so the user
|
|
176
|
+
* sees only one message (the canonical stream_reply output) rather than a
|
|
177
|
+
* raw-markdown duplicate followed by the properly-formatted reply.
|
|
178
|
+
*
|
|
179
|
+
* Best-effort: if deleteMessage is not wired or the API call fails, the
|
|
180
|
+
* preliminary message is left in place (same behaviour as before the fix).
|
|
181
|
+
* Resolves after the delete attempt (or immediately when no message exists).
|
|
182
|
+
*/
|
|
183
|
+
retract(): Promise<void>
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Draft-id allocation now lives in draft-transport.ts (shared with
|
|
187
|
+
// draft-stream.ts). Re-alias locally so the rest of this file is unchanged.
|
|
188
|
+
const allocateDraftId = _allocateDraftId
|
|
189
|
+
|
|
190
|
+
export function createAnswerStream(config: AnswerStreamConfig): AnswerStreamHandle {
|
|
191
|
+
const {
|
|
192
|
+
chatId,
|
|
193
|
+
isPrivateChat,
|
|
194
|
+
threadId,
|
|
195
|
+
minInitialChars = MIN_INITIAL_CHARS,
|
|
196
|
+
throttleMs = DEFAULT_THROTTLE_MS,
|
|
197
|
+
replyToMessageId,
|
|
198
|
+
sendMessageDraft: draftApi,
|
|
199
|
+
sendMessage,
|
|
200
|
+
editMessageText,
|
|
201
|
+
onSuperseded,
|
|
202
|
+
log,
|
|
203
|
+
warn,
|
|
204
|
+
onMetric,
|
|
205
|
+
checkDedup,
|
|
206
|
+
recordDedup,
|
|
207
|
+
recordOutbound,
|
|
208
|
+
} = config
|
|
209
|
+
|
|
210
|
+
const effectiveThrottle = Math.max(250, throttleMs)
|
|
211
|
+
|
|
212
|
+
// Draft transport is only used in DMs and only when the API method is available.
|
|
213
|
+
const preferDraft = isPrivateChat && draftApi != null
|
|
214
|
+
let usesDraftTransport = preferDraft
|
|
215
|
+
let draftId = preferDraft ? allocateDraftId() : undefined
|
|
216
|
+
|
|
217
|
+
// Stream state
|
|
218
|
+
let streamMsgId: number | undefined
|
|
219
|
+
let pendingText: string | null = null
|
|
220
|
+
let lastSentText = ''
|
|
221
|
+
let lastSentAt = 0
|
|
222
|
+
let inFlight: Promise<void> | null = null
|
|
223
|
+
let scheduledTimer: ReturnType<typeof setTimeout> | null = null
|
|
224
|
+
let stopped = false
|
|
225
|
+
let materialized = false
|
|
226
|
+
/** Generation counter for supersession detection. */
|
|
227
|
+
let generation = 0
|
|
228
|
+
|
|
229
|
+
function cancelScheduled(): void {
|
|
230
|
+
if (scheduledTimer != null) {
|
|
231
|
+
clearTimeout(scheduledTimer)
|
|
232
|
+
scheduledTimer = null
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function sendDraft(text: string): Promise<boolean> {
|
|
237
|
+
if (!draftApi || draftId == null) return false
|
|
238
|
+
try {
|
|
239
|
+
const params: { message_thread_id?: number } = {}
|
|
240
|
+
if (threadId != null) params.message_thread_id = threadId
|
|
241
|
+
await draftApi(chatId, draftId, text, Object.keys(params).length > 0 ? params : undefined)
|
|
242
|
+
onMetric?.({ kind: 'answer_lane_update', chatId, messageId: streamMsgId, charCount: text.length, transport: 'draft' })
|
|
243
|
+
return true
|
|
244
|
+
} catch (err) {
|
|
245
|
+
if (_shouldFallbackFromDraftTransport(err)) {
|
|
246
|
+
warn?.(
|
|
247
|
+
`answer-stream: sendMessageDraft rejected — falling back to sendMessage/editMessageText (${err instanceof Error ? err.message : String(err)})`,
|
|
248
|
+
)
|
|
249
|
+
usesDraftTransport = false
|
|
250
|
+
draftId = undefined
|
|
251
|
+
return false
|
|
252
|
+
}
|
|
253
|
+
throw err
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async function sendOrEdit(text: string, gen: number): Promise<void> {
|
|
258
|
+
if (stopped) return
|
|
259
|
+
const trimmed = text.trimEnd()
|
|
260
|
+
if (!trimmed || trimmed.length > TELEGRAM_MAX_CHARS) return
|
|
261
|
+
if (trimmed === lastSentText) return
|
|
262
|
+
|
|
263
|
+
const prevText = lastSentText
|
|
264
|
+
lastSentText = trimmed
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
if (usesDraftTransport) {
|
|
268
|
+
const ok = await sendDraft(trimmed)
|
|
269
|
+
if (!ok) {
|
|
270
|
+
// Draft failed with a permanent error → fell back to message transport
|
|
271
|
+
// Retry the same text via message transport
|
|
272
|
+
await sendOrEditViaMessage(trimmed, gen, prevText)
|
|
273
|
+
}
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
await sendOrEditViaMessage(trimmed, gen, prevText)
|
|
277
|
+
} catch (err) {
|
|
278
|
+
// Log but don't crash — transient errors are common
|
|
279
|
+
warn?.(`answer-stream: send/edit failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
280
|
+
// Restore so next iteration retries
|
|
281
|
+
lastSentText = prevText
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function sendOrEditViaMessage(trimmed: string, gen: number, prevText: string): Promise<void> {
|
|
286
|
+
if (typeof streamMsgId === 'number') {
|
|
287
|
+
// Edit existing message
|
|
288
|
+
const editParams: Parameters<typeof editMessageText>[3] = {
|
|
289
|
+
parse_mode: 'HTML',
|
|
290
|
+
link_preview_options: { is_disabled: true },
|
|
291
|
+
}
|
|
292
|
+
if (threadId != null) editParams.message_thread_id = threadId
|
|
293
|
+
try {
|
|
294
|
+
await editMessageText(chatId, streamMsgId, trimmed, editParams)
|
|
295
|
+
onMetric?.({ kind: 'answer_lane_update', chatId, messageId: streamMsgId, charCount: trimmed.length, transport: 'edit' })
|
|
296
|
+
} catch (err) {
|
|
297
|
+
const msg = err instanceof Error ? err.message : String(err)
|
|
298
|
+
if (/message is not modified/i.test(msg)) {
|
|
299
|
+
// Not an error — identical text
|
|
300
|
+
return
|
|
301
|
+
}
|
|
302
|
+
if (/message to edit not found|MESSAGE_ID_INVALID/i.test(msg)) {
|
|
303
|
+
// Message deleted — re-send from scratch next cycle
|
|
304
|
+
log?.(`answer-stream: message not found (id=${streamMsgId}), will re-send`)
|
|
305
|
+
streamMsgId = undefined
|
|
306
|
+
lastSentText = prevText
|
|
307
|
+
return
|
|
308
|
+
}
|
|
309
|
+
throw err
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
// First send — capture message_id; check generation for supersession
|
|
313
|
+
const sendParams: Parameters<typeof sendMessage>[2] = {
|
|
314
|
+
parse_mode: 'HTML',
|
|
315
|
+
link_preview_options: { is_disabled: true },
|
|
316
|
+
}
|
|
317
|
+
if (threadId != null) sendParams.message_thread_id = threadId
|
|
318
|
+
if (replyToMessageId != null) sendParams.reply_parameters = { message_id: replyToMessageId }
|
|
319
|
+
const sent = await sendMessage(chatId, trimmed, sendParams)
|
|
320
|
+
const sentId = sent?.message_id
|
|
321
|
+
if (typeof sentId !== 'number' || !Number.isFinite(sentId)) {
|
|
322
|
+
warn?.('answer-stream: sendMessage returned no message_id')
|
|
323
|
+
return
|
|
324
|
+
}
|
|
325
|
+
if (gen !== generation) {
|
|
326
|
+
// Superseded — this send resolved after forceNewMessage() was called
|
|
327
|
+
onSuperseded?.({ messageId: sentId, textSnapshot: trimmed })
|
|
328
|
+
log?.(`answer-stream: superseded send (messageId=${sentId}, gen=${gen} vs ${generation})`)
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
streamMsgId = sentId
|
|
332
|
+
log?.(`answer-stream: sent (id=${sentId})`)
|
|
333
|
+
onMetric?.({ kind: 'answer_lane_update', chatId, messageId: streamMsgId, charCount: trimmed.length, transport: 'message' })
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
async function flushLoop(): Promise<void> {
|
|
338
|
+
while (pendingText != null && !stopped) {
|
|
339
|
+
const text = pendingText
|
|
340
|
+
pendingText = null
|
|
341
|
+
const gen = generation
|
|
342
|
+
await sendOrEdit(text, gen)
|
|
343
|
+
lastSentAt = Date.now()
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function schedule(): void {
|
|
348
|
+
if (scheduledTimer != null || stopped) return
|
|
349
|
+
const sinceLast = Date.now() - lastSentAt
|
|
350
|
+
const delay = Math.max(0, effectiveThrottle - sinceLast)
|
|
351
|
+
scheduledTimer = setTimeout(() => {
|
|
352
|
+
scheduledTimer = null
|
|
353
|
+
if (inFlight) return
|
|
354
|
+
inFlight = flushLoop().finally(() => {
|
|
355
|
+
inFlight = null
|
|
356
|
+
})
|
|
357
|
+
}, delay)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
update(text: string): void {
|
|
362
|
+
if (stopped || materialized) return
|
|
363
|
+
const trimmed = text.trimEnd()
|
|
364
|
+
if (!trimmed) return
|
|
365
|
+
|
|
366
|
+
// minInitialChars gate: don't open the lane yet
|
|
367
|
+
if (streamMsgId == null && !usesDraftTransport && trimmed.length < minInitialChars) return
|
|
368
|
+
|
|
369
|
+
pendingText = trimmed
|
|
370
|
+
|
|
371
|
+
if (inFlight == null) {
|
|
372
|
+
const sinceLast = Date.now() - lastSentAt
|
|
373
|
+
if (sinceLast >= effectiveThrottle) {
|
|
374
|
+
inFlight = flushLoop().finally(() => {
|
|
375
|
+
inFlight = null
|
|
376
|
+
})
|
|
377
|
+
} else {
|
|
378
|
+
schedule()
|
|
379
|
+
}
|
|
380
|
+
} else {
|
|
381
|
+
// Chain off current in-flight to drain the new pendingText
|
|
382
|
+
inFlight.then(() => {
|
|
383
|
+
if (stopped || pendingText == null) return
|
|
384
|
+
if (inFlight != null) return
|
|
385
|
+
const sinceLast = Date.now() - lastSentAt
|
|
386
|
+
if (sinceLast >= effectiveThrottle) {
|
|
387
|
+
inFlight = flushLoop().finally(() => {
|
|
388
|
+
inFlight = null
|
|
389
|
+
})
|
|
390
|
+
} else {
|
|
391
|
+
schedule()
|
|
392
|
+
}
|
|
393
|
+
}).catch(() => {})
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
async materialize(): Promise<number | undefined> {
|
|
398
|
+
if (materialized) return streamMsgId
|
|
399
|
+
materialized = true
|
|
400
|
+
stopped = true
|
|
401
|
+
cancelScheduled()
|
|
402
|
+
|
|
403
|
+
// Wait for any in-flight edit to settle
|
|
404
|
+
if (inFlight) {
|
|
405
|
+
try { await inFlight } catch { /* ignore */ }
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Clear draft so Telegram input area doesn't show stale text
|
|
409
|
+
if (usesDraftTransport && draftApi != null && draftId != null) {
|
|
410
|
+
try {
|
|
411
|
+
const clearParams: { message_thread_id?: number } = {}
|
|
412
|
+
if (threadId != null) clearParams.message_thread_id = threadId
|
|
413
|
+
await draftApi(
|
|
414
|
+
chatId,
|
|
415
|
+
draftId,
|
|
416
|
+
'',
|
|
417
|
+
Object.keys(clearParams).length > 0 ? clearParams : undefined,
|
|
418
|
+
)
|
|
419
|
+
} catch {
|
|
420
|
+
// Best-effort cleanup
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// The text we want to materialize. Prefer pendingText (most recent
|
|
425
|
+
// snapshot from the model) over lastSentText (what last reached the
|
|
426
|
+
// wire). They usually match, but if a buffered update was scheduled
|
|
427
|
+
// and not yet sent when materialize() was called, pendingText holds
|
|
428
|
+
// the freshest content.
|
|
429
|
+
const textToSend = (pendingText || lastSentText).trimEnd()
|
|
430
|
+
if (!textToSend) {
|
|
431
|
+
log?.('answer-stream: materialize — nothing to send')
|
|
432
|
+
return undefined
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Telegram caps a single message at 4096 chars. The streaming path
|
|
436
|
+
// already guards on this in sendOrEdit; materialize must too, or
|
|
437
|
+
// long answers silently drop the final push notification (Telegram
|
|
438
|
+
// returns 400, the catch swallows). Per the JTBD anti-pattern
|
|
439
|
+
// "silent failure of any kind", warn and bail explicitly so the
|
|
440
|
+
// operator can correlate.
|
|
441
|
+
if (textToSend.length > TELEGRAM_MAX_CHARS) {
|
|
442
|
+
warn?.(
|
|
443
|
+
`answer-stream: materialize — text exceeds ${TELEGRAM_MAX_CHARS} chars (got ${textToSend.length}); skipping. ` +
|
|
444
|
+
`The reply path should have already delivered chunked output; this is a defensive guard.`,
|
|
445
|
+
)
|
|
446
|
+
return undefined
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Silent-marker guard: if the whole body is NO_REPLY / HEARTBEAT_OK
|
|
450
|
+
// (exact-match, with trailing-punctuation tolerance), suppress outbound
|
|
451
|
+
// and log — mirrors the suppression in server.ts and turn-flush-safety.ts.
|
|
452
|
+
if (isSilentFlushMarker(textToSend)) {
|
|
453
|
+
// Normalise the same way isSilentFlushMarker does so log searches for
|
|
454
|
+
// `marker=NO_REPLY` match both `NO_REPLY` and `NO_REPLY.` inputs.
|
|
455
|
+
let marker = textToSend.trim().toUpperCase()
|
|
456
|
+
if (marker.length > 0 && /\W$/.test(marker)) marker = marker.slice(0, -1)
|
|
457
|
+
log?.(
|
|
458
|
+
`telegram gateway: answer-stream: silent-marker-suppressed marker=${marker} chatId=${chatId}`,
|
|
459
|
+
)
|
|
460
|
+
return undefined
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// #646 — dedup check: was this content already sent via turn-flush
|
|
464
|
+
// (or another path) within the dedup TTL? If so, skip the send to
|
|
465
|
+
// avoid a duplicate push notification. We still emit the metric
|
|
466
|
+
// (with suppressed=true) so observability tooling can track the
|
|
467
|
+
// rate of suppressed materializations.
|
|
468
|
+
if (checkDedup != null && checkDedup(textToSend)) {
|
|
469
|
+
log?.(
|
|
470
|
+
`telegram gateway: answer-stream: materialize-dedup-suppressed chatId=${chatId} — turn-flush already sent this content`,
|
|
471
|
+
)
|
|
472
|
+
onMetric?.({ kind: 'answer_lane_materialized', chatId, messageId: undefined, suppressed: true })
|
|
473
|
+
return undefined
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Always send a fresh message for push notification
|
|
477
|
+
const sendParams: Parameters<typeof sendMessage>[2] = {
|
|
478
|
+
parse_mode: 'HTML',
|
|
479
|
+
link_preview_options: { is_disabled: true },
|
|
480
|
+
}
|
|
481
|
+
if (threadId != null) sendParams.message_thread_id = threadId
|
|
482
|
+
// Don't quote-reply on materialize — the draft stream already established
|
|
483
|
+
// the reply context visually. A second reply_parameters would create a
|
|
484
|
+
// nested quote that looks wrong.
|
|
485
|
+
|
|
486
|
+
try {
|
|
487
|
+
const sent = await sendMessage(chatId, textToSend, sendParams)
|
|
488
|
+
const sentId = sent?.message_id
|
|
489
|
+
if (typeof sentId === 'number' && Number.isFinite(sentId)) {
|
|
490
|
+
streamMsgId = sentId
|
|
491
|
+
log?.(`answer-stream: materialized (id=${sentId})`)
|
|
492
|
+
// #646 — record in dedup cache so a late-arriving turn-flush
|
|
493
|
+
// (or a second materialize on reconnect) with identical content
|
|
494
|
+
// gets suppressed. Mirrors the record call in gateway.ts
|
|
495
|
+
// turn-flush at line ~3795.
|
|
496
|
+
recordDedup?.(textToSend)
|
|
497
|
+
// #648 — mirror turn-flush's recordOutbound so this send shows up
|
|
498
|
+
// in get_recent_messages / SQLite history.
|
|
499
|
+
recordOutbound?.({ messageId: sentId, text: textToSend })
|
|
500
|
+
onMetric?.({ kind: 'answer_lane_materialized', chatId, messageId: streamMsgId })
|
|
501
|
+
return sentId
|
|
502
|
+
}
|
|
503
|
+
} catch (err) {
|
|
504
|
+
warn?.(`answer-stream: materialize send failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
505
|
+
}
|
|
506
|
+
return undefined
|
|
507
|
+
},
|
|
508
|
+
|
|
509
|
+
forceNewMessage(): void {
|
|
510
|
+
cancelScheduled()
|
|
511
|
+
generation += 1
|
|
512
|
+
streamMsgId = undefined
|
|
513
|
+
lastSentText = ''
|
|
514
|
+
lastSentAt = 0
|
|
515
|
+
pendingText = null
|
|
516
|
+
stopped = false
|
|
517
|
+
materialized = false
|
|
518
|
+
if (usesDraftTransport) {
|
|
519
|
+
draftId = allocateDraftId()
|
|
520
|
+
}
|
|
521
|
+
log?.(`answer-stream: forceNewMessage (gen=${generation})`)
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
messageId(): number | undefined {
|
|
525
|
+
return streamMsgId
|
|
526
|
+
},
|
|
527
|
+
|
|
528
|
+
stop(): void {
|
|
529
|
+
stopped = true
|
|
530
|
+
cancelScheduled()
|
|
531
|
+
},
|
|
532
|
+
|
|
533
|
+
async retract(): Promise<void> {
|
|
534
|
+
// Stop immediately so no further edits or sends go out.
|
|
535
|
+
stopped = true
|
|
536
|
+
cancelScheduled()
|
|
537
|
+
// Wait for any in-flight operation to settle so we don't race a
|
|
538
|
+
// concurrent sendMessage that would leave a dangling message.
|
|
539
|
+
if (inFlight) {
|
|
540
|
+
try { await inFlight } catch { /* ignore */ }
|
|
541
|
+
}
|
|
542
|
+
// Delete the preliminary message if one was sent and deleteMessage
|
|
543
|
+
// is wired. Best-effort: failures are logged but not re-thrown.
|
|
544
|
+
const msgId = streamMsgId
|
|
545
|
+
if (msgId != null && config.deleteMessage != null) {
|
|
546
|
+
try {
|
|
547
|
+
await config.deleteMessage(chatId, msgId)
|
|
548
|
+
log?.(`answer-stream: retracted preliminary message (id=${msgId})`)
|
|
549
|
+
} catch (err) {
|
|
550
|
+
warn?.(
|
|
551
|
+
`answer-stream: retract deleteMessage failed (id=${msgId}): ${
|
|
552
|
+
err instanceof Error ? err.message : String(err)
|
|
553
|
+
}`,
|
|
554
|
+
)
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/** Reset the draft-id counter for tests. */
|
|
562
|
+
/** Reset the shared draft-id counter for tests. Delegates to draft-transport.ts. */
|
|
563
|
+
export function __resetDraftIdForTests(): void {
|
|
564
|
+
_resetDraftIdForTests()
|
|
565
|
+
}
|