agentwire-dev 1.31.0__tar.gz → 1.32.0__tar.gz
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.
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/PKG-INFO +1 -1
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/__init__.py +1 -1
- agentwire_dev-1.32.0/agentwire/static/announcements.json +31 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/css/desktop.css +198 -0
- agentwire_dev-1.32.0/agentwire/static/js/announcement-modal.js +178 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/desktop.js +5 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/templates/desktop.html +1 -0
- agentwire_dev-1.32.0/tests/unit/test_announcements.py +60 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/.gitignore +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/CHANGELOG.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/CLA.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/Dockerfile.runpod +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/LICENSE +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/README.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/RELEASING.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/SECURITY.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/cli_safety.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/config.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/cli.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/config.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/dispatcher.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/eligibility.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/feedback_router.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/gc.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/github.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/naming.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/missions/state.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/overnight.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/prompts/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/prompts/init.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/scheduler.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/search.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/server.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-Echo--black.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-Echo--transparent.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-Echo.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-email-banner.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--transparent.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/favicon.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/android.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/automaton.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/bot.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/droid.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/drone.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/guardian.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/mech.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/probe.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/robot.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/machines/unit.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/blob.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/cloud.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/crystal.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/flame.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/horned.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/moon.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/slime.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/star.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/projects/winged.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/bear.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/cat.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/crown.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/deer.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/drone.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/fox.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/horse.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/lion.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/robot.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/components/icon-picker.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/components/list-card.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/components/type-tag.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/missions-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/utils/auto-refresh.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/engines/qwen_base.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/engines/qwen_custom.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/engines/qwen_design.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/voices/darren.wav +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/voices/default.wav +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/voices/jessica.wav +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/voices/lisa.wav +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/voices/may.wav +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/logo.png +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/missions.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/pyproject.toml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/requirements-tts.txt +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/templates/launchd/dev.agentwire.mission-dispatcher.plist +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/templates/launchd/dev.agentwire.mission-feedback-router.plist +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/templates/launchd/dev.agentwire.mission-janitor.plist +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/integration/test_missions_concurrency.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/integration/test_missions_lifecycle.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_cli_safety.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_cli.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_config.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_dispatcher.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_eligibility.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_feedback_router.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_gc.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_github.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_naming.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_missions_state.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_overnight_resume_flags.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_safety_mission_worker.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_search.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/tests/unit/test_worktree.py +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"announcements": [
|
|
3
|
+
{
|
|
4
|
+
"id": "evergreen-feedback-2026-06",
|
|
5
|
+
"placement": "banner",
|
|
6
|
+
"emoji": "👋",
|
|
7
|
+
"title": "You're an early one",
|
|
8
|
+
"body": "AgentWire is young and shaped by the handful of people running it. Bug, idea, or just hello — open an issue, it's read.",
|
|
9
|
+
"cta": {
|
|
10
|
+
"label": "Open an issue",
|
|
11
|
+
"url": "https://github.com/dotdevdotdev/agentwire-dev/issues/new"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "2026-06-idea-first-capture",
|
|
16
|
+
"placement": "modal",
|
|
17
|
+
"emoji": "💡",
|
|
18
|
+
"title": "New idea? Cmd+K and go.",
|
|
19
|
+
"date": "2026-06-08",
|
|
20
|
+
"body": "AgentWire can now spin up a whole project from a single sentence. Press Cmd/Ctrl+K (or the New idea button), type — or speak — what you want to build, and it scaffolds the folder, starts an agent, and hands it your idea as the first message. You watch it get to work the moment the window opens.",
|
|
21
|
+
"highlights": [
|
|
22
|
+
"Idea-first capture — type an idea, get a running agent",
|
|
23
|
+
"Instant voice mode — browser speech in and out, zero setup"
|
|
24
|
+
],
|
|
25
|
+
"cta": {
|
|
26
|
+
"label": "See what's in v1.31",
|
|
27
|
+
"url": "https://github.com/dotdevdotdev/agentwire-dev/releases/tag/v1.31.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -1000,6 +1000,151 @@ body {
|
|
|
1000
1000
|
font-weight: 500;
|
|
1001
1001
|
}
|
|
1002
1002
|
|
|
1003
|
+
/* =========================================================================
|
|
1004
|
+
Announcement modal (userbase welcome card)
|
|
1005
|
+
========================================================================= */
|
|
1006
|
+
|
|
1007
|
+
.announcement-overlay {
|
|
1008
|
+
z-index: 2100; /* above standard modals, below the command palette */
|
|
1009
|
+
animation: announcement-fade 180ms ease-out;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
.announcement-overlay .announcement-modal {
|
|
1013
|
+
width: 460px;
|
|
1014
|
+
max-width: 92vw;
|
|
1015
|
+
padding: 28px 28px 22px;
|
|
1016
|
+
text-align: center;
|
|
1017
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 7%, var(--chrome)) 0%, var(--chrome) 60%);
|
|
1018
|
+
border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--chrome-border));
|
|
1019
|
+
border-radius: 12px;
|
|
1020
|
+
animation: announcement-rise 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
.announcement-dismiss {
|
|
1024
|
+
position: absolute;
|
|
1025
|
+
top: 12px;
|
|
1026
|
+
right: 12px;
|
|
1027
|
+
background: transparent;
|
|
1028
|
+
border: none;
|
|
1029
|
+
color: var(--text-muted);
|
|
1030
|
+
font-size: 15px;
|
|
1031
|
+
cursor: pointer;
|
|
1032
|
+
line-height: 1;
|
|
1033
|
+
padding: 4px 6px;
|
|
1034
|
+
border-radius: 4px;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
.announcement-dismiss:hover {
|
|
1038
|
+
color: var(--text);
|
|
1039
|
+
background: var(--background);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
.announcement-emoji {
|
|
1043
|
+
font-size: 40px;
|
|
1044
|
+
line-height: 1;
|
|
1045
|
+
margin-bottom: 10px;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.announcement-title {
|
|
1049
|
+
margin: 0 0 4px;
|
|
1050
|
+
font-size: 21px;
|
|
1051
|
+
font-weight: 700;
|
|
1052
|
+
color: var(--text);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.announcement-date {
|
|
1056
|
+
font-size: 12px;
|
|
1057
|
+
color: var(--text-muted);
|
|
1058
|
+
margin-bottom: 14px;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
.announcement-body {
|
|
1062
|
+
font-size: 15px;
|
|
1063
|
+
line-height: 1.55;
|
|
1064
|
+
color: var(--text);
|
|
1065
|
+
opacity: 0.92;
|
|
1066
|
+
margin-bottom: 16px;
|
|
1067
|
+
text-align: left;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
.announcement-highlights {
|
|
1071
|
+
list-style: none;
|
|
1072
|
+
margin: 0 0 20px;
|
|
1073
|
+
padding: 0;
|
|
1074
|
+
text-align: left;
|
|
1075
|
+
display: flex;
|
|
1076
|
+
flex-direction: column;
|
|
1077
|
+
gap: 8px;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
.announcement-highlights li {
|
|
1081
|
+
position: relative;
|
|
1082
|
+
padding: 8px 12px 8px 34px;
|
|
1083
|
+
background: var(--background);
|
|
1084
|
+
border: 1px solid var(--chrome-border);
|
|
1085
|
+
border-radius: 6px;
|
|
1086
|
+
font-size: 14px;
|
|
1087
|
+
color: var(--text);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
.announcement-highlights li::before {
|
|
1091
|
+
content: "✦";
|
|
1092
|
+
position: absolute;
|
|
1093
|
+
left: 12px;
|
|
1094
|
+
top: 8px;
|
|
1095
|
+
color: var(--accent);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
.announcement-footer {
|
|
1099
|
+
display: flex;
|
|
1100
|
+
align-items: center;
|
|
1101
|
+
justify-content: center;
|
|
1102
|
+
gap: 10px;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
.announcement-cta {
|
|
1106
|
+
flex: 1;
|
|
1107
|
+
padding: 10px 16px;
|
|
1108
|
+
background: var(--accent);
|
|
1109
|
+
color: var(--background);
|
|
1110
|
+
border-radius: 6px;
|
|
1111
|
+
font-weight: 600;
|
|
1112
|
+
font-size: 14px;
|
|
1113
|
+
text-decoration: none;
|
|
1114
|
+
text-align: center;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
.announcement-cta:hover {
|
|
1118
|
+
filter: brightness(1.08);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
.announcement-ok {
|
|
1122
|
+
flex: 1;
|
|
1123
|
+
padding: 10px 16px;
|
|
1124
|
+
background: transparent;
|
|
1125
|
+
border: 1px solid var(--chrome-border);
|
|
1126
|
+
border-radius: 6px;
|
|
1127
|
+
color: var(--text);
|
|
1128
|
+
font-weight: 600;
|
|
1129
|
+
font-size: 14px;
|
|
1130
|
+
cursor: pointer;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
.announcement-ok:hover {
|
|
1134
|
+
border-color: var(--accent);
|
|
1135
|
+
color: var(--accent);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
@keyframes announcement-fade {
|
|
1139
|
+
from { opacity: 0; }
|
|
1140
|
+
to { opacity: 1; }
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
@keyframes announcement-rise {
|
|
1144
|
+
from { opacity: 0; transform: translateY(12px) scale(0.98); }
|
|
1145
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1003
1148
|
/* =========================================================================
|
|
1004
1149
|
Quicktask modal
|
|
1005
1150
|
========================================================================= */
|
|
@@ -4820,6 +4965,59 @@ body.sidebar-pinned .sidebar-tab {
|
|
|
4820
4965
|
opacity: 1;
|
|
4821
4966
|
}
|
|
4822
4967
|
|
|
4968
|
+
/* Sidebar announcement banner (evergreen userbase note — see announcement-modal.js) */
|
|
4969
|
+
.announcement-banner {
|
|
4970
|
+
position: relative;
|
|
4971
|
+
flex-basis: 100%;
|
|
4972
|
+
padding: calc(var(--spacing-base) * 1.25);
|
|
4973
|
+
margin-bottom: var(--spacing-base);
|
|
4974
|
+
border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--chrome-border));
|
|
4975
|
+
border-left: 3px solid var(--accent);
|
|
4976
|
+
border-radius: var(--radius, 6px);
|
|
4977
|
+
background: color-mix(in srgb, var(--accent) 6%, var(--chrome));
|
|
4978
|
+
font-size: 11px;
|
|
4979
|
+
line-height: 1.45;
|
|
4980
|
+
}
|
|
4981
|
+
|
|
4982
|
+
.announcement-banner-title {
|
|
4983
|
+
font-weight: 600;
|
|
4984
|
+
color: var(--accent);
|
|
4985
|
+
margin-bottom: 4px;
|
|
4986
|
+
padding-right: 14px; /* clear the ✕ */
|
|
4987
|
+
}
|
|
4988
|
+
|
|
4989
|
+
.announcement-banner-body {
|
|
4990
|
+
color: var(--text-secondary, inherit);
|
|
4991
|
+
}
|
|
4992
|
+
|
|
4993
|
+
.announcement-banner-cta {
|
|
4994
|
+
display: inline-block;
|
|
4995
|
+
margin-top: 6px;
|
|
4996
|
+
color: var(--accent);
|
|
4997
|
+
font-weight: 600;
|
|
4998
|
+
text-decoration: none;
|
|
4999
|
+
}
|
|
5000
|
+
|
|
5001
|
+
.announcement-banner-cta:hover {
|
|
5002
|
+
text-decoration: underline;
|
|
5003
|
+
}
|
|
5004
|
+
|
|
5005
|
+
.announcement-banner-dismiss {
|
|
5006
|
+
position: absolute;
|
|
5007
|
+
top: 4px;
|
|
5008
|
+
right: 6px;
|
|
5009
|
+
border: none;
|
|
5010
|
+
background: none;
|
|
5011
|
+
color: inherit;
|
|
5012
|
+
cursor: pointer;
|
|
5013
|
+
font-size: 11px;
|
|
5014
|
+
opacity: 0.6;
|
|
5015
|
+
}
|
|
5016
|
+
|
|
5017
|
+
.announcement-banner-dismiss:hover {
|
|
5018
|
+
opacity: 1;
|
|
5019
|
+
}
|
|
5020
|
+
|
|
4823
5021
|
/* Edit-before-send transcript bars (default STT tier) */
|
|
4824
5022
|
.sidebar-transcript-bar,
|
|
4825
5023
|
.wb-transcript-bar {
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Announcements — userbase messaging in two channels, one source file.
|
|
3
|
+
*
|
|
4
|
+
* Content is a single JSON file (agentwire/static/announcements.json) edited
|
|
5
|
+
* on `main`. It plays two roles:
|
|
6
|
+
* - Remote source: fetched from raw.githubusercontent on load, so an edit
|
|
7
|
+
* on `main` reaches every user on their next portal open — no upgrade.
|
|
8
|
+
* - Bundled fallback: the same file ships in the package and is served at
|
|
9
|
+
* /static/announcements.json, used when the remote GET fails (offline).
|
|
10
|
+
*
|
|
11
|
+
* Each entry's `placement` picks the channel:
|
|
12
|
+
* - "modal" (default) — big centered splash for the moments that matter.
|
|
13
|
+
* - "banner" — a quiet, persistent strip in the sidebar footer for
|
|
14
|
+
* evergreen notes (a link, a tip, an ask).
|
|
15
|
+
* Both show the newest entry whose id isn't in the shared dismissed set
|
|
16
|
+
* (localStorage `aw-announcements-seen`); dismiss is per-id.
|
|
17
|
+
*
|
|
18
|
+
* The fetch is a single unauthenticated GET with nothing about the user in
|
|
19
|
+
* it — no telemetry. Content fields are rendered as ESCAPED TEXT (the
|
|
20
|
+
* frontend owns all markup), so even though the body comes from a URL there
|
|
21
|
+
* is no injection surface; the CTA url is validated to http(s).
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const REMOTE_URL = 'https://raw.githubusercontent.com/dotdevdotdev/agentwire-dev/main/agentwire/static/announcements.json';
|
|
25
|
+
const LOCAL_URL = '/static/announcements.json';
|
|
26
|
+
const SEEN_KEY = 'aw-announcements-seen';
|
|
27
|
+
const FETCH_TIMEOUT_MS = 4000;
|
|
28
|
+
|
|
29
|
+
let modalEl = null;
|
|
30
|
+
let escHandler = null;
|
|
31
|
+
|
|
32
|
+
function escapeHtml(s) {
|
|
33
|
+
return String(s).replace(/[&<>"']/g, (c) => (
|
|
34
|
+
{ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]
|
|
35
|
+
));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function seenIds() {
|
|
39
|
+
try {
|
|
40
|
+
const raw = localStorage.getItem(SEEN_KEY);
|
|
41
|
+
const arr = raw ? JSON.parse(raw) : [];
|
|
42
|
+
return Array.isArray(arr) ? arr : [];
|
|
43
|
+
} catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function markSeen(id) {
|
|
49
|
+
const ids = seenIds();
|
|
50
|
+
if (!ids.includes(id)) {
|
|
51
|
+
ids.push(id);
|
|
52
|
+
try { localStorage.setItem(SEEN_KEY, JSON.stringify(ids)); } catch { /* ignore */ }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function fetchJson(url) {
|
|
57
|
+
const ctrl = new AbortController();
|
|
58
|
+
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
59
|
+
try {
|
|
60
|
+
// No credentials, no caching, nothing about the user goes out.
|
|
61
|
+
const resp = await fetch(url, { signal: ctrl.signal, cache: 'no-store', credentials: 'omit' });
|
|
62
|
+
if (!resp.ok) return null;
|
|
63
|
+
return await resp.json();
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
} finally {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** A valid, safe http(s) URL, or null. */
|
|
72
|
+
function safeUrl(url) {
|
|
73
|
+
try {
|
|
74
|
+
const u = new URL(String(url));
|
|
75
|
+
return (u.protocol === 'https:' || u.protocol === 'http:') ? u.href : null;
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Newest (file order) unseen announcement matching `placement` (default "modal"). */
|
|
82
|
+
function pickUnseen(list, placement) {
|
|
83
|
+
const seen = seenIds();
|
|
84
|
+
return list.find((a) => (
|
|
85
|
+
a && typeof a.id === 'string' && a.id
|
|
86
|
+
&& (a.placement || 'modal') === placement
|
|
87
|
+
&& !seen.includes(a.id)
|
|
88
|
+
)) || null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function renderModal(a) {
|
|
92
|
+
const emoji = a.emoji ? `<div class="announcement-emoji">${escapeHtml(a.emoji)}</div>` : '';
|
|
93
|
+
const date = a.date ? `<div class="announcement-date">${escapeHtml(a.date)}</div>` : '';
|
|
94
|
+
const highlights = Array.isArray(a.highlights) && a.highlights.length
|
|
95
|
+
? `<ul class="announcement-highlights">${a.highlights
|
|
96
|
+
.map((h) => `<li>${escapeHtml(h)}</li>`).join('')}</ul>`
|
|
97
|
+
: '';
|
|
98
|
+
const ctaUrl = a.cta && safeUrl(a.cta.url);
|
|
99
|
+
const cta = ctaUrl
|
|
100
|
+
? `<a class="announcement-cta" href="${escapeHtml(ctaUrl)}" target="_blank" rel="noopener noreferrer">${escapeHtml(a.cta.label || 'Learn more')}</a>`
|
|
101
|
+
: '';
|
|
102
|
+
return `<div class="modal-overlay announcement-overlay" id="announcementOverlay">
|
|
103
|
+
<div class="modal announcement-modal" role="dialog" aria-label="Announcement" aria-modal="true">
|
|
104
|
+
<button class="announcement-dismiss" data-action="dismiss" title="Dismiss" aria-label="Dismiss">✕</button>
|
|
105
|
+
${emoji}
|
|
106
|
+
<h2 class="announcement-title">${escapeHtml(a.title || 'What’s new')}</h2>
|
|
107
|
+
${date}
|
|
108
|
+
<div class="announcement-body">${escapeHtml(a.body || '')}</div>
|
|
109
|
+
${highlights}
|
|
110
|
+
<div class="announcement-footer">
|
|
111
|
+
${cta}
|
|
112
|
+
<button class="announcement-ok" data-action="dismiss">Got it</button>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function closeModal(id) {
|
|
119
|
+
if (id) markSeen(id);
|
|
120
|
+
if (escHandler) { document.removeEventListener('keydown', escHandler); escHandler = null; }
|
|
121
|
+
modalEl?.remove();
|
|
122
|
+
modalEl = null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function showModal(a) {
|
|
126
|
+
if (modalEl) return;
|
|
127
|
+
const wrapper = document.createElement('div');
|
|
128
|
+
wrapper.innerHTML = renderModal(a);
|
|
129
|
+
modalEl = wrapper.firstElementChild;
|
|
130
|
+
document.body.appendChild(modalEl);
|
|
131
|
+
|
|
132
|
+
modalEl.addEventListener('click', (e) => {
|
|
133
|
+
if (e.target === modalEl || e.target.closest('[data-action="dismiss"]')) {
|
|
134
|
+
closeModal(a.id);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
escHandler = (e) => { if (e.key === 'Escape') closeModal(a.id); };
|
|
138
|
+
document.addEventListener('keydown', escHandler);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function renderBanner(a) {
|
|
142
|
+
const slot = document.getElementById('sidebarAnnouncementBanner');
|
|
143
|
+
if (!slot) return;
|
|
144
|
+
const ctaUrl = a.cta && safeUrl(a.cta.url);
|
|
145
|
+
const title = a.emoji ? `${escapeHtml(a.emoji)} ${escapeHtml(a.title || '')}` : escapeHtml(a.title || '');
|
|
146
|
+
const cta = ctaUrl
|
|
147
|
+
? `<a class="announcement-banner-cta" href="${escapeHtml(ctaUrl)}" target="_blank" rel="noopener noreferrer">${escapeHtml(a.cta.label || 'Learn more')} →</a>`
|
|
148
|
+
: '';
|
|
149
|
+
slot.innerHTML = `<div class="announcement-banner">
|
|
150
|
+
<button class="announcement-banner-dismiss" data-action="dismiss" title="Dismiss" aria-label="Dismiss announcement">✕</button>
|
|
151
|
+
${title ? `<div class="announcement-banner-title">${title}</div>` : ''}
|
|
152
|
+
${a.body ? `<div class="announcement-banner-body">${escapeHtml(a.body)}</div>` : ''}
|
|
153
|
+
${cta}
|
|
154
|
+
</div>`;
|
|
155
|
+
slot.querySelector('[data-action="dismiss"]')?.addEventListener('click', () => {
|
|
156
|
+
markSeen(a.id);
|
|
157
|
+
slot.innerHTML = '';
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Fetch announcements (remote first, bundled fallback) and surface the newest
|
|
163
|
+
* unseen entry per channel: a centered modal and a sidebar-footer banner.
|
|
164
|
+
* Fails silently — an announcement is never worth a broken portal.
|
|
165
|
+
*/
|
|
166
|
+
export async function initAnnouncements() {
|
|
167
|
+
try {
|
|
168
|
+
const data = (await fetchJson(REMOTE_URL)) || (await fetchJson(LOCAL_URL));
|
|
169
|
+
const list = Array.isArray(data?.announcements) ? data.announcements : [];
|
|
170
|
+
if (!list.length) return;
|
|
171
|
+
const modal = pickUnseen(list, 'modal');
|
|
172
|
+
if (modal) showModal(modal);
|
|
173
|
+
const banner = pickUnseen(list, 'banner');
|
|
174
|
+
if (banner) renderBanner(banner);
|
|
175
|
+
} catch {
|
|
176
|
+
/* never let an announcement break the desktop */
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -32,6 +32,7 @@ import { armDeadKeySuppressor, disarmDeadKeySuppressor } from './dead-key-suppre
|
|
|
32
32
|
import { openCommandPalette, isCommandPaletteOpen } from './command-palette.js';
|
|
33
33
|
import * as browserStt from './voice/browser-stt.js';
|
|
34
34
|
import { voicePromptWrap } from './voice/prompt.js';
|
|
35
|
+
import { initAnnouncements } from './announcement-modal.js';
|
|
35
36
|
|
|
36
37
|
// State - track open windows
|
|
37
38
|
const sessionWindows = new Map(); // sessionId -> SessionWindow instance
|
|
@@ -251,6 +252,10 @@ async function init() {
|
|
|
251
252
|
|
|
252
253
|
// Fetch initial data in the background (will emit events to listeners above)
|
|
253
254
|
desktop.fetchSessions();
|
|
255
|
+
|
|
256
|
+
// Show a userbase announcement if there's a new one (non-blocking,
|
|
257
|
+
// fails silently — never holds up or breaks the desktop).
|
|
258
|
+
initAnnouncements();
|
|
254
259
|
}
|
|
255
260
|
|
|
256
261
|
/**
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
<!-- Phase 3: list panel accordion sections mount here -->
|
|
39
39
|
</div>
|
|
40
40
|
<div class="sidebar-footer">
|
|
41
|
+
<div class="sidebar-announcement-slot" id="sidebarAnnouncementBanner"></div>
|
|
41
42
|
<div class="instant-mode-banner" id="instantModeBanner" hidden>
|
|
42
43
|
<div class="instant-mode-banner-title">⚡ Instant voice mode</div>
|
|
43
44
|
<div class="instant-mode-banner-body">
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""The bundled announcements.json must parse and match the modal's schema.
|
|
2
|
+
|
|
3
|
+
It ships in the wheel as the offline fallback AND is the remote source the
|
|
4
|
+
portal fetches from `main`, so a malformed entry would reach every user.
|
|
5
|
+
This guards the shape the frontend (announcement-modal.js) renders.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from urllib.parse import urlparse
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
ANNOUNCEMENTS = Path(__file__).resolve().parents[2] / "agentwire" / "static" / "announcements.json"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture(scope="module")
|
|
18
|
+
def data():
|
|
19
|
+
assert ANNOUNCEMENTS.exists(), f"missing {ANNOUNCEMENTS}"
|
|
20
|
+
return json.loads(ANNOUNCEMENTS.read_text())
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_top_level_shape(data):
|
|
24
|
+
assert isinstance(data, dict)
|
|
25
|
+
assert isinstance(data.get("announcements"), list)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_ids_present_and_unique(data):
|
|
29
|
+
ids = [a["id"] for a in data["announcements"]]
|
|
30
|
+
assert all(isinstance(i, str) and i for i in ids), "every announcement needs a non-empty string id"
|
|
31
|
+
assert len(ids) == len(set(ids)), "announcement ids must be unique (dedup is by id)"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_required_and_typed_fields(data):
|
|
35
|
+
for a in data["announcements"]:
|
|
36
|
+
assert isinstance(a.get("title"), str) and a["title"], f"{a.get('id')}: title required"
|
|
37
|
+
assert isinstance(a.get("body"), str) and a["body"], f"{a.get('id')}: body required"
|
|
38
|
+
if "highlights" in a:
|
|
39
|
+
assert isinstance(a["highlights"], list)
|
|
40
|
+
assert all(isinstance(h, str) for h in a["highlights"])
|
|
41
|
+
if "emoji" in a:
|
|
42
|
+
assert isinstance(a["emoji"], str)
|
|
43
|
+
if "date" in a:
|
|
44
|
+
assert isinstance(a["date"], str)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_placement_valid(data):
|
|
48
|
+
for a in data["announcements"]:
|
|
49
|
+
placement = a.get("placement", "modal")
|
|
50
|
+
assert placement in ("modal", "banner"), f"{a['id']}: placement must be modal|banner"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_cta_is_safe_https(data):
|
|
54
|
+
for a in data["announcements"]:
|
|
55
|
+
cta = a.get("cta")
|
|
56
|
+
if cta is None:
|
|
57
|
+
continue
|
|
58
|
+
assert isinstance(cta.get("label"), str) and cta["label"], f"{a['id']}: cta needs a label"
|
|
59
|
+
scheme = urlparse(cta.get("url", "")).scheme
|
|
60
|
+
assert scheme in ("http", "https"), f"{a['id']}: cta url must be http(s)"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/audit_logger.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/agentwire.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/containers.yaml
RENAMED
|
File without changes
|
{agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/core.yaml
RENAMED
|
File without changes
|
{agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/databases.yaml
RENAMED
|
File without changes
|
{agentwire_dev-1.31.0 → agentwire_dev-1.32.0}/agentwire/hooks/damage-control/rules/firebase.yaml
RENAMED
|
File without changes
|