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,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured audit log for secret-detection events.
|
|
3
|
+
*
|
|
4
|
+
* Rationale: the telegram plugin already intercepts `process.stderr.write`
|
|
5
|
+
* and tees every write to `~/.switchroom/logs/telegram-plugin.log` (see
|
|
6
|
+
* plugin-logger.ts). We piggyback on that — `emitAudit` serializes the
|
|
7
|
+
* event as a single JSON line prefixed with `[secret-detect-audit]` and
|
|
8
|
+
* sends it through stderr. The logger rotation + ops tooling all work for
|
|
9
|
+
* free.
|
|
10
|
+
*
|
|
11
|
+
* CRITICAL: the raw secret value is NEVER placed in the log. Only the slug
|
|
12
|
+
* and rule id. See the `no-raw-secret-in-log` test.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export type AuditAction = 'stored' | 'suppressed' | 'ambiguous' | 'failed' | 'rewritten'
|
|
16
|
+
|
|
17
|
+
export interface AuditEvent {
|
|
18
|
+
event: 'secret-detected'
|
|
19
|
+
chat_id: string
|
|
20
|
+
message_id: number | null
|
|
21
|
+
rule_id: string
|
|
22
|
+
slug: string
|
|
23
|
+
action: AuditAction
|
|
24
|
+
delete_ok: boolean
|
|
25
|
+
ts: number
|
|
26
|
+
/** Optional free-form reason (never contains the raw secret). */
|
|
27
|
+
detail?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type AuditSink = (line: string) => void
|
|
31
|
+
|
|
32
|
+
let sink: AuditSink = (line) => {
|
|
33
|
+
try {
|
|
34
|
+
process.stderr.write(line + '\n')
|
|
35
|
+
} catch {
|
|
36
|
+
// best-effort — never let audit logging break the host path
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Override the sink (tests only). Pass `null` to restore the default.
|
|
42
|
+
*/
|
|
43
|
+
export function setAuditSink(next: AuditSink | null): void {
|
|
44
|
+
sink = next ?? ((line) => {
|
|
45
|
+
try {
|
|
46
|
+
process.stderr.write(line + '\n')
|
|
47
|
+
} catch {
|
|
48
|
+
/* ignore */
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function emitAudit(ev: Omit<AuditEvent, 'event' | 'ts'> & { ts?: number }): void {
|
|
54
|
+
const full: AuditEvent = {
|
|
55
|
+
event: 'secret-detected',
|
|
56
|
+
ts: ev.ts ?? Math.floor(Date.now() / 1000),
|
|
57
|
+
chat_id: ev.chat_id,
|
|
58
|
+
message_id: ev.message_id,
|
|
59
|
+
rule_id: ev.rule_id,
|
|
60
|
+
slug: ev.slug,
|
|
61
|
+
action: ev.action,
|
|
62
|
+
delete_ok: ev.delete_ok,
|
|
63
|
+
...(ev.detail ? { detail: ev.detail } : {}),
|
|
64
|
+
}
|
|
65
|
+
sink(`[secret-detect-audit] ${JSON.stringify(full)}`)
|
|
66
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sliding-window chunker for ReDoS-bounded detection.
|
|
3
|
+
*
|
|
4
|
+
* Inputs larger than 32 KB are split into 16 KB windows with 1 KB overlap.
|
|
5
|
+
* Each window is scanned independently; the caller is responsible for
|
|
6
|
+
* dedupe-by-byte-offset when merging per-window hits back together.
|
|
7
|
+
*
|
|
8
|
+
* The overlap exists so a secret that straddles a window boundary is still
|
|
9
|
+
* matched by at least one scan (provided the secret is ≤ 1 KB, which covers
|
|
10
|
+
* every known token format plus typical PEM private keys).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export interface Window {
|
|
14
|
+
/** Start offset in the original string. */
|
|
15
|
+
offset: number
|
|
16
|
+
/** The window text. */
|
|
17
|
+
text: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const CHUNK_THRESHOLD = 32 * 1024
|
|
21
|
+
export const WINDOW_SIZE = 16 * 1024
|
|
22
|
+
export const OVERLAP = 1024
|
|
23
|
+
|
|
24
|
+
export function chunk(text: string): Window[] {
|
|
25
|
+
if (text.length <= CHUNK_THRESHOLD) {
|
|
26
|
+
return [{ offset: 0, text }]
|
|
27
|
+
}
|
|
28
|
+
const out: Window[] = []
|
|
29
|
+
let offset = 0
|
|
30
|
+
while (offset < text.length) {
|
|
31
|
+
const end = Math.min(offset + WINDOW_SIZE, text.length)
|
|
32
|
+
out.push({ offset, text: text.slice(offset, end) })
|
|
33
|
+
if (end >= text.length) break
|
|
34
|
+
offset = end - OVERLAP
|
|
35
|
+
}
|
|
36
|
+
return out
|
|
37
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shannon entropy — bits per character of a string.
|
|
3
|
+
*
|
|
4
|
+
* Used as the gate for KEY=value scanning (see kv-scanner.ts). Pure,
|
|
5
|
+
* deterministic, O(n). Returns 0 for empty input.
|
|
6
|
+
*/
|
|
7
|
+
export function shannonEntropy(s: string): number {
|
|
8
|
+
if (s.length === 0) return 0
|
|
9
|
+
const counts = new Map<string, number>()
|
|
10
|
+
for (const ch of s) {
|
|
11
|
+
counts.set(ch, (counts.get(ch) ?? 0) + 1)
|
|
12
|
+
}
|
|
13
|
+
let h = 0
|
|
14
|
+
const len = s.length
|
|
15
|
+
for (const c of counts.values()) {
|
|
16
|
+
const p = c / len
|
|
17
|
+
h -= p * Math.log2(p)
|
|
18
|
+
}
|
|
19
|
+
return h
|
|
20
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal loader for the vendored gitleaks.toml.
|
|
3
|
+
*
|
|
4
|
+
* We intentionally avoid adding a full TOML parser dep. The vendored file
|
|
5
|
+
* (gitleaks.toml) is a small handpicked subset, so a naive section-based
|
|
6
|
+
* parser is enough — it handles `[[rules]]`, `id = "..."`, `regex = '''...'''`
|
|
7
|
+
* (triple-single-quoted literals).
|
|
8
|
+
*
|
|
9
|
+
* When v2 lands the full upstream gitleaks.toml, swap this out for a real
|
|
10
|
+
* parser like `@iarna/toml`.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
13
|
+
import { join, dirname } from 'node:path'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
import type { PatternDef } from './patterns.js'
|
|
16
|
+
|
|
17
|
+
export interface GitleaksRule {
|
|
18
|
+
id: string
|
|
19
|
+
description?: string
|
|
20
|
+
regex: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function defaultPath(): string {
|
|
24
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
25
|
+
return join(here, 'gitleaks.toml')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function parseGitleaksToml(content: string): GitleaksRule[] {
|
|
29
|
+
const rules: GitleaksRule[] = []
|
|
30
|
+
// Split on [[rules]] headers.
|
|
31
|
+
const sections = content.split(/^\s*\[\[\s*rules\s*\]\]\s*$/m).slice(1)
|
|
32
|
+
for (const section of sections) {
|
|
33
|
+
const rule: Partial<GitleaksRule> = {}
|
|
34
|
+
const idMatch = /^\s*id\s*=\s*"([^"]+)"\s*$/m.exec(section)
|
|
35
|
+
if (idMatch) rule.id = idMatch[1]
|
|
36
|
+
const descMatch = /^\s*description\s*=\s*"([^"]*)"\s*$/m.exec(section)
|
|
37
|
+
if (descMatch) rule.description = descMatch[1]
|
|
38
|
+
// Regex may be wrapped in ''' or " — prefer ''' which preserves regex
|
|
39
|
+
// escapes without TOML string escaping.
|
|
40
|
+
const reTriple = /^\s*regex\s*=\s*'''([\s\S]*?)'''\s*$/m.exec(section)
|
|
41
|
+
const reDouble = /^\s*regex\s*=\s*"((?:[^"\\]|\\.)*)"\s*$/m.exec(section)
|
|
42
|
+
const raw = reTriple?.[1] ?? reDouble?.[1]
|
|
43
|
+
if (rule.id && raw) {
|
|
44
|
+
rule.regex = raw
|
|
45
|
+
rules.push(rule as GitleaksRule)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return rules
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function loadGitleaksPatterns(path: string = defaultPath()): PatternDef[] {
|
|
52
|
+
if (!existsSync(path)) return []
|
|
53
|
+
let content: string
|
|
54
|
+
try {
|
|
55
|
+
content = readFileSync(path, 'utf8')
|
|
56
|
+
} catch {
|
|
57
|
+
return []
|
|
58
|
+
}
|
|
59
|
+
const rules = parseGitleaksToml(content)
|
|
60
|
+
const out: PatternDef[] = []
|
|
61
|
+
for (const r of rules) {
|
|
62
|
+
try {
|
|
63
|
+
const re = new RegExp(r.regex, 'g')
|
|
64
|
+
out.push({
|
|
65
|
+
rule_id: `gitleaks_${r.id.replace(/-/g, '_')}`,
|
|
66
|
+
regex: re,
|
|
67
|
+
captureIndex: 0,
|
|
68
|
+
})
|
|
69
|
+
} catch {
|
|
70
|
+
// Skip invalid regexes silently; the loader is best-effort.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return out
|
|
74
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Minimal vendored gitleaks-style rule file.
|
|
2
|
+
#
|
|
3
|
+
# Full upstream gitleaks.toml (https://github.com/gitleaks/gitleaks) is the
|
|
4
|
+
# long-term plan for v2. For v1 we ship a thin placeholder so the loader can
|
|
5
|
+
# be exercised and we have a declared file path to extend.
|
|
6
|
+
#
|
|
7
|
+
# Each rule is a [rules.<id>] section with `regex` and optional `tags`.
|
|
8
|
+
# The loader in gitleaks-loader.ts parses this file at boot and compiles
|
|
9
|
+
# each regex into a PatternDef. TOML parsing is intentionally naive to
|
|
10
|
+
# avoid a new dep — see gitleaks-loader.ts for the minimal parser.
|
|
11
|
+
|
|
12
|
+
title = "switchroom vendored gitleaks (subset)"
|
|
13
|
+
|
|
14
|
+
[[rules]]
|
|
15
|
+
id = "slack-webhook"
|
|
16
|
+
description = "Slack incoming webhook URL"
|
|
17
|
+
regex = '''https://hooks\.slack\.com/services/[A-Za-z0-9_/]+'''
|
|
18
|
+
|
|
19
|
+
[[rules]]
|
|
20
|
+
id = "stripe-live-key"
|
|
21
|
+
description = "Stripe live secret key"
|
|
22
|
+
regex = '''\b(sk_live_[A-Za-z0-9]{24,})\b'''
|
|
23
|
+
|
|
24
|
+
[[rules]]
|
|
25
|
+
id = "sendgrid-api-key"
|
|
26
|
+
description = "SendGrid API key"
|
|
27
|
+
regex = '''\b(SG\.[A-Za-z0-9_-]{22}\.[A-Za-z0-9_-]{43})\b'''
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret detection entrypoint for the Telegram plugin.
|
|
3
|
+
*
|
|
4
|
+
* `detectSecrets(text)` returns a normalized list of detections — each with
|
|
5
|
+
* a rule id, the matched bytes, byte-offsets in the original text, a
|
|
6
|
+
* confidence tier, a suppression flag, and a suggested vault slug.
|
|
7
|
+
*
|
|
8
|
+
* Detection stack (order = precedence on ties):
|
|
9
|
+
* 1. Anchored provider prefixes (sk-ant-, ghp_, AIza..., etc.)
|
|
10
|
+
* 2. Structured patterns (KEY=value, JSON fields, Authorization Bearer,
|
|
11
|
+
* PEM blocks, CLI flags)
|
|
12
|
+
* 3. KEY=VALUE heuristic with Shannon-entropy gate (≥ 4.0)
|
|
13
|
+
*
|
|
14
|
+
* Big inputs (>32 KB) are chunked into 16 KB windows with 1 KB overlap
|
|
15
|
+
* (chunker.ts) for ReDoS bounding; we dedupe by byte-offset after.
|
|
16
|
+
*
|
|
17
|
+
* Nearby test/mock/example/fixture/dummy markers (within 40 chars) demote
|
|
18
|
+
* a hit to `suppressed: true`. The caller decides what that means (our
|
|
19
|
+
* convention: suppressed high-confidence → ambiguous, user is asked).
|
|
20
|
+
*
|
|
21
|
+
* Secretlint is integrated as an async supplementary source via
|
|
22
|
+
* `detectSecretsAsync`. The sync `detectSecrets` keeps the fast vendored-
|
|
23
|
+
* pattern path for callers on the hot path (Telegram message ingest).
|
|
24
|
+
* Gitleaks TOML is loaded via `gitleaks-loader.ts`.
|
|
25
|
+
*/
|
|
26
|
+
import { ALL_PATTERNS } from './patterns.js'
|
|
27
|
+
import { scanKeyValue, type RawHit } from './kv-scanner.js'
|
|
28
|
+
import { chunk } from './chunker.js'
|
|
29
|
+
import { isSuppressed } from './suppressor.js'
|
|
30
|
+
import { deriveSlug } from './slug.js'
|
|
31
|
+
|
|
32
|
+
export interface Detection {
|
|
33
|
+
rule_id: string
|
|
34
|
+
matched_text: string
|
|
35
|
+
/** Byte offset into the original input text. */
|
|
36
|
+
start: number
|
|
37
|
+
/** Byte offset (exclusive) into the original input text. */
|
|
38
|
+
end: number
|
|
39
|
+
confidence: 'high' | 'ambiguous'
|
|
40
|
+
suppressed: boolean
|
|
41
|
+
/**
|
|
42
|
+
* Deterministic suggested vault key. Computed without reading the real
|
|
43
|
+
* vault; the caller may re-derive with `deriveSlug` when writing, passing
|
|
44
|
+
* the current vault key set to avoid collisions.
|
|
45
|
+
*/
|
|
46
|
+
suggested_slug: string
|
|
47
|
+
/**
|
|
48
|
+
* Free-form key name the detector thinks described this secret, e.g.
|
|
49
|
+
* `ANTHROPIC_API_KEY` when the pattern was `env_key_value`. Used by
|
|
50
|
+
* `deriveSlug` as the preferred slug source.
|
|
51
|
+
*/
|
|
52
|
+
key_name?: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function detectSecrets(text: string): Detection[] {
|
|
56
|
+
if (!text || text.length === 0) return []
|
|
57
|
+
|
|
58
|
+
// Chunk for ReDoS bounding; small inputs return a single window.
|
|
59
|
+
const windows = chunk(text)
|
|
60
|
+
|
|
61
|
+
// Collect raw hits with global offsets.
|
|
62
|
+
const raw: RawHit[] = []
|
|
63
|
+
|
|
64
|
+
for (const win of windows) {
|
|
65
|
+
for (const p of ALL_PATTERNS) {
|
|
66
|
+
// Make sure we're running a stateless global scan per window.
|
|
67
|
+
const re = new RegExp(p.regex.source, p.regex.flags.includes('g') ? p.regex.flags : p.regex.flags + 'g')
|
|
68
|
+
let m: RegExpExecArray | null
|
|
69
|
+
while ((m = re.exec(win.text)) !== null) {
|
|
70
|
+
if (m[0].length === 0) {
|
|
71
|
+
re.lastIndex++
|
|
72
|
+
continue
|
|
73
|
+
}
|
|
74
|
+
const cap = p.captureIndex === 0 ? m[0] : m[p.captureIndex]
|
|
75
|
+
if (!cap) continue
|
|
76
|
+
const matchStart = p.captureIndex === 0 ? m.index : m.index + m[0].indexOf(cap)
|
|
77
|
+
if (matchStart < 0) continue
|
|
78
|
+
const globalStart = win.offset + matchStart
|
|
79
|
+
const globalEnd = globalStart + cap.length
|
|
80
|
+
// For env_key_value (captureIndex=3), the LHS is group 1.
|
|
81
|
+
const keyName = p.rule_id === 'env_key_value' ? m[1] : undefined
|
|
82
|
+
raw.push({
|
|
83
|
+
rule_id: p.rule_id,
|
|
84
|
+
start: globalStart,
|
|
85
|
+
end: globalEnd,
|
|
86
|
+
matched_text: cap,
|
|
87
|
+
key_name: keyName,
|
|
88
|
+
confidence: 'high',
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// KV heuristic scanner runs per window too.
|
|
93
|
+
const kvHits = scanKeyValue(win.text)
|
|
94
|
+
for (const h of kvHits) {
|
|
95
|
+
raw.push({ ...h, start: h.start + win.offset, end: h.end + win.offset })
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Dedupe by range + rule. If two rules hit the same range, prefer the
|
|
100
|
+
// earlier one in `ALL_PATTERNS` (higher precedence).
|
|
101
|
+
const deduped = dedupeRaw(raw)
|
|
102
|
+
|
|
103
|
+
// Resolve overlaps — drop any hit fully contained inside a higher-precedence
|
|
104
|
+
// hit on the same range.
|
|
105
|
+
const final = dropOverlaps(deduped)
|
|
106
|
+
|
|
107
|
+
// Upgrade to Detection shape + compute slug + check suppressor.
|
|
108
|
+
const existing = new Set<string>()
|
|
109
|
+
const out: Detection[] = []
|
|
110
|
+
for (const h of final) {
|
|
111
|
+
const suggested_slug = deriveSlug(
|
|
112
|
+
{ key_name: h.key_name, rule_id: h.rule_id },
|
|
113
|
+
existing,
|
|
114
|
+
)
|
|
115
|
+
existing.add(suggested_slug)
|
|
116
|
+
out.push({
|
|
117
|
+
rule_id: h.rule_id,
|
|
118
|
+
matched_text: h.matched_text,
|
|
119
|
+
start: h.start,
|
|
120
|
+
end: h.end,
|
|
121
|
+
confidence: h.confidence,
|
|
122
|
+
suppressed: isSuppressed(text, h.start, h.end),
|
|
123
|
+
suggested_slug,
|
|
124
|
+
key_name: h.key_name,
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
// Stable sort by start offset so callers can rewrite left-to-right.
|
|
128
|
+
out.sort((a, b) => a.start - b.start)
|
|
129
|
+
return out
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function dedupeRaw(raw: RawHit[]): RawHit[] {
|
|
133
|
+
const seen = new Map<string, RawHit>()
|
|
134
|
+
for (const h of raw) {
|
|
135
|
+
const key = `${h.start}:${h.end}`
|
|
136
|
+
const existing = seen.get(key)
|
|
137
|
+
if (!existing) {
|
|
138
|
+
seen.set(key, h)
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
// Prefer high over ambiguous.
|
|
142
|
+
if (existing.confidence === 'ambiguous' && h.confidence === 'high') {
|
|
143
|
+
seen.set(key, h)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return Array.from(seen.values())
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Drop hits fully contained inside another hit. Keeps the outer (typically
|
|
151
|
+
* broader / higher-signal) hit — e.g. a JWT match wholly inside an
|
|
152
|
+
* Authorization Bearer match keeps the Bearer.
|
|
153
|
+
*/
|
|
154
|
+
function dropOverlaps(hits: RawHit[]): RawHit[] {
|
|
155
|
+
const sorted = [...hits].sort((a, b) => (a.end - a.start) - (b.end - b.start))
|
|
156
|
+
const out: RawHit[] = []
|
|
157
|
+
for (const h of sorted) {
|
|
158
|
+
const contained = out.some(
|
|
159
|
+
(existing) =>
|
|
160
|
+
existing !== h &&
|
|
161
|
+
existing.start <= h.start &&
|
|
162
|
+
existing.end >= h.end &&
|
|
163
|
+
!(existing.start === h.start && existing.end === h.end),
|
|
164
|
+
)
|
|
165
|
+
if (!contained) out.push(h)
|
|
166
|
+
}
|
|
167
|
+
// Re-sort by start offset for deterministic downstream handling.
|
|
168
|
+
out.sort((a, b) => a.start - b.start || a.end - b.end)
|
|
169
|
+
return out
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { maskToken } from './mask.js'
|
|
173
|
+
export { redactUrls } from './url-redact.js'
|
|
174
|
+
export { deriveSlug } from './slug.js'
|
|
175
|
+
export { detectViaSecretlint } from './secretlint-source.js'
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Async detection pipeline — runs `detectSecrets` (fast vendored engine)
|
|
179
|
+
* and Secretlint in parallel, then merges the results by deduping on
|
|
180
|
+
* `[start, end)` byte ranges. If Secretlint and a vendored pattern both
|
|
181
|
+
* match the same span, the first one wins (vendored, since it's listed
|
|
182
|
+
* first in the merge array below).
|
|
183
|
+
*
|
|
184
|
+
* Slug collisions are re-resolved on the merged list so the overall
|
|
185
|
+
* output has unique `suggested_slug` values.
|
|
186
|
+
*/
|
|
187
|
+
export async function detectSecretsAsync(text: string): Promise<Detection[]> {
|
|
188
|
+
if (!text || text.length === 0) return []
|
|
189
|
+
const [vendored, viaSecretlint] = await Promise.all([
|
|
190
|
+
Promise.resolve(detectSecrets(text)),
|
|
191
|
+
// Lazy-import keeps the sync `detectSecrets` path free of Secretlint
|
|
192
|
+
// initialization cost; paid once on first async call.
|
|
193
|
+
import('./secretlint-source.js').then((m) => m.detectViaSecretlint(text)),
|
|
194
|
+
])
|
|
195
|
+
|
|
196
|
+
// Merge with range-based dedupe. Vendored first wins on exact ties.
|
|
197
|
+
const seen = new Map<string, Detection>()
|
|
198
|
+
for (const d of vendored) {
|
|
199
|
+
const key = `${d.start}:${d.end}`
|
|
200
|
+
if (!seen.has(key)) seen.set(key, d)
|
|
201
|
+
}
|
|
202
|
+
for (const d of viaSecretlint) {
|
|
203
|
+
const key = `${d.start}:${d.end}`
|
|
204
|
+
if (!seen.has(key)) seen.set(key, d)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Re-derive slugs against the merged set (Secretlint and vendored each
|
|
208
|
+
// had independent `existing` sets; we coalesce here).
|
|
209
|
+
const existing = new Set<string>()
|
|
210
|
+
const out: Detection[] = Array.from(seen.values())
|
|
211
|
+
.sort((a, b) => a.start - b.start)
|
|
212
|
+
.map((d) => {
|
|
213
|
+
const slug = deriveSlug({ key_name: d.key_name, rule_id: d.rule_id }, existing)
|
|
214
|
+
existing.add(slug)
|
|
215
|
+
return { ...d, suggested_slug: slug }
|
|
216
|
+
})
|
|
217
|
+
return out
|
|
218
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristic KEY=VALUE scanner. Fallback when the structured patterns miss —
|
|
3
|
+
* e.g. lowercase env var names like `my_password=...` that the all-caps
|
|
4
|
+
* `env_key_value` pattern skips.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. Regex-scan for `(password|token|secret|key|api_key)\s*[:=]\s*...`
|
|
8
|
+
* 2. Extract the RHS value
|
|
9
|
+
* 3. Gate on Shannon entropy ≥ 4.0 to cut obvious placeholders like
|
|
10
|
+
* `password=foo` or `key=changeme`.
|
|
11
|
+
*
|
|
12
|
+
* Returns `RawHit` entries pointing at the VALUE bytes (not the whole
|
|
13
|
+
* `key=value` match), so the rewriter can preserve the `key=` prefix.
|
|
14
|
+
*/
|
|
15
|
+
import { shannonEntropy } from './entropy.js'
|
|
16
|
+
|
|
17
|
+
export interface RawHit {
|
|
18
|
+
rule_id: string
|
|
19
|
+
start: number
|
|
20
|
+
end: number
|
|
21
|
+
matched_text: string
|
|
22
|
+
/** The identifier on the left of `=` or `:`, if any. Used for slug derivation. */
|
|
23
|
+
key_name?: string
|
|
24
|
+
/** Confidence tier — high = anchored pattern, ambiguous = entropy-only. */
|
|
25
|
+
confidence: 'high' | 'ambiguous'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Lower-case / mixed-case KEY=VALUE. Uppercase-only is handled by the
|
|
29
|
+
// structured `env_key_value` pattern for higher confidence.
|
|
30
|
+
const KV_RE = /\b([A-Za-z_][A-Za-z0-9_-]*(?:password|passwd|token|secret|key|api[_-]?key))\s*[:=]\s*["']?([^\s"'\\]{8,})["']?/gi
|
|
31
|
+
|
|
32
|
+
export const KV_ENTROPY_THRESHOLD = 4.0
|
|
33
|
+
|
|
34
|
+
export function scanKeyValue(text: string): RawHit[] {
|
|
35
|
+
const hits: RawHit[] = []
|
|
36
|
+
KV_RE.lastIndex = 0
|
|
37
|
+
let m: RegExpExecArray | null
|
|
38
|
+
while ((m = KV_RE.exec(text)) !== null) {
|
|
39
|
+
const [, keyName, value] = m
|
|
40
|
+
if (!value) continue
|
|
41
|
+
// Shannon entropy gate — only flag values that actually look random.
|
|
42
|
+
const h = shannonEntropy(value)
|
|
43
|
+
if (h < KV_ENTROPY_THRESHOLD) continue
|
|
44
|
+
// The value starts at match.index + the length of everything before
|
|
45
|
+
// it in the match. Compute by finding the value inside the match.
|
|
46
|
+
const valueOffsetInMatch = m[0].indexOf(value, keyName!.length)
|
|
47
|
+
if (valueOffsetInMatch < 0) continue
|
|
48
|
+
const start = m.index + valueOffsetInMatch
|
|
49
|
+
const end = start + value.length
|
|
50
|
+
hits.push({
|
|
51
|
+
rule_id: 'kv_entropy',
|
|
52
|
+
start,
|
|
53
|
+
end,
|
|
54
|
+
matched_text: value,
|
|
55
|
+
key_name: keyName,
|
|
56
|
+
confidence: 'ambiguous',
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
return hits
|
|
60
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Partial-reveal mask for a detected secret.
|
|
3
|
+
*
|
|
4
|
+
* Rule (locked spec): if length ≥ 18, show first 6 + "..." + last 4; else "***".
|
|
5
|
+
* Never reveals the middle bytes, never returns a substring an attacker could
|
|
6
|
+
* search for verbatim.
|
|
7
|
+
*/
|
|
8
|
+
export function maskToken(s: string): string {
|
|
9
|
+
if (s.length >= 18) {
|
|
10
|
+
return `${s.slice(0, 6)}...${s.slice(-4)}`
|
|
11
|
+
}
|
|
12
|
+
return '***'
|
|
13
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern registry for secret detection — the openclaw-derived list plus
|
|
3
|
+
* a few anchored, high-confidence provider prefixes.
|
|
4
|
+
*
|
|
5
|
+
* Ordering matters: patterns near the top are preferred on ties (first match
|
|
6
|
+
* wins). Anchored provider prefixes are listed first so `sk-ant-...` wins
|
|
7
|
+
* over the generic "sk-..." match.
|
|
8
|
+
*
|
|
9
|
+
* Each entry has a rule_id, a regex, and a `captureIndex` pointing at the
|
|
10
|
+
* capture group that holds the raw secret bytes (so the detector can slice
|
|
11
|
+
* just the sensitive portion, not the whole match which may include
|
|
12
|
+
* "KEY=" or quote prefixes).
|
|
13
|
+
*/
|
|
14
|
+
export interface PatternDef {
|
|
15
|
+
rule_id: string
|
|
16
|
+
regex: RegExp
|
|
17
|
+
/**
|
|
18
|
+
* Which capture group is the secret value. 0 means "the whole match".
|
|
19
|
+
* For KEY=VALUE style, we point at the value group so the detection
|
|
20
|
+
* range covers only the secret bytes, letting the rewriter preserve
|
|
21
|
+
* the `KEY=` prefix.
|
|
22
|
+
*/
|
|
23
|
+
captureIndex: number
|
|
24
|
+
/** If set, a hint used when deriving the vault slug. */
|
|
25
|
+
slugHint?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* High-confidence anchored provider prefixes. Listed first so they win
|
|
30
|
+
* over the generic broad patterns.
|
|
31
|
+
*/
|
|
32
|
+
export const ANCHORED_PATTERNS: PatternDef[] = [
|
|
33
|
+
{ rule_id: 'anthropic_api_key', regex: /\b(sk-ant-[A-Za-z0-9_-]{8,})\b/g, captureIndex: 1, slugHint: 'anthropic_api_key' },
|
|
34
|
+
// anthropic_api_key precedes; the patterns don't overlap (the `#` separator
|
|
35
|
+
// isn't in api-key shape) so ordering is moot for correctness.
|
|
36
|
+
// Anthropic OAuth browser code — emitted by the claude.com/cai authorize
|
|
37
|
+
// flow as two URL-safe base64 segments joined by `#`.
|
|
38
|
+
// Shape: <20+ url-safe-b64>#<20+ url-safe-b64>
|
|
39
|
+
// Anchored to whitespace boundaries (^/\s before, \s/$ after) to avoid
|
|
40
|
+
// false-positives on real URLs whose path segment + fragment anchor both
|
|
41
|
+
// exceed 20 chars (e.g. GitHub headings, npm readme anchors). The bare-code
|
|
42
|
+
// paste case ("code#state" alone on a line or after prose) is the only
|
|
43
|
+
// intended match target.
|
|
44
|
+
{ rule_id: 'anthropic_oauth_code', regex: /(?:^|\s)([A-Za-z0-9_-]{20,}#[A-Za-z0-9_-]{20,})(?=\s|$)/gm, captureIndex: 1, slugHint: 'anthropic_oauth_code' },
|
|
45
|
+
{ rule_id: 'openai_api_key', regex: /\b(sk-[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: 'openai_api_key' },
|
|
46
|
+
{ rule_id: 'github_pat_classic', regex: /\b(ghp_[A-Za-z0-9]{20,})\b/g, captureIndex: 1, slugHint: 'github_pat' },
|
|
47
|
+
{ rule_id: 'github_pat_fine_grained', regex: /\b(github_pat_[A-Za-z0-9_]{20,})\b/g, captureIndex: 1, slugHint: 'github_pat' },
|
|
48
|
+
{ rule_id: 'slack_token', regex: /\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g, captureIndex: 1, slugHint: 'slack_token' },
|
|
49
|
+
{ rule_id: 'slack_app_token', regex: /\b(xapp-[A-Za-z0-9-]{10,})\b/g, captureIndex: 1, slugHint: 'slack_app_token' },
|
|
50
|
+
{ rule_id: 'groq_api_key', regex: /\b(gsk_[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: 'groq_api_key' },
|
|
51
|
+
{ rule_id: 'google_api_key', regex: /\b(AIza[0-9A-Za-z\-_]{20,})\b/g, captureIndex: 1, slugHint: 'google_api_key' },
|
|
52
|
+
{ rule_id: 'perplexity_api_key', regex: /\b(pplx-[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: 'perplexity_api_key' },
|
|
53
|
+
{ rule_id: 'npm_token', regex: /\b(npm_[A-Za-z0-9]{10,})\b/g, captureIndex: 1, slugHint: 'npm_token' },
|
|
54
|
+
// Telegram bot tokens: with "bot" prefix or bare ID:token.
|
|
55
|
+
{ rule_id: 'telegram_bot_token_prefixed', regex: /\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: 'telegram_bot_token' },
|
|
56
|
+
{ rule_id: 'telegram_bot_token', regex: /\b(\d{6,}:[A-Za-z0-9_-]{20,})\b/g, captureIndex: 1, slugHint: 'telegram_bot_token' },
|
|
57
|
+
{ rule_id: 'aws_access_key', regex: /\b(AKIA[0-9A-Z]{16})\b/g, captureIndex: 1, slugHint: 'aws_access_key' },
|
|
58
|
+
{ rule_id: 'jwt', regex: /\b(eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,})\b/g, captureIndex: 1, slugHint: 'jwt' },
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Openclaw default pattern list. Matches structured contexts where a value
|
|
63
|
+
* is "labelled" as a secret (KEY=value, JSON field, CLI flag, Bearer token,
|
|
64
|
+
* PEM block). Only the value group is captured.
|
|
65
|
+
*/
|
|
66
|
+
export const STRUCTURED_PATTERNS: PatternDef[] = [
|
|
67
|
+
// KEY=value (ALL-CAPS identifier ending in KEY/TOKEN/SECRET/PASSWORD/PASSWD).
|
|
68
|
+
// Value group index is 2 — group 1 is the optional quote char.
|
|
69
|
+
{
|
|
70
|
+
rule_id: 'env_key_value',
|
|
71
|
+
regex: /\b([A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD))\b\s*[=:]\s*(["']?)([^\s"'\\]+)\2/g,
|
|
72
|
+
captureIndex: 3,
|
|
73
|
+
slugHint: 'env',
|
|
74
|
+
},
|
|
75
|
+
// JSON field: "apiKey": "value"
|
|
76
|
+
{
|
|
77
|
+
rule_id: 'json_secret_field',
|
|
78
|
+
regex: /"(?:apiKey|token|secret|password|passwd|accessToken|refreshToken)"\s*:\s*"([^"]+)"/g,
|
|
79
|
+
captureIndex: 1,
|
|
80
|
+
slugHint: 'json_secret',
|
|
81
|
+
},
|
|
82
|
+
// CLI flag: --api-key VALUE or --token='VALUE'
|
|
83
|
+
{
|
|
84
|
+
rule_id: 'cli_flag',
|
|
85
|
+
regex: /--(?:api[-_]?key|hook[-_]?token|token|secret|password|passwd)\s+(["']?)([^\s"']+)\1/g,
|
|
86
|
+
captureIndex: 2,
|
|
87
|
+
slugHint: 'cli_flag',
|
|
88
|
+
},
|
|
89
|
+
// Authorization: Bearer token (form 1 — explicit Authorization header)
|
|
90
|
+
{
|
|
91
|
+
rule_id: 'bearer_auth_header',
|
|
92
|
+
regex: /Authorization\s*[:=]\s*Bearer\s+([A-Za-z0-9._\-+=]+)/g,
|
|
93
|
+
captureIndex: 1,
|
|
94
|
+
slugHint: 'bearer_token',
|
|
95
|
+
},
|
|
96
|
+
// Bare "Bearer XYZ" (length-gated to cut false positives on the word "Bearer")
|
|
97
|
+
{
|
|
98
|
+
rule_id: 'bearer_loose',
|
|
99
|
+
regex: /\bBearer\s+([A-Za-z0-9._\-+=]{18,})\b/g,
|
|
100
|
+
captureIndex: 1,
|
|
101
|
+
slugHint: 'bearer_token',
|
|
102
|
+
},
|
|
103
|
+
// PEM private key block — single greedy capture, non-overlapping.
|
|
104
|
+
{
|
|
105
|
+
rule_id: 'pem_private_key',
|
|
106
|
+
regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
107
|
+
captureIndex: 0,
|
|
108
|
+
slugHint: 'pem_private_key',
|
|
109
|
+
},
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Concatenated registry — anchored first, then structured.
|
|
114
|
+
*/
|
|
115
|
+
export const ALL_PATTERNS: PatternDef[] = [...ANCHORED_PATTERNS, ...STRUCTURED_PATTERNS]
|