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,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram-HTML sanitizer.
|
|
3
|
+
*
|
|
4
|
+
* Telegram's HTML parser is strict: it accepts only a small whitelist of
|
|
5
|
+
* tags (b/strong, i/em, u/ins, s/strike/del, code, pre, a, tg-spoiler,
|
|
6
|
+
* span class="tg-spoiler", tg-emoji, blockquote) and rejects the entire
|
|
7
|
+
* message with `400 Bad Request: can't parse entities` when it encounters
|
|
8
|
+
* an unknown tag, an unbalanced tag, or a stray `<` that doesn't open a
|
|
9
|
+
* known tag.
|
|
10
|
+
*
|
|
11
|
+
* `markdownToHtml()` already produces well-formed HTML for content the
|
|
12
|
+
* model wrote *as markdown*. This module is the second line of defence
|
|
13
|
+
* for content the model wrote *as raw HTML* (or as a mix that produces
|
|
14
|
+
* malformed HTML after rendering): we run the rendered string through a
|
|
15
|
+
* pure-text scanner that:
|
|
16
|
+
*
|
|
17
|
+
* 1. Escapes any `<` / `>` that doesn't open or close a whitelisted
|
|
18
|
+
* tag (e.g. `<frobnicate>` → `<frobnicate>`,
|
|
19
|
+
* `1 < 2 < 3` → `1 < 2 < 3`).
|
|
20
|
+
* 2. Escapes attributes that aren't on the small per-tag allowlist
|
|
21
|
+
* (only `<a href>`, `<code class>`, `<span class="tg-spoiler">`,
|
|
22
|
+
* `<tg-emoji emoji-id>`, `<blockquote expandable>` are accepted —
|
|
23
|
+
* everything else gets stripped from the tag).
|
|
24
|
+
* 3. Auto-closes any tag opened but never closed (so an "unclosed
|
|
25
|
+
* `<b>` at end of message" doesn't trip Telegram's parser).
|
|
26
|
+
* 4. Drops any unmatched closing tag (e.g. `</foo>` without an opener).
|
|
27
|
+
*
|
|
28
|
+
* The sanitizer is conservative: when in doubt, escape. The output is
|
|
29
|
+
* guaranteed to round-trip through Telegram's HTML parser without a
|
|
30
|
+
* `can't parse entities` 400 — at the cost of some false positives where
|
|
31
|
+
* raw `<` characters inside model prose end up as `<` (which is the
|
|
32
|
+
* correct Telegram-HTML behaviour anyway).
|
|
33
|
+
*
|
|
34
|
+
* Idempotent: sanitize(sanitize(x)) === sanitize(x).
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/** Telegram's parse_mode=HTML allowed tag names. */
|
|
38
|
+
const ALLOWED_TAGS = new Set([
|
|
39
|
+
'b', 'strong',
|
|
40
|
+
'i', 'em',
|
|
41
|
+
'u', 'ins',
|
|
42
|
+
's', 'strike', 'del',
|
|
43
|
+
'a',
|
|
44
|
+
'code',
|
|
45
|
+
'pre',
|
|
46
|
+
'span',
|
|
47
|
+
'tg-spoiler',
|
|
48
|
+
'tg-emoji',
|
|
49
|
+
'blockquote',
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Per-tag attribute allowlist. Keys are tag names; values are the set of
|
|
54
|
+
* attribute names that survive the sanitizer. Anything not listed is
|
|
55
|
+
* silently dropped from the opening tag.
|
|
56
|
+
*/
|
|
57
|
+
const ALLOWED_ATTRS: Record<string, Set<string>> = {
|
|
58
|
+
a: new Set(['href']),
|
|
59
|
+
code: new Set(['class']),
|
|
60
|
+
span: new Set(['class']),
|
|
61
|
+
'tg-emoji': new Set(['emoji-id']),
|
|
62
|
+
blockquote: new Set(['expandable']),
|
|
63
|
+
pre: new Set(['language']),
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Allowed schemes for `<a href>` — block javascript:, data:, etc. */
|
|
67
|
+
const ALLOWED_HREF_SCHEMES = /^(?:https?|mailto|tel|tg):/i
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Strip every `<…>` from a string, escaping the `<` and `>`. Used as the
|
|
71
|
+
* fallback when the input genuinely cannot be made HTML-safe.
|
|
72
|
+
*/
|
|
73
|
+
export function escapeAllHtml(text: string): string {
|
|
74
|
+
return text
|
|
75
|
+
.replace(/&/g, '&')
|
|
76
|
+
.replace(/</g, '<')
|
|
77
|
+
.replace(/>/g, '>')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Sanitize a string of Telegram HTML so it cannot trip the
|
|
82
|
+
* `can't parse entities` 400. See module docstring for the rules.
|
|
83
|
+
*
|
|
84
|
+
* @param input - the rendered HTML (post markdownToHtml).
|
|
85
|
+
* @returns the sanitized HTML, guaranteed parse-mode=HTML safe.
|
|
86
|
+
*/
|
|
87
|
+
export function sanitizeTelegramHtml(input: string): string {
|
|
88
|
+
// Walk the input character by character. When we see `<`, try to match
|
|
89
|
+
// a tag against our whitelist. If it matches, emit a normalized form;
|
|
90
|
+
// otherwise escape the `<` and continue.
|
|
91
|
+
//
|
|
92
|
+
// Tag regex: opening tag name, optional attributes (anything up to
|
|
93
|
+
// the next `>` that isn't inside a quoted string), and the closing
|
|
94
|
+
// `>`. We use a small hand-rolled parser rather than a generic regex
|
|
95
|
+
// because we need to validate attributes per-tag.
|
|
96
|
+
const out: string[] = []
|
|
97
|
+
const stack: string[] = [] // names of open tags, oldest-first
|
|
98
|
+
let i = 0
|
|
99
|
+
const len = input.length
|
|
100
|
+
|
|
101
|
+
while (i < len) {
|
|
102
|
+
const ch = input[i]
|
|
103
|
+
|
|
104
|
+
if (ch === '&') {
|
|
105
|
+
// Pass through known entities verbatim; escape bare `&`.
|
|
106
|
+
// A "known entity" is `&` followed by [a-z]+; or `&#` followed by digits;
|
|
107
|
+
// both terminated by `;` within ~10 chars.
|
|
108
|
+
const m = /^&(?:#\d+|#x[0-9a-f]+|[a-z]+);/i.exec(input.slice(i, i + 12))
|
|
109
|
+
if (m) {
|
|
110
|
+
out.push(m[0])
|
|
111
|
+
i += m[0].length
|
|
112
|
+
} else {
|
|
113
|
+
out.push('&')
|
|
114
|
+
i++
|
|
115
|
+
}
|
|
116
|
+
continue
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (ch !== '<') {
|
|
120
|
+
out.push(ch)
|
|
121
|
+
i++
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// We're at a `<`. Try to parse a tag.
|
|
126
|
+
const tagMatch = /^<\s*(\/?)\s*([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/.exec(input.slice(i))
|
|
127
|
+
if (!tagMatch) {
|
|
128
|
+
// Stray `<` — escape it.
|
|
129
|
+
out.push('<')
|
|
130
|
+
i++
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
const isClose = tagMatch[1] === '/'
|
|
134
|
+
const tagName = tagMatch[2].toLowerCase()
|
|
135
|
+
const attrText = tagMatch[3]
|
|
136
|
+
|
|
137
|
+
if (!ALLOWED_TAGS.has(tagName)) {
|
|
138
|
+
// Unknown tag — escape the whole `<…>` literal.
|
|
139
|
+
out.push(escapeAllHtml(tagMatch[0]))
|
|
140
|
+
i += tagMatch[0].length
|
|
141
|
+
continue
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (isClose) {
|
|
145
|
+
// Closing tag: only emit if it matches the most recently opened
|
|
146
|
+
// tag of the same name. If the stack contains a matching opener
|
|
147
|
+
// earlier, close out everything above it (auto-close any
|
|
148
|
+
// unbalanced inner tags). If there's no matching opener at all,
|
|
149
|
+
// drop the closing tag silently.
|
|
150
|
+
const idx = stack.lastIndexOf(tagName)
|
|
151
|
+
if (idx === -1) {
|
|
152
|
+
// No matching opener — drop the close tag.
|
|
153
|
+
i += tagMatch[0].length
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
// Auto-close anything above the matching opener.
|
|
157
|
+
while (stack.length > idx + 1) {
|
|
158
|
+
const top = stack.pop()!
|
|
159
|
+
out.push(`</${top}>`)
|
|
160
|
+
}
|
|
161
|
+
stack.pop()
|
|
162
|
+
out.push(`</${tagName}>`)
|
|
163
|
+
i += tagMatch[0].length
|
|
164
|
+
continue
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Opening tag: filter attributes.
|
|
168
|
+
const cleanAttrs = sanitizeAttrs(tagName, attrText)
|
|
169
|
+
out.push(`<${tagName}${cleanAttrs}>`)
|
|
170
|
+
// Self-closing void tags? Telegram has none — every allowed tag is
|
|
171
|
+
// a container. Push onto stack so we can auto-close later.
|
|
172
|
+
stack.push(tagName)
|
|
173
|
+
i += tagMatch[0].length
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Auto-close any unclosed tags so the output is balanced.
|
|
177
|
+
while (stack.length > 0) {
|
|
178
|
+
const top = stack.pop()!
|
|
179
|
+
out.push(`</${top}>`)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return out.join('')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Filter the attribute string of an opening tag against the per-tag
|
|
187
|
+
* allowlist. Returns the cleaned attribute string with a leading space
|
|
188
|
+
* (or empty string when no attributes survive).
|
|
189
|
+
*/
|
|
190
|
+
function sanitizeAttrs(tagName: string, attrText: string): string {
|
|
191
|
+
const allowed = ALLOWED_ATTRS[tagName]
|
|
192
|
+
if (!allowed || allowed.size === 0) return ''
|
|
193
|
+
|
|
194
|
+
// Match attribute name=value or bare name. Value may be double-quoted,
|
|
195
|
+
// single-quoted, or unquoted.
|
|
196
|
+
const attrRe = /([a-zA-Z_][a-zA-Z0-9_-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g
|
|
197
|
+
const kept: string[] = []
|
|
198
|
+
let m: RegExpExecArray | null
|
|
199
|
+
while ((m = attrRe.exec(attrText)) != null) {
|
|
200
|
+
const name = m[1].toLowerCase()
|
|
201
|
+
if (!allowed.has(name)) continue
|
|
202
|
+
const rawValue = m[2] ?? m[3] ?? m[4] ?? ''
|
|
203
|
+
|
|
204
|
+
// Per-attribute value sanitization.
|
|
205
|
+
if (tagName === 'a' && name === 'href') {
|
|
206
|
+
const trimmed = rawValue.trim()
|
|
207
|
+
if (!ALLOWED_HREF_SCHEMES.test(trimmed)) continue
|
|
208
|
+
kept.push(`href="${escapeAttrValue(trimmed)}"`)
|
|
209
|
+
continue
|
|
210
|
+
}
|
|
211
|
+
if (rawValue.length === 0) {
|
|
212
|
+
// Bare attribute like `<blockquote expandable>`.
|
|
213
|
+
kept.push(name)
|
|
214
|
+
continue
|
|
215
|
+
}
|
|
216
|
+
kept.push(`${name}="${escapeAttrValue(rawValue)}"`)
|
|
217
|
+
}
|
|
218
|
+
return kept.length > 0 ? ' ' + kept.join(' ') : ''
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function escapeAttrValue(v: string): string {
|
|
222
|
+
return v
|
|
223
|
+
.replace(/&/g, '&')
|
|
224
|
+
.replace(/"/g, '"')
|
|
225
|
+
.replace(/</g, '<')
|
|
226
|
+
.replace(/>/g, '>')
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Convert a rendered HTML body to a plain-text fallback. Used when
|
|
231
|
+
* Telegram still rejects the (presumably-already-sanitized) HTML — we
|
|
232
|
+
* strip every tag and unescape entities so the message lands as text
|
|
233
|
+
* instead of disappearing.
|
|
234
|
+
*/
|
|
235
|
+
export function htmlToPlainText(html: string): string {
|
|
236
|
+
return html
|
|
237
|
+
// Drop tags entirely.
|
|
238
|
+
.replace(/<\/?[a-zA-Z][a-zA-Z0-9-]*\b[^>]*>/g, '')
|
|
239
|
+
// Unescape the four entities the encoder produces.
|
|
240
|
+
.replace(/</g, '<')
|
|
241
|
+
.replace(/>/g, '>')
|
|
242
|
+
.replace(/"/g, '"')
|
|
243
|
+
.replace(/&/g, '&')
|
|
244
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure renderer for the idle/active footer shown on each agent's Telegram topic.
|
|
3
|
+
*
|
|
4
|
+
* No DB, no IO, no time-source coupling. Both `rows` and `now` are
|
|
5
|
+
* caller-supplied so the function is trivially testable.
|
|
6
|
+
*
|
|
7
|
+
* ## "Most recent" definition
|
|
8
|
+
* We pick the row with the greatest `startedAt` value. Using `startedAt` (rather
|
|
9
|
+
* than `endedAt ?? startedAt`) keeps the semantics simple: the most recently
|
|
10
|
+
* *started* turn is the one that best reflects the agent's current engagement.
|
|
11
|
+
* A turn that finished long ago but whose `endedAt` happens to be later than a
|
|
12
|
+
* newer turn's `startedAt` would give a misleading "working since" signal; that
|
|
13
|
+
* edge case can't occur in practice (turns are sequential per chat), but the
|
|
14
|
+
* comment documents the deliberate choice.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface TurnRow {
|
|
18
|
+
turnKey: string;
|
|
19
|
+
chatId: string;
|
|
20
|
+
startedAt: number; // ms epoch
|
|
21
|
+
endedAt: number | null; // ms epoch, or null if the turn is still running
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Format a past timestamp as a human-readable "ago" string.
|
|
26
|
+
*
|
|
27
|
+
* <60 s → "<1m ago"
|
|
28
|
+
* 60 s..59 min → "Nm ago"
|
|
29
|
+
* 60 min..23 h → "Nh ago"
|
|
30
|
+
* >=24 h → "Nd ago"
|
|
31
|
+
*/
|
|
32
|
+
function formatAgo(ts: number, now: number): string {
|
|
33
|
+
const diffMs = now - ts;
|
|
34
|
+
const diffSec = diffMs / 1000;
|
|
35
|
+
if (diffSec < 60) return "<1m ago";
|
|
36
|
+
const diffMin = Math.floor(diffMs / 60_000);
|
|
37
|
+
if (diffMin < 60) return `${diffMin}m ago`;
|
|
38
|
+
const diffHr = Math.floor(diffMs / 3_600_000);
|
|
39
|
+
if (diffHr < 24) return `${diffHr}h ago`;
|
|
40
|
+
const diffDay = Math.floor(diffMs / 86_400_000);
|
|
41
|
+
return `${diffDay}d ago`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Format an array of turn rows into a footer string for the agent's topic.
|
|
46
|
+
*
|
|
47
|
+
* States:
|
|
48
|
+
* - No rows → "🟡 quiet · no turns yet"
|
|
49
|
+
* - Latest turn running → "⚙️ working since <Nm ago>" (uses startedAt)
|
|
50
|
+
* - Latest turn ended → "🟢 idle · last reply <Nm ago>" (uses endedAt)
|
|
51
|
+
*/
|
|
52
|
+
export function formatIdleFooter(rows: ReadonlyArray<TurnRow>, now: number): string {
|
|
53
|
+
if (rows.length === 0) {
|
|
54
|
+
return "🟡 quiet · no turns yet";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Pick most recent by MAX(startedAt).
|
|
58
|
+
const latest = rows.reduce((best, row) => (row.startedAt > best.startedAt ? row : best));
|
|
59
|
+
|
|
60
|
+
if (latest.endedAt == null) {
|
|
61
|
+
return `⚙️ working since ${formatAgo(latest.startedAt, now)}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return `🟢 idle · last reply ${formatAgo(latest.endedAt, now)}`;
|
|
65
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-emitted inline-keyboard callback routing (#271).
|
|
3
|
+
*
|
|
4
|
+
* Agents emit `inline_keyboard` buttons via the `reply` / `stream_reply`
|
|
5
|
+
* MCP tools. URL buttons need no routing — Telegram opens them in the
|
|
6
|
+
* user's browser. callback_data buttons are different: the user's tap
|
|
7
|
+
* arrives as a `callback_query` update on the gateway's bot, and we
|
|
8
|
+
* need to deliver it back to the agent as an inbound channel event.
|
|
9
|
+
*
|
|
10
|
+
* Wire format
|
|
11
|
+
* ───────────
|
|
12
|
+
* The gateway namespaces agent-emitted callback_data with an `agent:`
|
|
13
|
+
* prefix BEFORE sending to Telegram. Two reasons:
|
|
14
|
+
*
|
|
15
|
+
* 1. The existing callback_query dispatcher in gateway.ts routes by
|
|
16
|
+
* data prefix (`auth:`, `op:`, `vd:`, `vg:`, `aq:`, `perm:`).
|
|
17
|
+
* Any unprefixed data falls through to "ack-and-ignore". Agents
|
|
18
|
+
* could otherwise collide with infrastructure prefixes — `auth:`
|
|
19
|
+
* from an agent would silently invoke the auth dashboard handler.
|
|
20
|
+
*
|
|
21
|
+
* 2. Round-tripping. On callback_query receipt the gateway sees the
|
|
22
|
+
* `agent:` prefix, strips it, and forwards the raw data the agent
|
|
23
|
+
* originally supplied. Agent code only ever sees its own opaque
|
|
24
|
+
* payload — no leaky abstraction.
|
|
25
|
+
*
|
|
26
|
+
* Effective payload budget: 64 bytes (Telegram limit) − 6 bytes
|
|
27
|
+
* (`agent:` prefix) = 58 bytes for agent-supplied data. This is
|
|
28
|
+
* documented in the MCP tool schema.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import {
|
|
32
|
+
validateInlineKeyboard,
|
|
33
|
+
type AnyButton,
|
|
34
|
+
type ButtonValidationError,
|
|
35
|
+
} from './telegram-button-constraints.js'
|
|
36
|
+
|
|
37
|
+
/** Prefix used to namespace agent-emitted callback_data on the wire. */
|
|
38
|
+
export const AGENT_CALLBACK_PREFIX = 'agent:'
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Maximum bytes available to the agent for callback_data payloads.
|
|
42
|
+
* Telegram's hard limit is 64 bytes; the gateway reserves 6 bytes for
|
|
43
|
+
* the `agent:` prefix.
|
|
44
|
+
*/
|
|
45
|
+
export const AGENT_CALLBACK_DATA_MAX = 64 - AGENT_CALLBACK_PREFIX.length
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Per-button agent-supplied metadata that controls post-tap UX (#710).
|
|
49
|
+
* These fields are stripped before the keyboard is sent to Telegram —
|
|
50
|
+
* they are NOT part of the Bot API. The gateway extracts and stores
|
|
51
|
+
* them via {@link extractAgentButtonMeta} so the callback handler can
|
|
52
|
+
* honor them when the user taps.
|
|
53
|
+
*/
|
|
54
|
+
export interface AgentButtonMeta {
|
|
55
|
+
/** Toast text shown via answerCallbackQuery on tap. Default `'✓ received'`. */
|
|
56
|
+
ack_text?: string
|
|
57
|
+
/**
|
|
58
|
+
* When false, the button keyboard is preserved after tap (re-tappable).
|
|
59
|
+
* When true (default), tapping ANY single_use button on the message
|
|
60
|
+
* removes the entire keyboard to prevent double-fire.
|
|
61
|
+
*/
|
|
62
|
+
single_use?: boolean
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Fields the gateway adds to button objects — not valid Telegram API fields. */
|
|
66
|
+
const AGENT_META_FIELDS: ReadonlyArray<keyof AgentButtonMeta> = ['ack_text', 'single_use']
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Wrap every callback_data field in a 2D inline-keyboard with the
|
|
70
|
+
* gateway's `agent:` namespace prefix. URL-only buttons pass through
|
|
71
|
+
* unchanged. Returns a fresh array — does not mutate the input.
|
|
72
|
+
*
|
|
73
|
+
* Also strips agent-only meta fields (`ack_text`, `single_use`) so they
|
|
74
|
+
* don't leak into the Telegram API request. Use
|
|
75
|
+
* {@link extractAgentButtonMeta} on the raw keyboard BEFORE wrapping to
|
|
76
|
+
* recover those fields for the callback handler.
|
|
77
|
+
*
|
|
78
|
+
* Throws when an agent-supplied callback_data exceeds the effective
|
|
79
|
+
* 58-byte budget (so the operator sees a clear error, not a silent
|
|
80
|
+
* Telegram 400 BUTTON_DATA_INVALID at send time).
|
|
81
|
+
*/
|
|
82
|
+
export function wrapAgentCallbacks(keyboard: AnyButton[][]): AnyButton[][] {
|
|
83
|
+
return keyboard.map((row) =>
|
|
84
|
+
row.map((btn) => {
|
|
85
|
+
const cleaned: AnyButton = { ...btn }
|
|
86
|
+
for (const f of AGENT_META_FIELDS) delete cleaned[f]
|
|
87
|
+
if (typeof btn.callback_data !== 'string') return cleaned
|
|
88
|
+
const raw = btn.callback_data
|
|
89
|
+
const rawBytes = new TextEncoder().encode(raw).byteLength
|
|
90
|
+
if (rawBytes > AGENT_CALLBACK_DATA_MAX) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`inline_keyboard.callback_data exceeds ${AGENT_CALLBACK_DATA_MAX}-byte agent budget ` +
|
|
93
|
+
`(actual=${rawBytes}, raw="${raw.slice(0, 32)}${raw.length > 32 ? '…' : ''}")`,
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
cleaned.callback_data = `${AGENT_CALLBACK_PREFIX}${raw}`
|
|
97
|
+
return cleaned
|
|
98
|
+
}),
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Extract per-button {@link AgentButtonMeta} from a raw (pre-wrap)
|
|
104
|
+
* keyboard. Returns a map keyed by the raw (unprefixed) callback_data
|
|
105
|
+
* string. Buttons without callback_data or without any meta fields are
|
|
106
|
+
* omitted. Used by the gateway to remember post-tap UX preferences for
|
|
107
|
+
* each button on a sent message.
|
|
108
|
+
*/
|
|
109
|
+
export function extractAgentButtonMeta(
|
|
110
|
+
keyboard: AnyButton[][],
|
|
111
|
+
): Map<string, AgentButtonMeta> {
|
|
112
|
+
const out = new Map<string, AgentButtonMeta>()
|
|
113
|
+
for (const row of keyboard) {
|
|
114
|
+
for (const btn of row) {
|
|
115
|
+
if (typeof btn.callback_data !== 'string') continue
|
|
116
|
+
const meta: AgentButtonMeta = {}
|
|
117
|
+
if (typeof btn.ack_text === 'string') meta.ack_text = btn.ack_text
|
|
118
|
+
if (typeof btn.single_use === 'boolean') meta.single_use = btn.single_use
|
|
119
|
+
if (meta.ack_text != null || meta.single_use != null) {
|
|
120
|
+
out.set(btn.callback_data, meta)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return out
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Aggregate the message-level "should we strip the keyboard after a tap"
|
|
129
|
+
* decision (#710). Default policy is single-use=true. The keyboard is
|
|
130
|
+
* preserved only when at least one button on the message explicitly opts
|
|
131
|
+
* out via `single_use: false`.
|
|
132
|
+
*/
|
|
133
|
+
export function keyboardIsSingleUse(
|
|
134
|
+
metaByRawData: Map<string, AgentButtonMeta>,
|
|
135
|
+
): boolean {
|
|
136
|
+
for (const meta of metaByRawData.values()) {
|
|
137
|
+
if (meta.single_use === false) return false
|
|
138
|
+
}
|
|
139
|
+
return true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Parse a callback_query.data string. Returns the raw agent payload
|
|
144
|
+
* (sans prefix) when the data is agent-emitted; null otherwise so the
|
|
145
|
+
* gateway dispatcher can fall through to its other routes.
|
|
146
|
+
*/
|
|
147
|
+
export function parseAgentCallback(data: string): { raw: string } | null {
|
|
148
|
+
if (!data.startsWith(AGENT_CALLBACK_PREFIX)) return null
|
|
149
|
+
return { raw: data.slice(AGENT_CALLBACK_PREFIX.length) }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Convenience: validate + wrap in one call. Returns either the
|
|
154
|
+
* wrapped keyboard or a structured error list — caller throws so the
|
|
155
|
+
* tool result carries the diagnostic upstream.
|
|
156
|
+
*/
|
|
157
|
+
export function validateAndWrapAgentKeyboard(
|
|
158
|
+
keyboard: AnyButton[][],
|
|
159
|
+
): { ok: true; wrapped: AnyButton[][] } | { ok: false; errors: ButtonValidationError[] } {
|
|
160
|
+
const errors = validateInlineKeyboard(keyboard)
|
|
161
|
+
if (errors.length > 0) return { ok: false, errors }
|
|
162
|
+
// wrapAgentCallbacks may throw on byte-budget overflow; let it
|
|
163
|
+
// propagate so the caller surfaces the message verbatim.
|
|
164
|
+
const wrapped = wrapAgentCallbacks(keyboard)
|
|
165
|
+
return { ok: true, wrapped }
|
|
166
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `!`-prefix interrupt marker — closes #575 / part of `reference/steer-or-queue-mid-flight.md`.
|
|
3
|
+
*
|
|
4
|
+
* The product contract: when the user starts a Telegram message with
|
|
5
|
+
* `!`, they're saying "drop what you're doing and handle this
|
|
6
|
+
* instead." The gateway:
|
|
7
|
+
* 1. Bypasses the inbound coalescer so the `!` always lands at
|
|
8
|
+
* the start of the parsed text (otherwise an earlier non-`!`
|
|
9
|
+
* message inside the same coalesce window would prepend itself
|
|
10
|
+
* and the marker would no longer be at position 0).
|
|
11
|
+
* 2. Sends SIGINT to the agent service so any in-flight turn dies.
|
|
12
|
+
* 3. Forwards the message with the `!` stripped as a fresh turn,
|
|
13
|
+
* so the agent sees clean intent without the marker character
|
|
14
|
+
* bleeding into its prompt.
|
|
15
|
+
*
|
|
16
|
+
* Pure helper — no side effects. Parses the marker; the gateway
|
|
17
|
+
* decides what to do with the verdict. Tested in
|
|
18
|
+
* `tests/interrupt-marker.test.ts` without grammY.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export interface InterruptParseResult {
|
|
22
|
+
/** True iff the message is a deliberate interrupt request. */
|
|
23
|
+
isInterrupt: boolean
|
|
24
|
+
/** The text the agent should see, minus the marker + leading whitespace. */
|
|
25
|
+
body: string
|
|
26
|
+
/** True iff the body would be empty (just `!` with nothing useful after).
|
|
27
|
+
* Caller may want to send a clarifying reply rather than forward an
|
|
28
|
+
* empty turn to the agent. */
|
|
29
|
+
emptyBody: boolean
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parse an inbound text body for the `!` interrupt marker.
|
|
34
|
+
*
|
|
35
|
+
* Rules:
|
|
36
|
+
* - Marker is `!` at position 0 of the trimmed body.
|
|
37
|
+
* - Doubled `!!` is NOT an interrupt — common typo / emphasis. The
|
|
38
|
+
* agent sees the literal `!!...` text. Single `!` is the rule.
|
|
39
|
+
* - Markdown-bold `*!*` or any other escape is NOT an interrupt.
|
|
40
|
+
* Strict literal match keeps the rule learnable.
|
|
41
|
+
* - The marker is consumed; the body returned is everything after,
|
|
42
|
+
* leading whitespace trimmed. So `! do this instead` → body `do
|
|
43
|
+
* this instead`.
|
|
44
|
+
*
|
|
45
|
+
* Why not other prefixes (e.g. `/stop`, `STOP`, `interrupt`):
|
|
46
|
+
* - `/`-prefixed strings are reserved for Telegram bot commands.
|
|
47
|
+
* - Word prefixes collide with normal speech ("Stop, that's wrong").
|
|
48
|
+
* - `!` is a single keystroke, hard to type by accident, easy to
|
|
49
|
+
* teach. Same convention as e.g. linuz90/claude-telegram-bot.
|
|
50
|
+
*/
|
|
51
|
+
export function parseInterruptMarker(text: string): InterruptParseResult {
|
|
52
|
+
const trimmed = text.trimStart()
|
|
53
|
+
if (!trimmed.startsWith('!')) {
|
|
54
|
+
return { isInterrupt: false, body: text, emptyBody: false }
|
|
55
|
+
}
|
|
56
|
+
// Doubled `!!` is intentional emphasis or typo — not a marker.
|
|
57
|
+
if (trimmed.startsWith('!!')) {
|
|
58
|
+
return { isInterrupt: false, body: text, emptyBody: false }
|
|
59
|
+
}
|
|
60
|
+
const body = trimmed.slice(1).trimStart()
|
|
61
|
+
return {
|
|
62
|
+
isInterrupt: true,
|
|
63
|
+
body,
|
|
64
|
+
emptyBody: body.length === 0,
|
|
65
|
+
}
|
|
66
|
+
}
|