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,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for tracking pinned progress-card message IDs across
|
|
3
|
+
* restarts.
|
|
4
|
+
*
|
|
5
|
+
* The progress-card driver pins a per-turn card on first emit and
|
|
6
|
+
* unpins on turn complete. That lifecycle is in-memory only, so a
|
|
7
|
+
* crash or kill mid-turn leaves a pinned message with no cleanup
|
|
8
|
+
* path — on restart, the in-memory map is empty and Telegram still
|
|
9
|
+
* shows the stale pin.
|
|
10
|
+
*
|
|
11
|
+
* This module persists the set of currently-pinned cards to a
|
|
12
|
+
* `.active-pins.json` sidecar under `$AGENT_DIR`. The server adds an
|
|
13
|
+
* entry right after `pinChatMessage` succeeds, removes the entry
|
|
14
|
+
* after `unpinChatMessage`, and on startup reads the file to sweep
|
|
15
|
+
* any stale entries (best-effort unpin) before the driver starts.
|
|
16
|
+
*
|
|
17
|
+
* All helpers are filesystem-only — no Telegram side effects — so
|
|
18
|
+
* they're unit-testable in isolation, mirroring `handoff-continuity.ts`.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFileSync, writeFileSync, renameSync, existsSync, unlinkSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
|
|
24
|
+
export const ACTIVE_PINS_FILENAME = ".active-pins.json";
|
|
25
|
+
|
|
26
|
+
export interface ActivePin {
|
|
27
|
+
chatId: string;
|
|
28
|
+
messageId: number;
|
|
29
|
+
turnKey: string;
|
|
30
|
+
pinnedAt: number;
|
|
31
|
+
/**
|
|
32
|
+
* Per-agent identity for the pin. Optional in the on-disk shape so
|
|
33
|
+
* sidecars written before per-agent cards (#per-agent-cards) still
|
|
34
|
+
* parse cleanly — readers should treat a missing field as the parent
|
|
35
|
+
* sentinel (`__parent__`).
|
|
36
|
+
*/
|
|
37
|
+
agentId?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function pinsPath(agentDir: string): string {
|
|
41
|
+
return join(agentDir, ACTIVE_PINS_FILENAME);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Read the active-pins sidecar. Missing, empty, or malformed files
|
|
46
|
+
* return an empty array — callers never have to handle parse errors.
|
|
47
|
+
* Entries that fail shape validation are dropped silently so a
|
|
48
|
+
* corrupted file can't brick the startup sweep.
|
|
49
|
+
*/
|
|
50
|
+
export function readActivePins(agentDir: string): ActivePin[] {
|
|
51
|
+
const p = pinsPath(agentDir);
|
|
52
|
+
if (!existsSync(p)) return [];
|
|
53
|
+
let raw: string;
|
|
54
|
+
try {
|
|
55
|
+
raw = readFileSync(p, "utf-8");
|
|
56
|
+
} catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
if (raw.trim().length === 0) return [];
|
|
60
|
+
let parsed: unknown;
|
|
61
|
+
try {
|
|
62
|
+
parsed = JSON.parse(raw);
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
if (!Array.isArray(parsed)) return [];
|
|
67
|
+
const out: ActivePin[] = [];
|
|
68
|
+
for (const item of parsed) {
|
|
69
|
+
if (
|
|
70
|
+
item != null &&
|
|
71
|
+
typeof item === "object" &&
|
|
72
|
+
typeof (item as ActivePin).chatId === "string" &&
|
|
73
|
+
typeof (item as ActivePin).messageId === "number" &&
|
|
74
|
+
typeof (item as ActivePin).turnKey === "string" &&
|
|
75
|
+
typeof (item as ActivePin).pinnedAt === "number"
|
|
76
|
+
) {
|
|
77
|
+
const aid = (item as ActivePin).agentId;
|
|
78
|
+
const entry: ActivePin = aid != null && typeof aid === "string"
|
|
79
|
+
? (item as ActivePin)
|
|
80
|
+
: { ...(item as ActivePin), agentId: undefined };
|
|
81
|
+
out.push(entry);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Atomically overwrite the sidecar with the given list. Writing an
|
|
89
|
+
* empty list deletes the file so a fresh restart sees no state.
|
|
90
|
+
*/
|
|
91
|
+
export function writeActivePins(agentDir: string, pins: ActivePin[]): void {
|
|
92
|
+
const p = pinsPath(agentDir);
|
|
93
|
+
if (pins.length === 0) {
|
|
94
|
+
try {
|
|
95
|
+
unlinkSync(p);
|
|
96
|
+
} catch {
|
|
97
|
+
/* already gone */
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
102
|
+
try {
|
|
103
|
+
writeFileSync(tmp, JSON.stringify(pins) + "\n", "utf-8");
|
|
104
|
+
renameSync(tmp, p);
|
|
105
|
+
} catch {
|
|
106
|
+
/* best-effort — failsafe cleanup is cosmetic, not safety-critical */
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Append a new pin to the sidecar. Idempotent on `(chatId, messageId)`
|
|
112
|
+
* — a duplicate add replaces the existing entry so `pinnedAt` reflects
|
|
113
|
+
* the most recent pin.
|
|
114
|
+
*/
|
|
115
|
+
export function addActivePin(agentDir: string, pin: ActivePin): void {
|
|
116
|
+
const existing = readActivePins(agentDir).filter(
|
|
117
|
+
(p) => !(p.chatId === pin.chatId && p.messageId === pin.messageId),
|
|
118
|
+
);
|
|
119
|
+
existing.push(pin);
|
|
120
|
+
writeActivePins(agentDir, existing);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Remove the pin matching `(chatId, messageId)`. No-op when the
|
|
125
|
+
* sidecar or entry is absent.
|
|
126
|
+
*/
|
|
127
|
+
export function removeActivePin(agentDir: string, chatId: string, messageId: number): void {
|
|
128
|
+
const existing = readActivePins(agentDir);
|
|
129
|
+
const next = existing.filter(
|
|
130
|
+
(p) => !(p.chatId === chatId && p.messageId === messageId),
|
|
131
|
+
);
|
|
132
|
+
if (next.length === existing.length) return;
|
|
133
|
+
writeActivePins(agentDir, next);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Delete the sidecar outright. Called after the startup sweep so the
|
|
138
|
+
* next run starts clean regardless of unpin success.
|
|
139
|
+
*/
|
|
140
|
+
export function clearActivePins(agentDir: string): void {
|
|
141
|
+
try {
|
|
142
|
+
unlinkSync(pinsPath(agentDir));
|
|
143
|
+
} catch {
|
|
144
|
+
/* already gone */
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sweep logic for the active-reactions sidecar.
|
|
3
|
+
*
|
|
4
|
+
* The sidecar (see `active-reactions.ts`) records every in-flight
|
|
5
|
+
* status reaction the bot has set but not yet resolved to a terminal
|
|
6
|
+
* state (👍 done or 😱 error). Two lifecycle events consume it:
|
|
7
|
+
*
|
|
8
|
+
* 1. Startup — when a new gateway process boots, it sweeps any
|
|
9
|
+
* entries left over from a prior session that crashed or was
|
|
10
|
+
* killed mid-turn. Without this, reactions stay stuck on
|
|
11
|
+
* intermediate emoji (🤔, 🔥, etc.) forever because the
|
|
12
|
+
* in-memory map that tracks them died with the old process.
|
|
13
|
+
*
|
|
14
|
+
* 2. Pre-restart — when /restart, /reconcile --restart, or /update
|
|
15
|
+
* commands fire a self-restart, the gateway proactively promotes
|
|
16
|
+
* any still-active reactions to 👍 before it gets SIGTERM'd.
|
|
17
|
+
*
|
|
18
|
+
* Both consumers call `sweepActiveReactions`, which is shaped as a
|
|
19
|
+
* pure function that takes the setDone callback as an argument. That
|
|
20
|
+
* keeps it testable in isolation — the tests pass a fake callback and
|
|
21
|
+
* assert which reactions were visited and whether the sidecar was
|
|
22
|
+
* cleared.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { readActiveReactions, clearActiveReactions, type ActiveReaction } from "./active-reactions.js";
|
|
26
|
+
|
|
27
|
+
export type SetDoneReactionFn = (chatId: string, messageId: number) => Promise<unknown>;
|
|
28
|
+
|
|
29
|
+
export interface SweepOptions {
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
log?: (msg: string) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface SweepResult {
|
|
35
|
+
swept: ActiveReaction[];
|
|
36
|
+
timedOut: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Promote every entry in the sidecar to 👍, then clear it. Bounded by
|
|
41
|
+
* `timeoutMs` (default 2s) so a slow Telegram API can't block a
|
|
42
|
+
* restart indefinitely. Failures are logged and swallowed — the
|
|
43
|
+
* sidecar is cleared regardless so stale entries don't pile up on
|
|
44
|
+
* subsequent boots.
|
|
45
|
+
*/
|
|
46
|
+
export async function sweepActiveReactions(
|
|
47
|
+
agentDir: string,
|
|
48
|
+
setDone: SetDoneReactionFn,
|
|
49
|
+
options: SweepOptions = {},
|
|
50
|
+
): Promise<SweepResult> {
|
|
51
|
+
const log = options.log ?? (() => {});
|
|
52
|
+
const timeoutMs = options.timeoutMs ?? 2000;
|
|
53
|
+
const reactions = readActiveReactions(agentDir);
|
|
54
|
+
if (reactions.length === 0) return { swept: [], timedOut: false };
|
|
55
|
+
|
|
56
|
+
log(`sweeping ${reactions.length} stale reaction(s)`);
|
|
57
|
+
const attempts = reactions.map((r) =>
|
|
58
|
+
Promise.resolve()
|
|
59
|
+
.then(() => setDone(r.chatId, r.messageId))
|
|
60
|
+
.catch((err: unknown) => {
|
|
61
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
62
|
+
log(`reaction sweep failed for ${r.chatId}/${r.messageId}: ${msg}`);
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
let timedOut = false;
|
|
67
|
+
await Promise.race([
|
|
68
|
+
Promise.allSettled(attempts),
|
|
69
|
+
new Promise<void>((resolve) =>
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
timedOut = true;
|
|
72
|
+
resolve();
|
|
73
|
+
}, timeoutMs),
|
|
74
|
+
),
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
clearActiveReactions(agentDir);
|
|
78
|
+
return { swept: reactions, timedOut };
|
|
79
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for tracking in-flight status reactions across gateway
|
|
3
|
+
* restarts.
|
|
4
|
+
*
|
|
5
|
+
* The status-reaction lifecycle is in-memory only (`activeStatusReactions`
|
|
6
|
+
* Map in gateway.ts). When the *gateway* crashes mid-turn, the Map is
|
|
7
|
+
* lost and Telegram still shows the intermediate emoji (🤔, 🔥, etc.)
|
|
8
|
+
* with no cleanup path.
|
|
9
|
+
*
|
|
10
|
+
* This module persists the set of currently-active reactions to a
|
|
11
|
+
* `.active-reactions.json` sidecar under `$AGENT_DIR`. The gateway adds
|
|
12
|
+
* an entry right after creating a StatusReactionController, removes it
|
|
13
|
+
* when the reaction reaches a terminal state, and on startup reads the
|
|
14
|
+
* file to sweep any stale entries (best-effort promotion to 👍).
|
|
15
|
+
*
|
|
16
|
+
* All helpers are filesystem-only — no Telegram side effects — so
|
|
17
|
+
* they're unit-testable in isolation, mirroring `active-pins.ts`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readFileSync, writeFileSync, renameSync, existsSync, unlinkSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
|
|
23
|
+
export const ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
|
|
24
|
+
|
|
25
|
+
export interface ActiveReaction {
|
|
26
|
+
chatId: string;
|
|
27
|
+
messageId: number;
|
|
28
|
+
threadId: number | null;
|
|
29
|
+
reactedAt: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function reactionsPath(agentDir: string): string {
|
|
33
|
+
return join(agentDir, ACTIVE_REACTIONS_FILENAME);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Read the active-reactions sidecar. Missing, empty, or malformed files
|
|
38
|
+
* return an empty array — callers never have to handle parse errors.
|
|
39
|
+
* Entries that fail shape validation are dropped silently so a
|
|
40
|
+
* corrupted file can't brick the startup sweep.
|
|
41
|
+
*/
|
|
42
|
+
export function readActiveReactions(agentDir: string): ActiveReaction[] {
|
|
43
|
+
const p = reactionsPath(agentDir);
|
|
44
|
+
if (!existsSync(p)) return [];
|
|
45
|
+
let raw: string;
|
|
46
|
+
try {
|
|
47
|
+
raw = readFileSync(p, "utf-8");
|
|
48
|
+
} catch {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
if (raw.trim().length === 0) return [];
|
|
52
|
+
let parsed: unknown;
|
|
53
|
+
try {
|
|
54
|
+
parsed = JSON.parse(raw);
|
|
55
|
+
} catch {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
if (!Array.isArray(parsed)) return [];
|
|
59
|
+
const out: ActiveReaction[] = [];
|
|
60
|
+
for (const item of parsed) {
|
|
61
|
+
if (
|
|
62
|
+
item != null &&
|
|
63
|
+
typeof item === "object" &&
|
|
64
|
+
typeof (item as ActiveReaction).chatId === "string" &&
|
|
65
|
+
typeof (item as ActiveReaction).messageId === "number" &&
|
|
66
|
+
(typeof (item as ActiveReaction).threadId === "number" || (item as ActiveReaction).threadId === null) &&
|
|
67
|
+
typeof (item as ActiveReaction).reactedAt === "number"
|
|
68
|
+
) {
|
|
69
|
+
out.push(item as ActiveReaction);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Atomically overwrite the sidecar with the given list. Writing an
|
|
77
|
+
* empty list deletes the file so a fresh restart sees no state.
|
|
78
|
+
*/
|
|
79
|
+
export function writeActiveReactions(agentDir: string, reactions: ActiveReaction[]): void {
|
|
80
|
+
const p = reactionsPath(agentDir);
|
|
81
|
+
if (reactions.length === 0) {
|
|
82
|
+
try {
|
|
83
|
+
unlinkSync(p);
|
|
84
|
+
} catch {
|
|
85
|
+
/* already gone */
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
90
|
+
try {
|
|
91
|
+
writeFileSync(tmp, JSON.stringify(reactions) + "\n", "utf-8");
|
|
92
|
+
renameSync(tmp, p);
|
|
93
|
+
} catch {
|
|
94
|
+
/* best-effort — failsafe cleanup is cosmetic, not safety-critical */
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Append a new reaction to the sidecar. Idempotent on `(chatId, messageId)`
|
|
100
|
+
* — a duplicate add replaces the existing entry so `reactedAt` reflects
|
|
101
|
+
* the most recent reaction.
|
|
102
|
+
*/
|
|
103
|
+
export function addActiveReaction(agentDir: string, reaction: ActiveReaction): void {
|
|
104
|
+
const existing = readActiveReactions(agentDir).filter(
|
|
105
|
+
(r) => !(r.chatId === reaction.chatId && r.messageId === reaction.messageId),
|
|
106
|
+
);
|
|
107
|
+
existing.push(reaction);
|
|
108
|
+
writeActiveReactions(agentDir, existing);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Remove the reaction matching `(chatId, messageId)`. No-op when the
|
|
113
|
+
* sidecar or entry is absent.
|
|
114
|
+
*/
|
|
115
|
+
export function removeActiveReaction(agentDir: string, chatId: string, messageId: number): void {
|
|
116
|
+
const existing = readActiveReactions(agentDir);
|
|
117
|
+
const next = existing.filter(
|
|
118
|
+
(r) => !(r.chatId === chatId && r.messageId === messageId),
|
|
119
|
+
);
|
|
120
|
+
if (next.length === existing.length) return;
|
|
121
|
+
writeActiveReactions(agentDir, next);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Delete the sidecar outright. Called after the startup sweep so the
|
|
126
|
+
* next run starts clean regardless of sweep success.
|
|
127
|
+
*/
|
|
128
|
+
export function clearActiveReactions(agentDir: string): void {
|
|
129
|
+
try {
|
|
130
|
+
unlinkSync(reactionsPath(agentDir));
|
|
131
|
+
} catch {
|
|
132
|
+
/* already gone */
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { dispatchAdminCommand, parseCommandName, ADMIN_COMMAND_NAMES } from './index.js'
|
|
3
|
+
|
|
4
|
+
// ─── parseCommandName ────────────────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
describe('parseCommandName', () => {
|
|
7
|
+
it('extracts a simple command', () => {
|
|
8
|
+
expect(parseCommandName('/agents')).toBe('agents')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('strips a @botname suffix', () => {
|
|
12
|
+
expect(parseCommandName('/agents@mybot')).toBe('agents')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('ignores arguments after a space', () => {
|
|
16
|
+
expect(parseCommandName('/logs 50')).toBe('logs')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('normalises to lowercase', () => {
|
|
20
|
+
expect(parseCommandName('/Agents')).toBe('agents')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('returns null for non-slash text', () => {
|
|
24
|
+
expect(parseCommandName('hello')).toBeNull()
|
|
25
|
+
expect(parseCommandName('')).toBeNull()
|
|
26
|
+
expect(parseCommandName('agents')).toBeNull()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('returns an empty string for a bare slash', () => {
|
|
30
|
+
expect(parseCommandName('/ ')).toBe('')
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
// ─── ADMIN_COMMAND_NAMES ─────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
describe('ADMIN_COMMAND_NAMES', () => {
|
|
37
|
+
it('contains the fleet-management admin commands', () => {
|
|
38
|
+
const required = ['agents', 'logs', 'restart', 'update', 'reconcile', 'stop', 'agentstart', 'grant', 'dangerous', 'permissions', 'vault']
|
|
39
|
+
for (const cmd of required) {
|
|
40
|
+
expect(ADMIN_COMMAND_NAMES.has(cmd)).toBe(true)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('does not contain per-agent auth ops (must work without model)', () => {
|
|
45
|
+
// /auth, /reauth, /authfallback are handled by the gateway directly so
|
|
46
|
+
// the user can re-authenticate even when the model is rate-limited or the
|
|
47
|
+
// token is expired. Routing them through Claude would defeat the point.
|
|
48
|
+
expect(ADMIN_COMMAND_NAMES.has('auth')).toBe(false)
|
|
49
|
+
expect(ADMIN_COMMAND_NAMES.has('reauth')).toBe(false)
|
|
50
|
+
expect(ADMIN_COMMAND_NAMES.has('authfallback')).toBe(false)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('does not contain interrupt (cancellation must always work)', () => {
|
|
54
|
+
expect(ADMIN_COMMAND_NAMES.has('interrupt')).toBe(false)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('does not contain the permission-response flow', () => {
|
|
58
|
+
// /approve, /deny, /pending are intercepted by the gateway before the
|
|
59
|
+
// model is invoked anyway — they have nothing to do with admin gating.
|
|
60
|
+
expect(ADMIN_COMMAND_NAMES.has('approve')).toBe(false)
|
|
61
|
+
expect(ADMIN_COMMAND_NAMES.has('deny')).toBe(false)
|
|
62
|
+
expect(ADMIN_COMMAND_NAMES.has('pending')).toBe(false)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('does not contain info commands (must work when model is down)', () => {
|
|
66
|
+
expect(ADMIN_COMMAND_NAMES.has('version')).toBe(false)
|
|
67
|
+
expect(ADMIN_COMMAND_NAMES.has('doctor')).toBe(false)
|
|
68
|
+
expect(ADMIN_COMMAND_NAMES.has('usage')).toBe(false)
|
|
69
|
+
expect(ADMIN_COMMAND_NAMES.has('commands')).toBe(false)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('does not contain session-reset commands', () => {
|
|
73
|
+
expect(ADMIN_COMMAND_NAMES.has('new')).toBe(false)
|
|
74
|
+
expect(ADMIN_COMMAND_NAMES.has('reset')).toBe(false)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('does not contain create-agent (out of scope for phase 1)', () => {
|
|
78
|
+
expect(ADMIN_COMMAND_NAMES.has('create-agent')).toBe(false)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('does not contain legacy verbs upgrade or rebuild', () => {
|
|
82
|
+
expect(ADMIN_COMMAND_NAMES.has('upgrade')).toBe(false)
|
|
83
|
+
expect(ADMIN_COMMAND_NAMES.has('rebuild')).toBe(false)
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// ─── dispatchAdminCommand ────────────────────────────────────────────────────
|
|
88
|
+
|
|
89
|
+
describe('dispatchAdminCommand', () => {
|
|
90
|
+
describe('when admin=true', () => {
|
|
91
|
+
it('handles a known admin command', () => {
|
|
92
|
+
expect(dispatchAdminCommand('/agents', true)).toEqual({ handled: true })
|
|
93
|
+
expect(dispatchAdminCommand('/logs', true)).toEqual({ handled: true })
|
|
94
|
+
expect(dispatchAdminCommand('/restart', true)).toEqual({ handled: true })
|
|
95
|
+
expect(dispatchAdminCommand('/update', true)).toEqual({ handled: true })
|
|
96
|
+
expect(dispatchAdminCommand('/vault', true)).toEqual({ handled: true })
|
|
97
|
+
expect(dispatchAdminCommand('/permissions', true)).toEqual({ handled: true })
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('does NOT handle per-agent ops (auth/interrupt/info/session)', () => {
|
|
101
|
+
// These are intentionally NOT admin-gated — they always run via the
|
|
102
|
+
// gateway, regardless of admin status, so the user can recover when
|
|
103
|
+
// the model is unreachable.
|
|
104
|
+
expect(dispatchAdminCommand('/auth', true)).toEqual({ handled: false })
|
|
105
|
+
expect(dispatchAdminCommand('/reauth', true)).toEqual({ handled: false })
|
|
106
|
+
expect(dispatchAdminCommand('/interrupt', true)).toEqual({ handled: false })
|
|
107
|
+
expect(dispatchAdminCommand('/version', true)).toEqual({ handled: false })
|
|
108
|
+
expect(dispatchAdminCommand('/doctor', true)).toEqual({ handled: false })
|
|
109
|
+
expect(dispatchAdminCommand('/usage', true)).toEqual({ handled: false })
|
|
110
|
+
expect(dispatchAdminCommand('/new', true)).toEqual({ handled: false })
|
|
111
|
+
expect(dispatchAdminCommand('/reset', true)).toEqual({ handled: false })
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('handles a known command with arguments', () => {
|
|
115
|
+
expect(dispatchAdminCommand('/logs 50', true)).toEqual({ handled: true })
|
|
116
|
+
expect(dispatchAdminCommand('/restart myagent', true)).toEqual({ handled: true })
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('handles a known command with @botname suffix', () => {
|
|
120
|
+
expect(dispatchAdminCommand('/agents@switchroombot', true)).toEqual({ handled: true })
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('does NOT handle an unknown slash command', () => {
|
|
124
|
+
expect(dispatchAdminCommand('/nope', true)).toEqual({ handled: false })
|
|
125
|
+
expect(dispatchAdminCommand('/unknown-command', true)).toEqual({ handled: false })
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('does NOT handle plain text (non-slash)', () => {
|
|
129
|
+
expect(dispatchAdminCommand('hello', true)).toEqual({ handled: false })
|
|
130
|
+
expect(dispatchAdminCommand('show me the agents', true)).toEqual({ handled: false })
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('does NOT handle empty string', () => {
|
|
134
|
+
expect(dispatchAdminCommand('', true)).toEqual({ handled: false })
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
describe('when admin=false', () => {
|
|
139
|
+
it('does NOT handle any command — all fall through to Claude', () => {
|
|
140
|
+
// Belt-and-braces: even if the gateway calls the dispatcher for a known
|
|
141
|
+
// admin command, it must return handled=false when admin is off.
|
|
142
|
+
expect(dispatchAdminCommand('/agents', false)).toEqual({ handled: false })
|
|
143
|
+
expect(dispatchAdminCommand('/logs', false)).toEqual({ handled: false })
|
|
144
|
+
expect(dispatchAdminCommand('/restart', false)).toEqual({ handled: false })
|
|
145
|
+
expect(dispatchAdminCommand('/nope', false)).toEqual({ handled: false })
|
|
146
|
+
expect(dispatchAdminCommand('hello', false)).toEqual({ handled: false })
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
})
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* admin-commands/index.ts
|
|
3
|
+
*
|
|
4
|
+
* Shared dispatcher for switchroom admin slash commands. Used by both:
|
|
5
|
+
* - gateway.ts (when SWITCHROOM_AGENT_ADMIN=true in the agent's systemd unit)
|
|
6
|
+
* - server.ts (legacy monolith — always acts as its own admin)
|
|
7
|
+
*
|
|
8
|
+
* The dispatcher is intentionally thin: it only decides whether an inbound
|
|
9
|
+
* text message matches a known admin command AND should be handled locally
|
|
10
|
+
* (intercepted before Claude sees it). Actual command execution lives in the
|
|
11
|
+
* Grammy bot.command() handlers in gateway.ts / server.ts; this module
|
|
12
|
+
* provides the gating logic and the canonical command list so both paths
|
|
13
|
+
* stay in sync.
|
|
14
|
+
*
|
|
15
|
+
* Architecture
|
|
16
|
+
* ────────────
|
|
17
|
+
* Grammy routes a message to whichever handler matches first. `bot.command()`
|
|
18
|
+
* handlers fire BEFORE `bot.on('message:text')`, so a `/agents` message never
|
|
19
|
+
* reaches `handleInbound` under normal circumstances. However, when admin=false
|
|
20
|
+
* we WANT those commands to fall through to Claude. The gateway registers a
|
|
21
|
+
* middleware (via `makeAdminCommandMiddleware`) BEFORE its bot.command() calls;
|
|
22
|
+
* the middleware redirects to handleInbound when admin=false.
|
|
23
|
+
*
|
|
24
|
+
* Out of scope for Phase 1
|
|
25
|
+
* ────────────────────────
|
|
26
|
+
* `/create-agent` has a complex multi-turn state machine (persisted wizard
|
|
27
|
+
* state across messages). It is intentionally NOT included here and remains
|
|
28
|
+
* foreman/server-only until Phase 2 or later.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The set of command names that are treated as "admin commands" — intercepted
|
|
33
|
+
* by the gateway when SWITCHROOM_AGENT_ADMIN=true, forwarded to Claude otherwise.
|
|
34
|
+
*
|
|
35
|
+
* Scope: ONLY fleet-management verbs (lifecycle, scaffolding, privileges,
|
|
36
|
+
* secrets). Per-agent / per-chat ops — auth, interrupt, permission flow,
|
|
37
|
+
* info commands (`/version`, `/doctor`, `/usage`), session reset (`/new`,
|
|
38
|
+
* `/reset`), and `/commands` — must always be gateway-handled
|
|
39
|
+
* regardless of admin status, because they need to work even when the model
|
|
40
|
+
* is unreachable (rate-limited, expired token, network down). Routing those
|
|
41
|
+
* through Claude defeats the entire point of the slash-command UX.
|
|
42
|
+
*
|
|
43
|
+
* Keep in sync with the bot.command() registrations in gateway.ts.
|
|
44
|
+
*/
|
|
45
|
+
export const ADMIN_COMMAND_NAMES = new Set<string>([
|
|
46
|
+
// Fleet lifecycle
|
|
47
|
+
'agents',
|
|
48
|
+
'logs',
|
|
49
|
+
'restart',
|
|
50
|
+
'stop',
|
|
51
|
+
'agentstart',
|
|
52
|
+
'update',
|
|
53
|
+
'reconcile',
|
|
54
|
+
// Privileges + secrets
|
|
55
|
+
'grant',
|
|
56
|
+
'dangerous',
|
|
57
|
+
'permissions',
|
|
58
|
+
'vault',
|
|
59
|
+
// Per-agent ops that read shared fleet state via the switchroom CLI
|
|
60
|
+
'memory',
|
|
61
|
+
'topics',
|
|
62
|
+
])
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Parse a slash command name from a text message, accounting for bot@username
|
|
66
|
+
* suffixes (e.g. `/agents@mybot`). Returns null for non-command text.
|
|
67
|
+
*/
|
|
68
|
+
export function parseCommandName(text: string): string | null {
|
|
69
|
+
if (!text.startsWith('/')) return null
|
|
70
|
+
// Extract the part after / up to the first space or end-of-string,
|
|
71
|
+
// stripping an optional @botname suffix.
|
|
72
|
+
const raw = text.split(' ')[0]!.slice(1)
|
|
73
|
+
const atIdx = raw.indexOf('@')
|
|
74
|
+
return atIdx === -1 ? raw.toLowerCase() : raw.slice(0, atIdx).toLowerCase()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Decide whether an inbound message should be intercepted as an admin command.
|
|
79
|
+
*
|
|
80
|
+
* Returns `{ handled: true }` when:
|
|
81
|
+
* - `adminEnabled` is true (SWITCHROOM_AGENT_ADMIN=true)
|
|
82
|
+
* - `text` starts with `/`
|
|
83
|
+
* - The command name is in ADMIN_COMMAND_NAMES
|
|
84
|
+
*
|
|
85
|
+
* Returns `{ handled: false }` in all other cases — the message should fall
|
|
86
|
+
* through to normal processing (forwarded to Claude via IPC).
|
|
87
|
+
*
|
|
88
|
+
* Note: this function does NOT execute the command. Execution is performed by
|
|
89
|
+
* Grammy's bot.command() handlers in gateway.ts. This function is used:
|
|
90
|
+
* 1. By the gateway middleware to decide whether to forward non-admin-gated
|
|
91
|
+
* commands to Claude (when adminEnabled=false).
|
|
92
|
+
* 2. By tests to verify the dispatch table is correct without starting a bot.
|
|
93
|
+
*/
|
|
94
|
+
export function dispatchAdminCommand(
|
|
95
|
+
text: string,
|
|
96
|
+
adminEnabled: boolean,
|
|
97
|
+
): { handled: boolean } {
|
|
98
|
+
// Belt-and-braces: even if the caller forgot to check, we never intercept
|
|
99
|
+
// when admin is off.
|
|
100
|
+
if (!adminEnabled) return { handled: false }
|
|
101
|
+
if (!text.startsWith('/')) return { handled: false }
|
|
102
|
+
const cmd = parseCommandName(text)
|
|
103
|
+
if (!cmd) return { handled: false }
|
|
104
|
+
if (ADMIN_COMMAND_NAMES.has(cmd)) return { handled: true }
|
|
105
|
+
return { handled: false }
|
|
106
|
+
}
|