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,151 @@
|
|
|
1
|
+
// === Gateway -> Bridge (Client) messages ===
|
|
2
|
+
|
|
3
|
+
export interface InboundMessage {
|
|
4
|
+
type: "inbound";
|
|
5
|
+
chatId: string;
|
|
6
|
+
threadId?: number;
|
|
7
|
+
messageId: number;
|
|
8
|
+
user: string;
|
|
9
|
+
userId: number;
|
|
10
|
+
ts: number;
|
|
11
|
+
text: string;
|
|
12
|
+
imagePath?: string;
|
|
13
|
+
attachment?: { fileId: string; mimeType: string; fileName?: string };
|
|
14
|
+
meta: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface PermissionEvent {
|
|
18
|
+
type: "permission";
|
|
19
|
+
requestId: string;
|
|
20
|
+
behavior: "allow" | "deny";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface StatusEvent {
|
|
24
|
+
type: "status";
|
|
25
|
+
status: "agent_down" | "agent_connected" | "gateway_shutting_down";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ToolCallResult {
|
|
29
|
+
type: "tool_call_result";
|
|
30
|
+
id: string;
|
|
31
|
+
success: boolean;
|
|
32
|
+
result?: unknown;
|
|
33
|
+
error?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ScheduleRestartResult {
|
|
37
|
+
type: "schedule_restart_result";
|
|
38
|
+
success: boolean;
|
|
39
|
+
restartedImmediately?: boolean;
|
|
40
|
+
waitingForTurn?: boolean;
|
|
41
|
+
error?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type GatewayToClient =
|
|
45
|
+
| InboundMessage
|
|
46
|
+
| PermissionEvent
|
|
47
|
+
| StatusEvent
|
|
48
|
+
| ToolCallResult
|
|
49
|
+
| ScheduleRestartResult;
|
|
50
|
+
|
|
51
|
+
// === Bridge (Client) -> Gateway messages ===
|
|
52
|
+
|
|
53
|
+
export interface RegisterMessage {
|
|
54
|
+
type: "register";
|
|
55
|
+
agentName: string;
|
|
56
|
+
topicId?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ToolCallMessage {
|
|
60
|
+
type: "tool_call";
|
|
61
|
+
id: string;
|
|
62
|
+
tool: string;
|
|
63
|
+
args: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface SessionEventForward {
|
|
67
|
+
type: "session_event";
|
|
68
|
+
event: Record<string, unknown>;
|
|
69
|
+
chatId: string;
|
|
70
|
+
threadId?: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface PermissionRequestForward {
|
|
74
|
+
type: "permission_request";
|
|
75
|
+
requestId: string;
|
|
76
|
+
toolName: string;
|
|
77
|
+
description: string;
|
|
78
|
+
inputPreview: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface HeartbeatMessage {
|
|
82
|
+
type: "heartbeat";
|
|
83
|
+
agentName: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface ScheduleRestartMessage {
|
|
87
|
+
type: "schedule_restart";
|
|
88
|
+
agentName: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Forwarded from bridge → gateway when session-tail detects a Claude API
|
|
93
|
+
* error in the JSONL transcript (Phase 4b).
|
|
94
|
+
*/
|
|
95
|
+
export interface OperatorEventForward {
|
|
96
|
+
type: "operator_event";
|
|
97
|
+
/** OperatorEventKind — kept as string to avoid cross-package type dep. */
|
|
98
|
+
kind: string;
|
|
99
|
+
agent: string;
|
|
100
|
+
detail: string;
|
|
101
|
+
chatId: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Forwarded from bridge → gateway when PTY-tail extracts updated reply
|
|
106
|
+
* text from Claude Code's TUI rendering. The gateway routes the text
|
|
107
|
+
* through `handlePtyPartial` → draft-stream so the user sees the model's
|
|
108
|
+
* reply assemble character-by-character (Claude.ai-style streaming).
|
|
109
|
+
*
|
|
110
|
+
* Sent by bridge.ts's `startPtyTail({onPartial})` callback. The bridge
|
|
111
|
+
* doesn't know the chat id — the gateway resolves it from
|
|
112
|
+
* `currentSessionChatId`, which is set when the bridge forwards the
|
|
113
|
+
* matching `enqueue` session event.
|
|
114
|
+
*
|
|
115
|
+
* No throttle on the wire: PTY-tail's onPartial already coalesces at
|
|
116
|
+
* ~150 ms. Same pattern as session_event forwarding.
|
|
117
|
+
*/
|
|
118
|
+
export interface PtyPartialForward {
|
|
119
|
+
type: "pty_partial";
|
|
120
|
+
/** Extracted reply text snapshot. Up to ~4096 chars (Telegram limit). */
|
|
121
|
+
text: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Legacy `update_placeholder` IPC from `vendor/hindsight-memory`'s
|
|
126
|
+
* `recall.py` hook. The placeholder UX (`🔵 thinking`, `📚 recalling
|
|
127
|
+
* memories`, `💭 thinking`) was removed in PR #553 PR 5 — the gateway no
|
|
128
|
+
* longer registers a real handler for these. We still accept the wire
|
|
129
|
+
* shape so the validator does NOT reject + log "invalid IPC message
|
|
130
|
+
* shape" on every recall.py invocation, and so the message dispatches to
|
|
131
|
+
* a no-op stub instead of falling through to the default-case warning.
|
|
132
|
+
*
|
|
133
|
+
* Important: we cannot edit `vendor/hindsight-memory/scripts/recall.py`
|
|
134
|
+
* (vendored), so this soft-accept is the correct compatibility shim.
|
|
135
|
+
*/
|
|
136
|
+
export interface UpdatePlaceholderMessage {
|
|
137
|
+
type: "update_placeholder";
|
|
138
|
+
chatId: string;
|
|
139
|
+
text: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export type ClientToGateway =
|
|
143
|
+
| RegisterMessage
|
|
144
|
+
| ToolCallMessage
|
|
145
|
+
| SessionEventForward
|
|
146
|
+
| PermissionRequestForward
|
|
147
|
+
| HeartbeatMessage
|
|
148
|
+
| ScheduleRestartMessage
|
|
149
|
+
| OperatorEventForward
|
|
150
|
+
| PtyPartialForward
|
|
151
|
+
| UpdatePlaceholderMessage;
|
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import { renameSync, unlinkSync } from "fs";
|
|
2
|
+
import type {
|
|
3
|
+
ClientToGateway,
|
|
4
|
+
GatewayToClient,
|
|
5
|
+
HeartbeatMessage,
|
|
6
|
+
OperatorEventForward,
|
|
7
|
+
PermissionRequestForward,
|
|
8
|
+
PtyPartialForward,
|
|
9
|
+
RegisterMessage,
|
|
10
|
+
ScheduleRestartMessage,
|
|
11
|
+
SessionEventForward,
|
|
12
|
+
ToolCallMessage,
|
|
13
|
+
ToolCallResult,
|
|
14
|
+
} from "./ipc-protocol.js";
|
|
15
|
+
|
|
16
|
+
export interface IpcServerOptions {
|
|
17
|
+
socketPath: string;
|
|
18
|
+
onClientRegistered: (client: IpcClient) => void;
|
|
19
|
+
onClientDisconnected: (client: IpcClient) => void;
|
|
20
|
+
onToolCall: (client: IpcClient, msg: ToolCallMessage) => Promise<ToolCallResult>;
|
|
21
|
+
onSessionEvent: (client: IpcClient, msg: SessionEventForward) => void;
|
|
22
|
+
onPermissionRequest: (client: IpcClient, msg: PermissionRequestForward) => void;
|
|
23
|
+
onHeartbeat: (client: IpcClient, msg: HeartbeatMessage) => void;
|
|
24
|
+
onScheduleRestart: (client: IpcClient, msg: ScheduleRestartMessage) => void;
|
|
25
|
+
onOperatorEvent?: (client: IpcClient, msg: OperatorEventForward) => void;
|
|
26
|
+
/**
|
|
27
|
+
* Forwarded PTY-tail partial — the latest extracted reply text from
|
|
28
|
+
* Claude Code's TUI rendering. Optional: gateways without streaming
|
|
29
|
+
* configured (or in test fixtures) can omit this and pty_partial
|
|
30
|
+
* messages will be silently dropped at dispatch.
|
|
31
|
+
*/
|
|
32
|
+
onPtyPartial?: (client: IpcClient, msg: PtyPartialForward) => void;
|
|
33
|
+
log?: (msg: string) => void;
|
|
34
|
+
/**
|
|
35
|
+
* How long (in ms) to wait without a heartbeat before force-closing the
|
|
36
|
+
* client connection. The bridge sends heartbeats every 5s by default, so
|
|
37
|
+
* a safe threshold is 3–5× that (15–30s). Set to 0 to disable the watchdog.
|
|
38
|
+
* Defaults to 30 000 ms (30 s).
|
|
39
|
+
*
|
|
40
|
+
* Issue #71: without this, a bridge that crashes or hangs silently stays in
|
|
41
|
+
* the agentIndex and new inbound Telegram messages are never delivered to the
|
|
42
|
+
* new claude process that reconnects after a restart.
|
|
43
|
+
*/
|
|
44
|
+
heartbeatTimeoutMs?: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface IpcClient {
|
|
48
|
+
id: string;
|
|
49
|
+
agentName: string | null;
|
|
50
|
+
topicId: number | null;
|
|
51
|
+
send(msg: GatewayToClient): void;
|
|
52
|
+
close(): void;
|
|
53
|
+
isAlive(): boolean;
|
|
54
|
+
lastHeartbeat: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface IpcServer {
|
|
58
|
+
sendToAgent(agentName: string, msg: GatewayToClient): boolean;
|
|
59
|
+
sendToTopic(topicId: number, msg: GatewayToClient): boolean;
|
|
60
|
+
broadcast(msg: GatewayToClient): void;
|
|
61
|
+
getClient(agentName: string): IpcClient | undefined;
|
|
62
|
+
clientCount(): number;
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type SocketData = { clientId: string; buffer: string };
|
|
67
|
+
|
|
68
|
+
/** Max buffer size per client (1MB). Protects against a client flooding
|
|
69
|
+
* data without newline delimiters, which would cause unbounded memory growth. */
|
|
70
|
+
const MAX_BUFFER_SIZE = 1024 * 1024;
|
|
71
|
+
|
|
72
|
+
/** Allowlist of OperatorEventKind values that can arrive over IPC. Mirrors
|
|
73
|
+
* the union in `telegram-plugin/operator-events.ts` — kept as a literal Set
|
|
74
|
+
* here so the validator has zero cross-package type dependencies. If the
|
|
75
|
+
* taxonomy grows, update both places. */
|
|
76
|
+
const VALID_OPERATOR_KINDS = new Set([
|
|
77
|
+
"credentials-expired",
|
|
78
|
+
"credentials-invalid",
|
|
79
|
+
"credit-exhausted",
|
|
80
|
+
"quota-exhausted",
|
|
81
|
+
"rate-limited",
|
|
82
|
+
"agent-crashed",
|
|
83
|
+
"agent-restarted-unexpectedly",
|
|
84
|
+
"unknown-4xx",
|
|
85
|
+
"unknown-5xx",
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
/** Same regex as `assertSafeAgentName` and the op:* callback handler in
|
|
89
|
+
* gateway.ts — keeps every entry-point that touches an agent name on the
|
|
90
|
+
* same shape. */
|
|
91
|
+
const AGENT_NAME_RE = /^[a-z0-9][a-z0-9_-]{0,50}$/;
|
|
92
|
+
|
|
93
|
+
/** Cap for the `detail` field on an operator_event message. Long enough to
|
|
94
|
+
* carry a typical Anthropic error body, short enough that a misbehaving
|
|
95
|
+
* bridge can't fill the gateway log. */
|
|
96
|
+
const OPERATOR_EVENT_DETAIL_MAX = 1000;
|
|
97
|
+
|
|
98
|
+
/** Validate that a parsed JSON object looks like a legitimate ClientToGateway
|
|
99
|
+
* message. Returns false for malformed or unexpected shapes. This prevents
|
|
100
|
+
* a rogue process on the same Unix socket from injecting arbitrary payloads.
|
|
101
|
+
*
|
|
102
|
+
* Exported so tests can exercise every field-level rejection independently
|
|
103
|
+
* without spinning up a real Unix-socket server. */
|
|
104
|
+
export function validateClientMessage(msg: unknown): msg is ClientToGateway {
|
|
105
|
+
if (typeof msg !== "object" || msg === null || !("type" in msg)) return false;
|
|
106
|
+
const m = msg as Record<string, unknown>;
|
|
107
|
+
switch (m.type) {
|
|
108
|
+
case "register":
|
|
109
|
+
// Reject the literal "default" — that's the legacy fallback used
|
|
110
|
+
// by anonymous bridges (see #430). A correctly-configured bridge
|
|
111
|
+
// sets SWITCHROOM_AGENT_NAME to the real agent name; a bridge
|
|
112
|
+
// sending "default" is either an older binary or a stray
|
|
113
|
+
// claude-code session and would crosstalk into another agent's
|
|
114
|
+
// chat. Server-side rejection is defence in depth — the bridge
|
|
115
|
+
// refuses to register without a name first.
|
|
116
|
+
return typeof m.agentName === "string"
|
|
117
|
+
&& m.agentName.length > 0
|
|
118
|
+
&& m.agentName !== "default"
|
|
119
|
+
&& m.agentName.length <= 128
|
|
120
|
+
&& (m.topicId === undefined
|
|
121
|
+
|| (typeof m.topicId === "number"
|
|
122
|
+
&& Number.isInteger(m.topicId)
|
|
123
|
+
&& Number.isFinite(m.topicId)));
|
|
124
|
+
case "tool_call":
|
|
125
|
+
return typeof m.id === "string" && m.id.length > 0
|
|
126
|
+
&& typeof m.tool === "string" && m.tool.length > 0
|
|
127
|
+
&& typeof m.args === "object" && m.args !== null;
|
|
128
|
+
case "session_event":
|
|
129
|
+
return typeof m.event === "object" && m.event !== null
|
|
130
|
+
&& typeof m.chatId === "string";
|
|
131
|
+
case "permission_request":
|
|
132
|
+
return typeof m.requestId === "string" && m.requestId.length > 0
|
|
133
|
+
&& typeof m.toolName === "string"
|
|
134
|
+
&& typeof m.description === "string"
|
|
135
|
+
&& typeof m.inputPreview === "string";
|
|
136
|
+
case "heartbeat":
|
|
137
|
+
return typeof m.agentName === "string" && m.agentName.length > 0;
|
|
138
|
+
case "schedule_restart":
|
|
139
|
+
return typeof m.agentName === "string" && m.agentName.length > 0;
|
|
140
|
+
case "operator_event":
|
|
141
|
+
return typeof m.kind === "string"
|
|
142
|
+
&& VALID_OPERATOR_KINDS.has(m.kind as string)
|
|
143
|
+
&& typeof m.agent === "string"
|
|
144
|
+
&& AGENT_NAME_RE.test(m.agent as string)
|
|
145
|
+
&& typeof m.detail === "string"
|
|
146
|
+
&& (m.detail as string).length <= OPERATOR_EVENT_DETAIL_MAX
|
|
147
|
+
&& typeof m.chatId === "string";
|
|
148
|
+
case "pty_partial":
|
|
149
|
+
// Extracted reply text from PTY-tail. May be empty (the extractor
|
|
150
|
+
// returns empty strings for "no text yet" snapshots — gateway
|
|
151
|
+
// handler dedups on lastPtyPreviewByChat). Capped at 8192 to
|
|
152
|
+
// give some headroom over Telegram's 4096-char wire limit while
|
|
153
|
+
// still bounding buffer growth from a runaway extractor.
|
|
154
|
+
return typeof m.text === "string"
|
|
155
|
+
&& (m.text as string).length <= 8192;
|
|
156
|
+
case "update_placeholder":
|
|
157
|
+
// Legacy recall.py IPC. Accepted as a valid wire shape so the
|
|
158
|
+
// validator doesn't log "invalid IPC message shape" on every
|
|
159
|
+
// recall hook fire; dispatched to a no-op handler in
|
|
160
|
+
// `handleMessage` below. See `UpdatePlaceholderMessage` doc in
|
|
161
|
+
// ipc-protocol.ts for context.
|
|
162
|
+
return typeof m.chatId === "string" && (m.chatId as string).length > 0
|
|
163
|
+
&& typeof m.text === "string" && (m.text as string).length <= 8192;
|
|
164
|
+
default:
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function createIpcServer(options: IpcServerOptions): IpcServer {
|
|
170
|
+
const {
|
|
171
|
+
socketPath,
|
|
172
|
+
onClientRegistered,
|
|
173
|
+
onClientDisconnected,
|
|
174
|
+
onToolCall,
|
|
175
|
+
onSessionEvent,
|
|
176
|
+
onPermissionRequest,
|
|
177
|
+
onHeartbeat,
|
|
178
|
+
onScheduleRestart,
|
|
179
|
+
onOperatorEvent,
|
|
180
|
+
onPtyPartial,
|
|
181
|
+
log = () => {},
|
|
182
|
+
heartbeatTimeoutMs = 30_000,
|
|
183
|
+
} = options;
|
|
184
|
+
|
|
185
|
+
// Race-safe cleanup: rename the live socket to a .bak sidecar rather than
|
|
186
|
+
// unlinking it. If the old gateway's delayed shutdown-cleanup later tries to
|
|
187
|
+
// rename again, it targets .bak (already-moved) not the freshly-bound file.
|
|
188
|
+
// Previous unlinkSync-based cleanup had a race where an in-flight old-gateway
|
|
189
|
+
// cleanup could delete the new gateway's just-bound socket inode, leaving the
|
|
190
|
+
// server listening but the filesystem entry gone (orphaned socket).
|
|
191
|
+
try { renameSync(socketPath, socketPath + ".bak"); } catch {}
|
|
192
|
+
// Now that we're about to bind fresh, stale .bak from a prior generation
|
|
193
|
+
// is safe to remove — no one is using it (we haven't bound yet).
|
|
194
|
+
try { unlinkSync(socketPath + ".bak"); } catch {}
|
|
195
|
+
|
|
196
|
+
const clients = new Set<IpcClient>();
|
|
197
|
+
const agentIndex = new Map<string, IpcClient>();
|
|
198
|
+
const topicIndex = new Map<number, IpcClient>();
|
|
199
|
+
|
|
200
|
+
/** Per-client dedup set for the legacy `update_placeholder` log line —
|
|
201
|
+
* one log entry per connection, not per message. Cleared on disconnect. */
|
|
202
|
+
const loggedLegacyUpdatePlaceholder = new Set<string>();
|
|
203
|
+
|
|
204
|
+
function removeClient(client: IpcClient & { _socket: ReturnType<typeof Bun.listen> extends infer S ? any : never }) {
|
|
205
|
+
clients.delete(client);
|
|
206
|
+
if (client.agentName) agentIndex.delete(client.agentName);
|
|
207
|
+
if (client.topicId != null) topicIndex.delete(client.topicId);
|
|
208
|
+
loggedLegacyUpdatePlaceholder.delete(client.id);
|
|
209
|
+
onClientDisconnected(client);
|
|
210
|
+
log(`client disconnected: ${client.id} (agent=${client.agentName})`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Local alias of the exported validator — kept as a named reference so
|
|
214
|
+
// the call site below reads the same as before.
|
|
215
|
+
const validateMessage = validateClientMessage;
|
|
216
|
+
|
|
217
|
+
function processBuffer(
|
|
218
|
+
socket: import("bun").Socket<SocketData>,
|
|
219
|
+
) {
|
|
220
|
+
const lines = socket.data.buffer.split("\n");
|
|
221
|
+
socket.data.buffer = lines.pop()!;
|
|
222
|
+
|
|
223
|
+
for (const line of lines) {
|
|
224
|
+
if (!line.trim()) continue;
|
|
225
|
+
try {
|
|
226
|
+
const parsed: unknown = JSON.parse(line);
|
|
227
|
+
if (!validateMessage(parsed)) {
|
|
228
|
+
log(`invalid IPC message shape from client: ${line.slice(0, 200)}`);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
const client = clientBySocketId.get(socket.data.clientId);
|
|
232
|
+
if (client) handleMessage(client, parsed);
|
|
233
|
+
} catch {
|
|
234
|
+
log(`bad JSON from client: ${line.slice(0, 200)}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function handleMessage(client: IpcClientImpl, msg: ClientToGateway) {
|
|
240
|
+
switch (msg.type) {
|
|
241
|
+
case "register":
|
|
242
|
+
handleRegister(client, msg);
|
|
243
|
+
break;
|
|
244
|
+
case "tool_call":
|
|
245
|
+
handleToolCall(client, msg);
|
|
246
|
+
break;
|
|
247
|
+
case "session_event":
|
|
248
|
+
onSessionEvent(client, msg);
|
|
249
|
+
break;
|
|
250
|
+
case "permission_request":
|
|
251
|
+
onPermissionRequest(client, msg);
|
|
252
|
+
break;
|
|
253
|
+
case "heartbeat":
|
|
254
|
+
client.lastHeartbeat = Date.now();
|
|
255
|
+
onHeartbeat(client, msg);
|
|
256
|
+
break;
|
|
257
|
+
case "schedule_restart":
|
|
258
|
+
onScheduleRestart(client, msg);
|
|
259
|
+
break;
|
|
260
|
+
case "operator_event":
|
|
261
|
+
if (onOperatorEvent) onOperatorEvent(client, msg as OperatorEventForward);
|
|
262
|
+
break;
|
|
263
|
+
case "pty_partial":
|
|
264
|
+
if (onPtyPartial) onPtyPartial(client, msg as PtyPartialForward);
|
|
265
|
+
break;
|
|
266
|
+
case "update_placeholder":
|
|
267
|
+
// Legacy recall.py IPC — placeholder UX was removed in #553 PR 5.
|
|
268
|
+
// Soft-accepted so recall.py keeps working without modifying
|
|
269
|
+
// vendored code; logged once per client connection so the gateway
|
|
270
|
+
// log doesn't fill with one line per hook fire.
|
|
271
|
+
if (!loggedLegacyUpdatePlaceholder.has(client.id)) {
|
|
272
|
+
loggedLegacyUpdatePlaceholder.add(client.id);
|
|
273
|
+
log(`legacy update_placeholder ignored (client=${client.id}, agent=${client.agentName ?? "anonymous"})`);
|
|
274
|
+
}
|
|
275
|
+
break;
|
|
276
|
+
default:
|
|
277
|
+
log(`unknown IPC message type from client ${client.id}: ${(msg as any).type}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function handleRegister(client: IpcClientImpl, msg: RegisterMessage) {
|
|
282
|
+
// Defence in depth for #430. The bridge refuses to register
|
|
283
|
+
// without SWITCHROOM_AGENT_NAME (set in start.sh per agent), but
|
|
284
|
+
// an older bridge or a third-party caller could still send the
|
|
285
|
+
// string "default" — which crosstalks into whichever agent's
|
|
286
|
+
// gateway happens to accept the connection. Reject server-side
|
|
287
|
+
// so the gateway never confuses an anonymous client for the
|
|
288
|
+
// agent it was launched to serve. The expected switchroom
|
|
289
|
+
// contract is exactly one agent name per gateway socket; any
|
|
290
|
+
// mismatch is an outright bug, not a transient.
|
|
291
|
+
if (msg.agentName === "default") {
|
|
292
|
+
log(
|
|
293
|
+
`rejecting register: agentName="default" — anonymous bridges are not allowed (close+drop client=${client.id})`,
|
|
294
|
+
);
|
|
295
|
+
try {
|
|
296
|
+
client.close();
|
|
297
|
+
} catch {
|
|
298
|
+
/* nothing to do */
|
|
299
|
+
}
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (client.agentName) agentIndex.delete(client.agentName);
|
|
304
|
+
if (client.topicId != null) topicIndex.delete(client.topicId);
|
|
305
|
+
|
|
306
|
+
client.agentName = msg.agentName;
|
|
307
|
+
client.topicId = msg.topicId ?? null;
|
|
308
|
+
|
|
309
|
+
agentIndex.set(msg.agentName, client);
|
|
310
|
+
if (msg.topicId != null) topicIndex.set(msg.topicId, client);
|
|
311
|
+
|
|
312
|
+
log(`registered agent=${msg.agentName} topicId=${msg.topicId ?? "none"}`);
|
|
313
|
+
onClientRegistered(client);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function handleToolCall(client: IpcClientImpl, msg: ToolCallMessage) {
|
|
317
|
+
onToolCall(client, msg).then(
|
|
318
|
+
(result) => client.send(result),
|
|
319
|
+
(err) => client.send({
|
|
320
|
+
type: "tool_call_result",
|
|
321
|
+
id: msg.id,
|
|
322
|
+
success: false,
|
|
323
|
+
error: err instanceof Error ? err.message : String(err),
|
|
324
|
+
}),
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
class IpcClientImpl implements IpcClient {
|
|
329
|
+
id: string;
|
|
330
|
+
agentName: string | null = null;
|
|
331
|
+
topicId: number | null = null;
|
|
332
|
+
lastHeartbeat: number = Date.now();
|
|
333
|
+
_socket: import("bun").Socket<SocketData>;
|
|
334
|
+
private _closed = false;
|
|
335
|
+
|
|
336
|
+
constructor(socket: import("bun").Socket<SocketData>) {
|
|
337
|
+
this.id = socket.data.clientId;
|
|
338
|
+
this._socket = socket;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
send(msg: GatewayToClient): void {
|
|
342
|
+
if (this._closed) return;
|
|
343
|
+
this._socket.write(JSON.stringify(msg) + "\n");
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
close(): void {
|
|
347
|
+
if (this._closed) return;
|
|
348
|
+
this._closed = true;
|
|
349
|
+
this._socket.end();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
isAlive(): boolean {
|
|
353
|
+
return !this._closed;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const clientBySocketId = new Map<string, IpcClientImpl>();
|
|
358
|
+
|
|
359
|
+
const server = Bun.listen<SocketData>({
|
|
360
|
+
unix: socketPath,
|
|
361
|
+
socket: {
|
|
362
|
+
open(socket) {
|
|
363
|
+
const clientId = crypto.randomUUID();
|
|
364
|
+
socket.data = { clientId, buffer: "" };
|
|
365
|
+
const client = new IpcClientImpl(socket);
|
|
366
|
+
clients.add(client);
|
|
367
|
+
clientBySocketId.set(clientId, client);
|
|
368
|
+
log(`client connected: ${clientId}`);
|
|
369
|
+
},
|
|
370
|
+
data(socket, data) {
|
|
371
|
+
socket.data.buffer += data.toString();
|
|
372
|
+
if (socket.data.buffer.length > MAX_BUFFER_SIZE) {
|
|
373
|
+
log(`client ${socket.data.clientId} exceeded max buffer size (${MAX_BUFFER_SIZE} bytes), dropping connection`);
|
|
374
|
+
socket.end();
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
processBuffer(socket);
|
|
378
|
+
},
|
|
379
|
+
close(socket) {
|
|
380
|
+
const client = clientBySocketId.get(socket.data.clientId);
|
|
381
|
+
if (client) {
|
|
382
|
+
clientBySocketId.delete(socket.data.clientId);
|
|
383
|
+
removeClient(client);
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
drain() {},
|
|
387
|
+
error(socket, err) {
|
|
388
|
+
log(`socket error: ${err.message}`);
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
log(`listening on ${socketPath}`);
|
|
394
|
+
|
|
395
|
+
// ─── Heartbeat watchdog (issue #71) ─────────────────────────────────────
|
|
396
|
+
// The IPC client sends a heartbeat every `heartbeatIntervalMs` (default 5s).
|
|
397
|
+
// If a client's `lastHeartbeat` is older than `heartbeatTimeoutMs` (default
|
|
398
|
+
// 30s), the TCP socket is likely wedged (process crashed but the socket fd
|
|
399
|
+
// was never cleanly closed, or the OS hasn't yet delivered the FIN). Force-
|
|
400
|
+
// close those connections so:
|
|
401
|
+
// 1. The gateway clears the stale agentIndex entry immediately.
|
|
402
|
+
// 2. Inbound Telegram messages are not silently dropped into a black hole.
|
|
403
|
+
// 3. The real bridge process (which may already be reconnecting) gets its
|
|
404
|
+
// fresh register() handled rather than silently shadowed by the stale
|
|
405
|
+
// entry (handleRegister does replace-not-reject, so this is belt-and-
|
|
406
|
+
// suspenders — but eviction is cleaner).
|
|
407
|
+
let watchdogTimer: ReturnType<typeof setInterval> | null = null;
|
|
408
|
+
if (heartbeatTimeoutMs > 0) {
|
|
409
|
+
// Poll at half the timeout so we catch a wedged client within one interval.
|
|
410
|
+
const watchdogInterval = Math.max(1000, Math.floor(heartbeatTimeoutMs / 2));
|
|
411
|
+
watchdogTimer = setInterval(() => {
|
|
412
|
+
const now = Date.now();
|
|
413
|
+
for (const client of clients) {
|
|
414
|
+
if (!client.isAlive()) continue;
|
|
415
|
+
// Only evict clients that have registered (agentName set). Unregistered
|
|
416
|
+
// connections that just opened are excluded — they haven't had a chance
|
|
417
|
+
// to send their first heartbeat yet.
|
|
418
|
+
if (client.agentName === null) continue;
|
|
419
|
+
const age = now - client.lastHeartbeat;
|
|
420
|
+
if (age > heartbeatTimeoutMs) {
|
|
421
|
+
log(
|
|
422
|
+
`heartbeat watchdog: evicting stale client agent=${client.agentName} id=${client.id} ` +
|
|
423
|
+
`lastHeartbeat=${age}ms ago (threshold=${heartbeatTimeoutMs}ms)`,
|
|
424
|
+
);
|
|
425
|
+
client.close();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}, watchdogInterval);
|
|
429
|
+
// Unref so the watchdog doesn't prevent clean process exit.
|
|
430
|
+
if (typeof (watchdogTimer as any)?.unref === "function") {
|
|
431
|
+
(watchdogTimer as any).unref();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const ipcServer: IpcServer = {
|
|
436
|
+
sendToAgent(agentName: string, msg: GatewayToClient): boolean {
|
|
437
|
+
const client = agentIndex.get(agentName);
|
|
438
|
+
if (!client || !client.isAlive()) return false;
|
|
439
|
+
client.send(msg);
|
|
440
|
+
return true;
|
|
441
|
+
},
|
|
442
|
+
|
|
443
|
+
sendToTopic(topicId: number, msg: GatewayToClient): boolean {
|
|
444
|
+
const client = topicIndex.get(topicId);
|
|
445
|
+
if (!client || !client.isAlive()) return false;
|
|
446
|
+
client.send(msg);
|
|
447
|
+
return true;
|
|
448
|
+
},
|
|
449
|
+
|
|
450
|
+
broadcast(msg: GatewayToClient): void {
|
|
451
|
+
for (const client of clients) {
|
|
452
|
+
if (client.isAlive()) client.send(msg);
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
getClient(agentName: string): IpcClient | undefined {
|
|
457
|
+
return agentIndex.get(agentName);
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
clientCount(): number {
|
|
461
|
+
return clients.size;
|
|
462
|
+
},
|
|
463
|
+
|
|
464
|
+
async close(): Promise<void> {
|
|
465
|
+
// Stop the heartbeat watchdog before closing clients so it doesn't
|
|
466
|
+
// log spurious evictions during planned shutdown.
|
|
467
|
+
if (watchdogTimer !== null) {
|
|
468
|
+
clearInterval(watchdogTimer);
|
|
469
|
+
watchdogTimer = null;
|
|
470
|
+
}
|
|
471
|
+
for (const client of clients) {
|
|
472
|
+
client.close();
|
|
473
|
+
}
|
|
474
|
+
clients.clear();
|
|
475
|
+
agentIndex.clear();
|
|
476
|
+
topicIndex.clear();
|
|
477
|
+
clientBySocketId.clear();
|
|
478
|
+
server.stop(true);
|
|
479
|
+
// Rename (not unlink) so a subsequent new-gateway bind that has already
|
|
480
|
+
// landed at socketPath is not accidentally clobbered by this late cleanup.
|
|
481
|
+
// If this rename arrives after a new server is listening, it moves the
|
|
482
|
+
// NEW server's live file to .bak — which is wrong but recoverable. See
|
|
483
|
+
// the note on test 4 in ipc-server-race.test.ts: when both generations
|
|
484
|
+
// target the same pathname, the rename-to-.bak discipline is not enough
|
|
485
|
+
// by itself to prevent the new generation's file from being moved away
|
|
486
|
+
// by the old generation's delayed cleanup. Startup-side cleanup unlinks
|
|
487
|
+
// the stale .bak, so the self-healing property is the best we can do
|
|
488
|
+
// without an inode-matching check.
|
|
489
|
+
try { renameSync(socketPath, socketPath + ".bak"); } catch {}
|
|
490
|
+
},
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
return ipcServer;
|
|
494
|
+
}
|