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,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Phase 3b foreman write operations:
|
|
3
|
+
* - handleRestartCommand (mocked execFileSync)
|
|
4
|
+
* - handleDeleteCommand + executeDeleteAgent (mocked exec + FS)
|
|
5
|
+
* - handleUpdateCommand (mocked combined exec)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
9
|
+
import {
|
|
10
|
+
handleRestartCommand,
|
|
11
|
+
handleDeleteCommand,
|
|
12
|
+
executeDeleteAgent,
|
|
13
|
+
handleUpdateCommand,
|
|
14
|
+
type SwitchroomExecFn,
|
|
15
|
+
} from '../foreman/foreman-handlers.js'
|
|
16
|
+
import type { execFileSync } from 'child_process'
|
|
17
|
+
|
|
18
|
+
// ─── /restart ─────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
describe('foreman: handleRestartCommand — input validation', () => {
|
|
21
|
+
it('returns usage when no agent specified', () => {
|
|
22
|
+
const result = handleRestartCommand('')
|
|
23
|
+
expect(result.ok).toBe(false)
|
|
24
|
+
expect(result.text).toContain('Usage')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('rejects invalid agent name', () => {
|
|
28
|
+
const execFile = vi.fn()
|
|
29
|
+
// 'BadName' has uppercase — first token is invalid
|
|
30
|
+
const result = handleRestartCommand('BadName', execFile as never)
|
|
31
|
+
expect(result.ok).toBe(false)
|
|
32
|
+
expect(result.text).toBe('Invalid agent name.')
|
|
33
|
+
expect(execFile).not.toHaveBeenCalled()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('rejects path traversal', () => {
|
|
37
|
+
const execFile = vi.fn()
|
|
38
|
+
const result = handleRestartCommand('../etc/passwd', execFile as never)
|
|
39
|
+
expect(result.ok).toBe(false)
|
|
40
|
+
expect(execFile).not.toHaveBeenCalled()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('rejects agent name with colon', () => {
|
|
44
|
+
const execFile = vi.fn()
|
|
45
|
+
const result = handleRestartCommand('bad:name', execFile as never)
|
|
46
|
+
expect(result.ok).toBe(false)
|
|
47
|
+
expect(execFile).not.toHaveBeenCalled()
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
describe('foreman: handleRestartCommand — execFileSync calls', () => {
|
|
52
|
+
it('calls systemctl --user restart with correct unit name', () => {
|
|
53
|
+
const execFile = vi.fn().mockReturnValue('')
|
|
54
|
+
const result = handleRestartCommand('gymbro', execFile as never)
|
|
55
|
+
|
|
56
|
+
expect(result.ok).toBe(true)
|
|
57
|
+
expect(execFile).toHaveBeenCalledOnce()
|
|
58
|
+
const [cmd, args] = execFile.mock.calls[0] as [string, string[]]
|
|
59
|
+
expect(cmd).toBe('systemctl')
|
|
60
|
+
expect(args).toContain('--user')
|
|
61
|
+
expect(args).toContain('restart')
|
|
62
|
+
expect(args).toContain('switchroom-gymbro')
|
|
63
|
+
// Must NOT be a shell string — second arg must be an array
|
|
64
|
+
expect(Array.isArray(args)).toBe(true)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('uses execFileSync not execSync (no shell)', () => {
|
|
68
|
+
const execFile = vi.fn().mockReturnValue('')
|
|
69
|
+
handleRestartCommand('gymbro', execFile as never)
|
|
70
|
+
// The function is called with 3 args (cmd, args[], opts) not a shell string
|
|
71
|
+
const [, args] = execFile.mock.calls[0] as [string, string[], object]
|
|
72
|
+
expect(Array.isArray(args)).toBe(true)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('includes agent name in success reply', () => {
|
|
76
|
+
const execFile = vi.fn().mockReturnValue('')
|
|
77
|
+
const result = handleRestartCommand('gymbro', execFile as never)
|
|
78
|
+
expect(result.ok).toBe(true)
|
|
79
|
+
expect(result.text).toContain('gymbro')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('returns error text when systemctl fails', () => {
|
|
83
|
+
const execFile = vi.fn().mockImplementation(() => {
|
|
84
|
+
throw Object.assign(new Error('unit not found'), { stderr: 'Unit switchroom-gymbro.service not found.' })
|
|
85
|
+
})
|
|
86
|
+
const result = handleRestartCommand('gymbro', execFile as never)
|
|
87
|
+
expect(result.ok).toBe(false)
|
|
88
|
+
expect(result.text).toContain('restart failed')
|
|
89
|
+
expect(result.text).toContain('gymbro')
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('handles agent name with hyphen', () => {
|
|
93
|
+
const execFile = vi.fn().mockReturnValue('')
|
|
94
|
+
handleRestartCommand('my-agent', execFile as never)
|
|
95
|
+
const [, args] = execFile.mock.calls[0] as [string, string[]]
|
|
96
|
+
expect(args).toContain('switchroom-my-agent')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('escapes HTML in error output', () => {
|
|
100
|
+
const execFile = vi.fn().mockImplementation(() => {
|
|
101
|
+
throw Object.assign(new Error('err'), { stderr: 'Error: <unit> not found' })
|
|
102
|
+
})
|
|
103
|
+
const result = handleRestartCommand('gymbro', execFile as never)
|
|
104
|
+
expect(result.text).not.toContain('<unit>')
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// ─── /delete first step ───────────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
describe('foreman: handleDeleteCommand — prompt', () => {
|
|
111
|
+
it('returns usage when no agent specified', () => {
|
|
112
|
+
const result = handleDeleteCommand('')
|
|
113
|
+
expect(result.replies[0].text).toContain('Usage')
|
|
114
|
+
expect(result.needsConfirm).toBeFalsy()
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('rejects invalid agent name', () => {
|
|
118
|
+
// 'BadAgent' has uppercase — invalid
|
|
119
|
+
const result = handleDeleteCommand('BadAgent')
|
|
120
|
+
expect(result.replies[0].text).toBe('Invalid agent name.')
|
|
121
|
+
expect(result.needsConfirm).toBeFalsy()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('returns confirmation prompt for valid agent', () => {
|
|
125
|
+
const result = handleDeleteCommand('gymbro')
|
|
126
|
+
expect(result.replies[0].text).toContain('gymbro')
|
|
127
|
+
expect(result.replies[0].text).toContain('YES')
|
|
128
|
+
expect(result.needsConfirm).toBe(true)
|
|
129
|
+
expect(result.agentForConfirm).toBe('gymbro')
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('escapes HTML in agent name in prompt', () => {
|
|
133
|
+
// valid name, but let's use one that could trip HTML — actually all valid names
|
|
134
|
+
// are alphanumeric so no HTML risk; just verify the name appears
|
|
135
|
+
const result = handleDeleteCommand('my-agent')
|
|
136
|
+
expect(result.replies[0].text).toContain('my-agent')
|
|
137
|
+
expect(result.replies[0].html).toBe(true)
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
// ─── executeDeleteAgent ───────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
describe('foreman: executeDeleteAgent — execution', () => {
|
|
144
|
+
it('runs CLI destroy with --yes flag', () => {
|
|
145
|
+
const switchroomExec: SwitchroomExecFn = vi.fn().mockReturnValue('Removed unit.')
|
|
146
|
+
const execFile = vi.fn().mockReturnValue('')
|
|
147
|
+
const tmpDir = '/tmp/fake-agents-dir'
|
|
148
|
+
|
|
149
|
+
const result = executeDeleteAgent('gymbro', switchroomExec, execFile as never, tmpDir)
|
|
150
|
+
expect(switchroomExec).toHaveBeenCalledWith(['agent', 'destroy', '--yes', 'gymbro'])
|
|
151
|
+
expect(result.replies[0].text).toContain('gymbro')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('reports success without archive when dir does not exist', () => {
|
|
155
|
+
const switchroomExec: SwitchroomExecFn = vi.fn().mockReturnValue('done')
|
|
156
|
+
const result = executeDeleteAgent('gymbro', switchroomExec, vi.fn() as never, '/nonexistent-agents-dir')
|
|
157
|
+
// No archive reported (dir didn't exist)
|
|
158
|
+
expect(result.replies[0].text).not.toContain('Archived')
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('rejects invalid agent name without calling CLI', () => {
|
|
162
|
+
const switchroomExec: SwitchroomExecFn = vi.fn()
|
|
163
|
+
const result = executeDeleteAgent('bad name!', switchroomExec, vi.fn() as never, '/tmp')
|
|
164
|
+
expect(result.replies[0].text).toBe('Invalid agent name.')
|
|
165
|
+
expect(switchroomExec).not.toHaveBeenCalled()
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('reports CLI error but notes archive succeeded', () => {
|
|
169
|
+
const switchroomExec: SwitchroomExecFn = vi.fn().mockImplementation(() => {
|
|
170
|
+
throw Object.assign(new Error('destroy failed'), { stderr: 'switchroom error' })
|
|
171
|
+
})
|
|
172
|
+
// Use a dir that definitely doesn't exist so no actual rename
|
|
173
|
+
const result = executeDeleteAgent('gymbro', switchroomExec, vi.fn() as never, '/nonexistent-agents-12345')
|
|
174
|
+
expect(result.replies[0].text).toContain('CLI destroy failed')
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// ─── /update ──────────────────────────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
describe('foreman: handleUpdateCommand', () => {
|
|
181
|
+
it('calls switchroomExec with ["update"]', () => {
|
|
182
|
+
const exec: SwitchroomExecFn = vi.fn().mockReturnValue('Updated successfully.')
|
|
183
|
+
handleUpdateCommand(exec)
|
|
184
|
+
expect(exec).toHaveBeenCalledWith(['update'])
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('returns output in a pre block', () => {
|
|
188
|
+
const exec: SwitchroomExecFn = vi.fn().mockReturnValue('Pulled abc123. Reconciled 2 agents.')
|
|
189
|
+
const result = handleUpdateCommand(exec)
|
|
190
|
+
expect(result.replies[0].text).toContain('Pulled abc123')
|
|
191
|
+
expect(result.replies[0].html).toBe(true)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('returns error message when CLI throws', () => {
|
|
195
|
+
const exec: SwitchroomExecFn = vi.fn().mockImplementation(() => {
|
|
196
|
+
throw Object.assign(new Error('not a git repo'), { stderr: 'fatal: not a git repository' })
|
|
197
|
+
})
|
|
198
|
+
const result = handleUpdateCommand(exec)
|
|
199
|
+
expect(result.replies[0].text).toContain('update failed')
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('returns no-output message when CLI returns empty', () => {
|
|
203
|
+
const exec: SwitchroomExecFn = vi.fn().mockReturnValue(' \n')
|
|
204
|
+
const result = handleUpdateCommand(exec)
|
|
205
|
+
expect(result.replies[0].text).toContain('Update complete')
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('paginates output > 3 KB', () => {
|
|
209
|
+
const bigOutput = 'x'.repeat(4000)
|
|
210
|
+
const exec: SwitchroomExecFn = vi.fn().mockReturnValue(bigOutput)
|
|
211
|
+
const result = handleUpdateCommand(exec)
|
|
212
|
+
expect(result.replies.length).toBeGreaterThan(1)
|
|
213
|
+
})
|
|
214
|
+
})
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Regression guard for the false-restart banner bug observed on
|
|
5
|
+
* 2026-04-22.
|
|
6
|
+
*
|
|
7
|
+
* Incident: klanker user received 4+ "⚡ Recovered from unexpected
|
|
8
|
+
* restart" banners in a 2-minute window while `journalctl --user -u
|
|
9
|
+
* switchroom-klanker-gateway.service` showed the process PID constant
|
|
10
|
+
* (1939077 throughout) and zero lifecycle events. The only signal
|
|
11
|
+
* correlating with the banner-bursts was a stream of 409 Conflict
|
|
12
|
+
* errors from grammY's long-poll, triggering the gateway's outer
|
|
13
|
+
* `for (let attempt = 1; ; attempt++)` retry loop to re-enter its
|
|
14
|
+
* `try { ... }` block. That try-block contains the boot-time
|
|
15
|
+
* "crash recovery" banner send, so every retry re-posted the banner.
|
|
16
|
+
*
|
|
17
|
+
* Fix: a `didOneTimeSetup` boolean guards the one-shot startup blocks
|
|
18
|
+
* (restart follow-up, crash recovery, pin sweep, setInterval for
|
|
19
|
+
* auto-fallback poll, bot-command registration). Retries bypass the
|
|
20
|
+
* guard and go straight to `run(bot)` again.
|
|
21
|
+
*
|
|
22
|
+
* These tests model the retry loop's gating contract abstractly so we
|
|
23
|
+
* can't regress without the test failing. The real retry loop lives
|
|
24
|
+
* in telegram-plugin/gateway/gateway.ts and telegram-plugin/server.ts.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Minimal model of the gated retry loop. Returns how many times
|
|
29
|
+
* each of the two code paths ran over a simulated sequence of
|
|
30
|
+
* retry attempts.
|
|
31
|
+
*/
|
|
32
|
+
function simulateGatedRetryLoop(numAttempts: number): {
|
|
33
|
+
oneTimeRuns: number;
|
|
34
|
+
pollerStartRuns: number;
|
|
35
|
+
} {
|
|
36
|
+
let didOneTimeSetup = false;
|
|
37
|
+
let oneTimeRuns = 0;
|
|
38
|
+
let pollerStartRuns = 0;
|
|
39
|
+
for (let attempt = 1; attempt <= numAttempts; attempt++) {
|
|
40
|
+
if (!didOneTimeSetup) {
|
|
41
|
+
didOneTimeSetup = true;
|
|
42
|
+
oneTimeRuns += 1; // banner send, pin sweep, setInterval, etc.
|
|
43
|
+
}
|
|
44
|
+
pollerStartRuns += 1; // grammY runner.task() — always re-tried
|
|
45
|
+
}
|
|
46
|
+
return { oneTimeRuns, pollerStartRuns };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe("gateway 409-retry banner suppression", () => {
|
|
50
|
+
it("runs one-shot setup exactly once across many 409 retries", () => {
|
|
51
|
+
// Matches the 2026-04-22 klanker incident: 4 retries observed.
|
|
52
|
+
const result = simulateGatedRetryLoop(4);
|
|
53
|
+
expect(result.oneTimeRuns).toBe(1);
|
|
54
|
+
expect(result.pollerStartRuns).toBe(4);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("runs one-shot setup exactly once on first attempt (no prior retries)", () => {
|
|
58
|
+
const result = simulateGatedRetryLoop(1);
|
|
59
|
+
expect(result.oneTimeRuns).toBe(1);
|
|
60
|
+
expect(result.pollerStartRuns).toBe(1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("still only posts once even under a long 409 storm", () => {
|
|
64
|
+
const result = simulateGatedRetryLoop(100);
|
|
65
|
+
expect(result.oneTimeRuns).toBe(1);
|
|
66
|
+
expect(result.pollerStartRuns).toBe(100);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("regression: without the guard, a naive loop would banner-spam", () => {
|
|
70
|
+
// Models the pre-fix code path. Kept as a sanity check that our
|
|
71
|
+
// simulator actually distinguishes the two shapes — i.e. the bug
|
|
72
|
+
// is real and the fix is load-bearing.
|
|
73
|
+
let oneTimeRuns = 0;
|
|
74
|
+
for (let attempt = 1; attempt <= 4; attempt++) {
|
|
75
|
+
oneTimeRuns += 1; // no guard
|
|
76
|
+
}
|
|
77
|
+
expect(oneTimeRuns).toBe(4); // matches the 4 banners the user saw
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Direct source-level guard: assert the gating variable exists in
|
|
83
|
+
* the two files that own the retry loop. Catches refactors that
|
|
84
|
+
* silently drop the guard.
|
|
85
|
+
*/
|
|
86
|
+
describe("source-level guard present", () => {
|
|
87
|
+
it("gateway.ts declares didOneTimeSetup before the retry loop", async () => {
|
|
88
|
+
const fs = await import("node:fs");
|
|
89
|
+
const src = fs.readFileSync(
|
|
90
|
+
new URL("../gateway/gateway.ts", import.meta.url),
|
|
91
|
+
"utf8",
|
|
92
|
+
);
|
|
93
|
+
expect(src).toContain("let didOneTimeSetup = false");
|
|
94
|
+
// After the runWithRetry wire-in, the gate lives inside beforeRun as
|
|
95
|
+
// `if (didOneTimeSetup) return` (early-exit). Accept either shape so
|
|
96
|
+
// this guard stays meaningful across refactors.
|
|
97
|
+
expect(
|
|
98
|
+
/if\s*\(!didOneTimeSetup\)/.test(src) ||
|
|
99
|
+
/if\s*\(didOneTimeSetup\)\s*return/.test(src),
|
|
100
|
+
).toBe(true);
|
|
101
|
+
// Sanity-check the banner still exists — fix is gating, not deleting.
|
|
102
|
+
expect(src).toContain("Recovered from unexpected restart");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// #235 Wave 3 F4: server.ts monolith removed; the source-level guard
|
|
106
|
+
// for `didOneTimeSetup` now only applies to gateway.ts (the single
|
|
107
|
+
// source of truth). The pre-F4 server.ts `it` block is gone.
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Regression guard for the 2026-04-22 banner-cascade bug. Root cause:
|
|
112
|
+
* server.ts's dual-mode probe used to call rmSync(_gatewaySocket) when
|
|
113
|
+
* Bun.connect failed, even when the failure was transient and the
|
|
114
|
+
* gateway was actually alive. Deleting the socket file orphaned the
|
|
115
|
+
* live listener — every subsequent sidecar spawn then saw
|
|
116
|
+
* existsSync===false, entered legacy monolith mode, sent a spurious
|
|
117
|
+
* "⚡ Recovered from unexpected restart" banner, and started polling
|
|
118
|
+
* the bot token. That polling conflicted with the real gateway's
|
|
119
|
+
* long-poll (→ 409 Conflict storm) and produced the banner spam the
|
|
120
|
+
* user saw while PID/systemd were unchanged.
|
|
121
|
+
*
|
|
122
|
+
* Fix: the probe logs and falls through on failure, but NEVER deletes
|
|
123
|
+
* the socket. The gateway owns its socket's lifecycle (ipc-server.ts
|
|
124
|
+
* already calls unlinkSync at startup for genuine stale-socket
|
|
125
|
+
* recovery). This test pins that contract at the source level.
|
|
126
|
+
*/
|
|
127
|
+
describe("server.ts dual-mode probe must not delete live gateway socket", () => {
|
|
128
|
+
it("never calls rmSync on the gateway socket path in the probe block", async () => {
|
|
129
|
+
const fs = await import("node:fs");
|
|
130
|
+
const src = fs.readFileSync(
|
|
131
|
+
new URL("../server.ts", import.meta.url),
|
|
132
|
+
"utf8",
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// Isolate the dual-mode block. We key off the block's distinctive
|
|
136
|
+
// comment header so a rename/move doesn't silently neuter the check.
|
|
137
|
+
// After Wave 3 F4 (server.ts monolith deleted), the dual-mode block
|
|
138
|
+
// is essentially the entire file body, so the slice runs to EOF.
|
|
139
|
+
const blockStart = src.indexOf("─── Dual-mode detection ───");
|
|
140
|
+
expect(blockStart).toBeGreaterThan(-1);
|
|
141
|
+
const block = src.slice(blockStart);
|
|
142
|
+
|
|
143
|
+
// The probe must not attempt to delete the gateway socket under
|
|
144
|
+
// any circumstance. rmSync / unlinkSync against _gatewaySocket are
|
|
145
|
+
// both banned here — the gateway owns lifecycle.
|
|
146
|
+
expect(block).not.toMatch(/rmSync\s*\(\s*_gatewaySocket/);
|
|
147
|
+
expect(block).not.toMatch(/unlinkSync\s*\(\s*_gatewaySocket/);
|
|
148
|
+
|
|
149
|
+
// The probe must still run (we haven't accidentally removed the
|
|
150
|
+
// liveness check entirely and reverted to "existsSync → bridge").
|
|
151
|
+
expect(block).toContain("Bun.connect");
|
|
152
|
+
expect(block).toContain("_gatewayLive = true");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("documents the no-delete posture in a comment so future edits understand why", async () => {
|
|
156
|
+
const fs = await import("node:fs");
|
|
157
|
+
const src = fs.readFileSync(
|
|
158
|
+
new URL("../server.ts", import.meta.url),
|
|
159
|
+
"utf8",
|
|
160
|
+
);
|
|
161
|
+
// Keep this loose — intent, not exact wording. Any comment in the
|
|
162
|
+
// dual-mode block mentioning "rmSync" + "never" (or equivalent)
|
|
163
|
+
// satisfies the guard. We pin at least the rmSync keyword so a
|
|
164
|
+
// future maintainer grepping for the symbol lands here.
|
|
165
|
+
const blockStart = src.indexOf("─── Dual-mode detection ───");
|
|
166
|
+
const blockEnd = src.indexOf(
|
|
167
|
+
"import { type DraftStreamHandle }",
|
|
168
|
+
blockStart,
|
|
169
|
+
);
|
|
170
|
+
const block = src.slice(blockStart, blockEnd);
|
|
171
|
+
expect(block).toMatch(/never rmSync/i);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural pin for the boot-time turn-active marker cleanup
|
|
3
|
+
* (regression coverage for the 2026-05-01 flap-loop incident).
|
|
4
|
+
*
|
|
5
|
+
* What broke: an interrupted turn left `<stateDir>/turn-active.json`
|
|
6
|
+
* on disk. The next gateway boot saw the orphan; the watchdog read its
|
|
7
|
+
* mtime, computed `age >= TURN_HANG_SECS` (300s default), and
|
|
8
|
+
* restarted the agent — which killed the gateway mid-cleanup, leaving
|
|
9
|
+
* the marker again. Result: 2-min flap loop, observed live on `clerk`.
|
|
10
|
+
*
|
|
11
|
+
* The fix: gateway calls `removeTurnActiveMarker(STATE_DIR)` once at
|
|
12
|
+
* boot, inside the `!didOneTimeSetup` block (so it runs only on the
|
|
13
|
+
* first poll-loop entry, not on every retry attempt). By definition
|
|
14
|
+
* no turn can be in flight when the gateway just started — any
|
|
15
|
+
* leftover marker is from a turn that didn't complete.
|
|
16
|
+
*
|
|
17
|
+
* The unit tests in `turn-active-marker.test.ts` already cover the
|
|
18
|
+
* primitive's behaviour. This test pins the *call site* — fails
|
|
19
|
+
* loudly if a future refactor moves or removes the boot-time clear.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { describe, it, expect } from 'vitest'
|
|
23
|
+
import { readFileSync } from 'node:fs'
|
|
24
|
+
import { fileURLToPath } from 'node:url'
|
|
25
|
+
import { dirname, resolve } from 'node:path'
|
|
26
|
+
|
|
27
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
28
|
+
const GATEWAY_SRC = readFileSync(
|
|
29
|
+
resolve(__dirname, '..', 'gateway', 'gateway.ts'),
|
|
30
|
+
'utf8',
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
describe('gateway boot — clear stale turn-active marker', () => {
|
|
34
|
+
it('removeTurnActiveMarker is called exactly once inside the !didOneTimeSetup block', () => {
|
|
35
|
+
// Locate the one-time setup block. It's gated on `!didOneTimeSetup`
|
|
36
|
+
// and runs after the first successful `bot.api.getMe()` so the
|
|
37
|
+
// clear only happens once per process lifetime.
|
|
38
|
+
const setupBlockStart = GATEWAY_SRC.indexOf('if (!didOneTimeSetup)')
|
|
39
|
+
expect(setupBlockStart).toBeGreaterThan(0)
|
|
40
|
+
|
|
41
|
+
// The clear should land near the top of that block — before
|
|
42
|
+
// pin-sweep, before any boot-card emission. Bound the search
|
|
43
|
+
// window to ~5KB so we don't pick up the unrelated
|
|
44
|
+
// `removeTurnActiveMarker` call in the onTurnComplete handler
|
|
45
|
+
// way down at the bottom of the file.
|
|
46
|
+
const setupWindow = GATEWAY_SRC.slice(setupBlockStart, setupBlockStart + 5000)
|
|
47
|
+
const clearMatches = setupWindow.match(/removeTurnActiveMarker\s*\(\s*STATE_DIR\s*\)/g) ?? []
|
|
48
|
+
expect(clearMatches.length).toBe(1)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('clear is wrapped in try/catch so a disk error never blocks boot', () => {
|
|
52
|
+
// The clear is best-effort — a transient EBUSY or permission glitch
|
|
53
|
+
// must not prevent the gateway from coming up. Pin the try-wrapping
|
|
54
|
+
// to make sure a future refactor doesn't drop it.
|
|
55
|
+
const setupBlockStart = GATEWAY_SRC.indexOf('if (!didOneTimeSetup)')
|
|
56
|
+
const setupWindow = GATEWAY_SRC.slice(setupBlockStart, setupBlockStart + 5000)
|
|
57
|
+
expect(setupWindow).toMatch(/try\s*\{\s*removeTurnActiveMarker\(STATE_DIR\)\s*\}\s*catch/)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('clear runs before the boot-time pin sweep (not after)', () => {
|
|
61
|
+
// Ordering pin: pin sweep can be slow (many chats × API calls).
|
|
62
|
+
// Clearing the marker first means the watchdog sees a clean slate
|
|
63
|
+
// immediately, even if pin sweep takes 30s+ to finish.
|
|
64
|
+
const setupBlockStart = GATEWAY_SRC.indexOf('if (!didOneTimeSetup)')
|
|
65
|
+
const setupWindow = GATEWAY_SRC.slice(setupBlockStart, setupBlockStart + 5000)
|
|
66
|
+
const clearIdx = setupWindow.indexOf('removeTurnActiveMarker(STATE_DIR)')
|
|
67
|
+
const pinSweepIdx = setupWindow.indexOf('Boot-time pin sweep')
|
|
68
|
+
expect(clearIdx).toBeGreaterThan(0)
|
|
69
|
+
expect(pinSweepIdx).toBeGreaterThan(0)
|
|
70
|
+
expect(clearIdx).toBeLessThan(pinSweepIdx)
|
|
71
|
+
})
|
|
72
|
+
})
|