agentwire-dev 1.26.0__tar.gz → 1.27.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.26.0 → agentwire_dev-1.27.0}/PKG-INFO +1 -1
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/cli_safety.py +4 -1
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/config.py +22 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/audit_logger.py +46 -1
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +185 -17
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +178 -16
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +178 -16
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/project_config.py +18 -2
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/safety/_core.py +171 -15
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/server.py +111 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/css/desktop.css +423 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/desktop.js +2 -0
- agentwire_dev-1.27.0/agentwire/static/js/safety-shared.js +164 -0
- agentwire_dev-1.27.0/agentwire/static/js/safety-window.js +172 -0
- agentwire_dev-1.27.0/agentwire/static/js/sidebar/safety-section.js +131 -0
- agentwire_dev-1.27.0/tests/unit/test_safety_disabled_rules.py +36 -0
- agentwire_dev-1.27.0/tests/unit/test_safety_escape_hatch.py +39 -0
- agentwire_dev-1.27.0/tests/unit/test_safety_kill_switch.py +34 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/.gitignore +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/CHANGELOG.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/CLA.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/Dockerfile.runpod +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/LICENSE +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/README.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/RELEASING.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/SECURITY.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/bridges/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/bridges/telegram.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/_template.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/discord.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/slack.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/sms.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/telegram.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/channels/webhook.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/overnight.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/prompts/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/prompts/init.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/app.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/commands.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/context.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/mentions.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/persistence.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/state.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/textual_app.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/views/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/repl/views/fanout.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/channel-admin.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/discord-dm.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/slack-dm.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/scheduler.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/capabilities.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/client.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/damage_control.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/errors.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/events.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/render.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/sinks/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/sinks/base.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/sinks/textual.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/sdk/state.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/search.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-Echo--black.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-Echo--transparent.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-Echo.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-email-banner.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--transparent.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/favicon.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/android.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/automaton.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/bot.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/droid.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/drone.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/guardian.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/mech.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/probe.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/robot.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/unit.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/blob.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/cloud.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/crystal.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/flame.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/horned.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/moon.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/slime.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/star.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/winged.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/bear.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/cat.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/crown.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/deer.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/drone.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/fox.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/horse.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/lion.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/robot.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/components/icon-picker.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/components/list-card.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/components/type-tag.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/quicktask-modal.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/sdk-sessions-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/socials-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/workflows-section.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/utils/auto-refresh.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/windows/chat-window.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/windows/sdk-watch-window.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/static/js/windows/workflow-window.js +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/stt/whisperkit.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/qwen_base.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/qwen_custom.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/qwen_design.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts/runpod_handler.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/voices/darren.wav +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/voices/default.wav +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/voices/jessica.wav +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/voices/lisa.wav +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/voices/may.wav +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/cli.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/context.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/definitions.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/node.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/outputs.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/pi_runner.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/runner.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/runners/__init__.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/runners/anthropic.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/runners/human_gate.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/runners/pi.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/workflows/storage.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/logo.png +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/scheduling/workflows.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/sessions/repl-tui.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/tts/runpod-tts.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/docs/wiki/tts/tts-self-hosted.md +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/pyproject.toml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/requirements-tts.txt +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/integration/test_anthropic_runner_live.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/integration/test_channels_cli.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/snapshot/__snapshots__/test_repl_snapshots/test_empty_boot_snapshot.raw +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/snapshot/apps/repl_empty.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/snapshot/test_repl_snapshots.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_anthropic_capabilities.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_anthropic_classify.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_anthropic_events.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_cli_safety.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_human_gate_runner.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_overnight_resume_flags.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_pi_runner.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_commands.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_context.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_damage_control.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_fanout.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_mentions.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_persistence.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_sdk.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_sink_wrap.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_tail.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_textual_app.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_runner_on_event.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_runner_override.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_runners_registry.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_scheduler_workflow_dispatch.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_sdk_session_types.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_search.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_server_sdk_watch.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_server_workflow_history.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_workflow_cli.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_workflow_storage.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_workflows.py +0 -0
- {agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/tests/unit/test_worktree.py +0 -0
|
@@ -190,7 +190,10 @@ def query_audit_logs(
|
|
|
190
190
|
if today:
|
|
191
191
|
log_files = [LOGS_DIR / f"{datetime.now().strftime('%Y-%m-%d')}.jsonl"]
|
|
192
192
|
else:
|
|
193
|
-
|
|
193
|
+
# Sort chronologically (oldest first) so that within the merged list,
|
|
194
|
+
# entries are strictly in time order. Callers that want newest-first
|
|
195
|
+
# (e.g. the portal Safety section) reverse on their end after slicing.
|
|
196
|
+
log_files = sorted(LOGS_DIR.glob("*.jsonl"))
|
|
194
197
|
|
|
195
198
|
for log_file in log_files:
|
|
196
199
|
if not log_file.exists():
|
|
@@ -267,6 +267,14 @@ class OvernightConfig:
|
|
|
267
267
|
self.live_state_file = _expand_path(self.live_state_file) or self.live_state_file
|
|
268
268
|
|
|
269
269
|
|
|
270
|
+
@dataclass
|
|
271
|
+
class SafetyConfig:
|
|
272
|
+
"""Global damage-control safety knobs."""
|
|
273
|
+
|
|
274
|
+
enabled: bool = True
|
|
275
|
+
disabled_rules: list[str] = field(default_factory=list)
|
|
276
|
+
|
|
277
|
+
|
|
270
278
|
@dataclass
|
|
271
279
|
class Config:
|
|
272
280
|
"""Root configuration for AgentWire."""
|
|
@@ -285,6 +293,7 @@ class Config:
|
|
|
285
293
|
repl: ReplConfig = field(default_factory=ReplConfig)
|
|
286
294
|
scheduler: SchedulerConfig = field(default_factory=SchedulerConfig)
|
|
287
295
|
overnight: OvernightConfig = field(default_factory=OvernightConfig)
|
|
296
|
+
safety: SafetyConfig = field(default_factory=SafetyConfig)
|
|
288
297
|
channels: dict = field(default_factory=dict)
|
|
289
298
|
|
|
290
299
|
|
|
@@ -508,6 +517,18 @@ def _dict_to_config(data: dict) -> Config:
|
|
|
508
517
|
theme_overrides = {}
|
|
509
518
|
repl = ReplConfig(theme={str(k): str(v) for k, v in theme_overrides.items()})
|
|
510
519
|
|
|
520
|
+
# Safety (damage-control kill switch + disabled rules)
|
|
521
|
+
safety_data = data.get("safety", {}) or {}
|
|
522
|
+
if not isinstance(safety_data, dict):
|
|
523
|
+
safety_data = {}
|
|
524
|
+
disabled_rules_raw = safety_data.get("disabled_rules", []) or []
|
|
525
|
+
if not isinstance(disabled_rules_raw, list):
|
|
526
|
+
disabled_rules_raw = []
|
|
527
|
+
safety = SafetyConfig(
|
|
528
|
+
enabled=bool(safety_data.get("enabled", True)),
|
|
529
|
+
disabled_rules=[str(r) for r in disabled_rules_raw if r],
|
|
530
|
+
)
|
|
531
|
+
|
|
511
532
|
return Config(
|
|
512
533
|
server=server,
|
|
513
534
|
projects=projects,
|
|
@@ -523,6 +544,7 @@ def _dict_to_config(data: dict) -> Config:
|
|
|
523
544
|
overnight=overnight,
|
|
524
545
|
channels=channel_configs,
|
|
525
546
|
repl=repl,
|
|
547
|
+
safety=safety,
|
|
526
548
|
)
|
|
527
549
|
|
|
528
550
|
|
{agentwire_dev-1.26.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/audit_logger.py
RENAMED
|
@@ -56,6 +56,9 @@ def log_entry(
|
|
|
56
56
|
blocked_by: Optional[str] = None,
|
|
57
57
|
user_approved: Optional[bool] = None,
|
|
58
58
|
pattern_matched: Optional[str] = None,
|
|
59
|
+
rule_id: Optional[str] = None,
|
|
60
|
+
escape_reason: Optional[str] = None,
|
|
61
|
+
cwd: Optional[str] = None,
|
|
59
62
|
) -> None:
|
|
60
63
|
"""
|
|
61
64
|
Write a log entry to the audit log.
|
|
@@ -63,11 +66,15 @@ def log_entry(
|
|
|
63
66
|
Args:
|
|
64
67
|
tool: Tool name (Bash, Edit, Write)
|
|
65
68
|
command: Command or path that was checked
|
|
66
|
-
decision: "blocked", "asked", or "
|
|
69
|
+
decision: "blocked", "asked", "allowed", "allowed_by_escape", or "allowed_by_disabled"
|
|
67
70
|
blocked_by: Reason/pattern that triggered block
|
|
68
71
|
user_approved: Whether user approved (for ask patterns)
|
|
69
72
|
pattern_matched: The regex pattern that matched
|
|
73
|
+
rule_id: Stable identifier of the matched rule (when applicable)
|
|
74
|
+
escape_reason: Reason supplied via "# allow:" escape hatch (when applicable)
|
|
75
|
+
cwd: Working directory where the command would have run
|
|
70
76
|
"""
|
|
77
|
+
import os
|
|
71
78
|
context = get_session_context()
|
|
72
79
|
|
|
73
80
|
entry = {
|
|
@@ -80,6 +87,9 @@ def log_entry(
|
|
|
80
87
|
"blocked_by": blocked_by,
|
|
81
88
|
"user_approved": user_approved,
|
|
82
89
|
"pattern_matched": pattern_matched,
|
|
90
|
+
"rule_id": rule_id,
|
|
91
|
+
"escape_reason": escape_reason,
|
|
92
|
+
"cwd": cwd or os.environ.get("PWD") or os.getcwd(),
|
|
83
93
|
}
|
|
84
94
|
|
|
85
95
|
log_file = get_log_file()
|
|
@@ -94,6 +104,7 @@ def log_blocked(
|
|
|
94
104
|
command: str,
|
|
95
105
|
reason: str,
|
|
96
106
|
pattern: Optional[str] = None,
|
|
107
|
+
rule_id: Optional[str] = None,
|
|
97
108
|
) -> None:
|
|
98
109
|
"""
|
|
99
110
|
Log a blocked operation.
|
|
@@ -103,6 +114,7 @@ def log_blocked(
|
|
|
103
114
|
command: Command or path that was blocked
|
|
104
115
|
reason: Human-readable reason for block
|
|
105
116
|
pattern: The regex pattern that matched
|
|
117
|
+
rule_id: Stable identifier of the matched rule
|
|
106
118
|
"""
|
|
107
119
|
log_entry(
|
|
108
120
|
tool=tool,
|
|
@@ -110,6 +122,39 @@ def log_blocked(
|
|
|
110
122
|
decision="blocked",
|
|
111
123
|
blocked_by=reason,
|
|
112
124
|
pattern_matched=pattern,
|
|
125
|
+
rule_id=rule_id,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def log_escape(
|
|
130
|
+
tool: str,
|
|
131
|
+
command: str,
|
|
132
|
+
escape_reason: str,
|
|
133
|
+
) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Log a command that was allowed through the ``# allow: <reason>`` escape hatch.
|
|
136
|
+
"""
|
|
137
|
+
log_entry(
|
|
138
|
+
tool=tool,
|
|
139
|
+
command=command,
|
|
140
|
+
decision="allowed_by_escape",
|
|
141
|
+
blocked_by=f"Escape hatch: {escape_reason}",
|
|
142
|
+
escape_reason=escape_reason,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def log_disabled(
|
|
147
|
+
tool: str,
|
|
148
|
+
command: str,
|
|
149
|
+
) -> None:
|
|
150
|
+
"""
|
|
151
|
+
Log a command that was allowed because the safety system is disabled.
|
|
152
|
+
"""
|
|
153
|
+
log_entry(
|
|
154
|
+
tool=tool,
|
|
155
|
+
command=command,
|
|
156
|
+
decision="allowed_by_disabled",
|
|
157
|
+
blocked_by="safety disabled",
|
|
113
158
|
)
|
|
114
159
|
|
|
115
160
|
|
|
@@ -24,11 +24,13 @@ from pathlib import Path
|
|
|
24
24
|
|
|
25
25
|
# audit_logger lives next to this script
|
|
26
26
|
try:
|
|
27
|
-
from audit_logger import log_allowed, log_asked, log_blocked
|
|
27
|
+
from audit_logger import log_allowed, log_asked, log_blocked, log_disabled, log_escape
|
|
28
28
|
except ImportError:
|
|
29
29
|
def log_allowed(*args, **kwargs): pass
|
|
30
30
|
def log_asked(*args, **kwargs): pass
|
|
31
31
|
def log_blocked(*args, **kwargs): pass
|
|
32
|
+
def log_disabled(*args, **kwargs): pass
|
|
33
|
+
def log_escape(*args, **kwargs): pass
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
# === BEGIN GENERATED FROM agentwire/safety/_core.py ===
|
|
@@ -408,11 +410,42 @@ def load_write_patterns_from_tooldefs(tooldefs_dir: Optional[Path]) -> List[Dict
|
|
|
408
410
|
return patterns
|
|
409
411
|
|
|
410
412
|
|
|
413
|
+
_RULE_ID_SLUG_RE = re.compile(r"[^a-z0-9]+")
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def _slug_for_rule(text: str, max_len: int = 60) -> str:
|
|
417
|
+
"""Lowercase, ASCII, kebab-case slug suitable for rule IDs."""
|
|
418
|
+
s = _RULE_ID_SLUG_RE.sub("-", (text or "").lower()).strip("-")
|
|
419
|
+
return s[:max_len] or "rule"
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def _assign_rule_id(pattern_obj: Dict[str, Any], file_stem: str, taken: set) -> str:
|
|
423
|
+
"""Generate (or honor) an ID for a bash pattern. Mutates pattern_obj in place."""
|
|
424
|
+
existing = pattern_obj.get("id")
|
|
425
|
+
if isinstance(existing, str) and existing.strip():
|
|
426
|
+
pattern_obj["id"] = existing.strip()
|
|
427
|
+
taken.add(pattern_obj["id"])
|
|
428
|
+
return pattern_obj["id"]
|
|
429
|
+
slug = _slug_for_rule(pattern_obj.get("reason", "rule"))
|
|
430
|
+
candidate = f"{file_stem}.{slug}"
|
|
431
|
+
n = 2
|
|
432
|
+
while candidate in taken:
|
|
433
|
+
candidate = f"{file_stem}.{slug}-{n}"
|
|
434
|
+
n += 1
|
|
435
|
+
pattern_obj["id"] = candidate
|
|
436
|
+
taken.add(candidate)
|
|
437
|
+
return candidate
|
|
438
|
+
|
|
439
|
+
|
|
411
440
|
def load_config(
|
|
412
441
|
rules_dir: Path,
|
|
413
442
|
tooldefs_dir: Optional[Path] = None,
|
|
414
443
|
) -> Dict[str, Any]:
|
|
415
|
-
"""Load and merge all rule YAMLs in ``rules_dir`` plus tooldef ask-patterns.
|
|
444
|
+
"""Load and merge all rule YAMLs in ``rules_dir`` plus tooldef ask-patterns.
|
|
445
|
+
|
|
446
|
+
Bash patterns get a stable ``id`` field (``"<file>.<slug-of-reason>"``) so
|
|
447
|
+
they can be referenced by the ``safety.disabled_rules`` config.
|
|
448
|
+
"""
|
|
416
449
|
merged: Dict[str, Any] = {
|
|
417
450
|
"bashToolPatterns": [],
|
|
418
451
|
"zeroAccessPaths": [],
|
|
@@ -422,22 +455,110 @@ def load_config(
|
|
|
422
455
|
}
|
|
423
456
|
if not yaml or not rules_dir.exists():
|
|
424
457
|
return merged
|
|
458
|
+
taken_ids: set = set()
|
|
425
459
|
yaml_files = sorted(rules_dir.glob("*.yaml"))
|
|
426
460
|
for rules_file in yaml_files:
|
|
427
461
|
try:
|
|
428
462
|
with open(rules_file, "r") as f:
|
|
429
463
|
data = yaml.safe_load(f) or {}
|
|
430
464
|
for key in merged:
|
|
431
|
-
|
|
465
|
+
items = data.get(key, []) or []
|
|
466
|
+
if key == "bashToolPatterns":
|
|
467
|
+
for it in items:
|
|
468
|
+
if isinstance(it, dict):
|
|
469
|
+
_assign_rule_id(it, rules_file.stem, taken_ids)
|
|
470
|
+
it.setdefault("source", rules_file.stem)
|
|
471
|
+
merged[key].extend(items)
|
|
432
472
|
except Exception:
|
|
433
473
|
continue
|
|
434
474
|
if tooldefs_dir is not None:
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
475
|
+
tooldef_patterns = load_write_patterns_from_tooldefs(tooldefs_dir)
|
|
476
|
+
for it in tooldef_patterns:
|
|
477
|
+
_assign_rule_id(it, "tooldef", taken_ids)
|
|
478
|
+
it.setdefault("source", "tooldef")
|
|
479
|
+
merged["bashToolPatterns"].extend(tooldef_patterns)
|
|
438
480
|
return merged
|
|
439
481
|
|
|
440
482
|
|
|
483
|
+
def load_safety_config(
|
|
484
|
+
global_config_path: Optional[Path] = None,
|
|
485
|
+
cwd: Optional[str] = None,
|
|
486
|
+
) -> Dict[str, Any]:
|
|
487
|
+
"""Resolve the effective ``safety`` block from global + nearest project config.
|
|
488
|
+
|
|
489
|
+
Returns ``{enabled: bool, disabled_rules: list[str]}``. Project ``.agentwire.yml``
|
|
490
|
+
overrides global; ``disabled_rules`` are merged (set-union).
|
|
491
|
+
"""
|
|
492
|
+
enabled = True
|
|
493
|
+
disabled_rules: List[str] = []
|
|
494
|
+
project_enabled: Optional[bool] = None
|
|
495
|
+
if not yaml:
|
|
496
|
+
return {"enabled": enabled, "disabled_rules": disabled_rules}
|
|
497
|
+
|
|
498
|
+
if global_config_path is None:
|
|
499
|
+
global_config_path = Path.home() / ".agentwire" / "config.yaml"
|
|
500
|
+
try:
|
|
501
|
+
if global_config_path.exists():
|
|
502
|
+
with open(global_config_path, "r") as f:
|
|
503
|
+
data = yaml.safe_load(f) or {}
|
|
504
|
+
safety = data.get("safety", {})
|
|
505
|
+
if isinstance(safety, dict):
|
|
506
|
+
if "enabled" in safety:
|
|
507
|
+
enabled = bool(safety["enabled"])
|
|
508
|
+
rules = safety.get("disabled_rules", [])
|
|
509
|
+
if isinstance(rules, list):
|
|
510
|
+
disabled_rules.extend(str(r) for r in rules if r)
|
|
511
|
+
except Exception:
|
|
512
|
+
pass
|
|
513
|
+
|
|
514
|
+
if cwd is None:
|
|
515
|
+
cwd = os.environ.get("PWD", os.getcwd())
|
|
516
|
+
current = os.path.abspath(cwd)
|
|
517
|
+
while True:
|
|
518
|
+
candidate = os.path.join(current, ".agentwire.yml")
|
|
519
|
+
if os.path.isfile(candidate):
|
|
520
|
+
try:
|
|
521
|
+
with open(candidate, "r") as f:
|
|
522
|
+
pdata = yaml.safe_load(f) or {}
|
|
523
|
+
psafety = pdata.get("safety", {})
|
|
524
|
+
if isinstance(psafety, dict):
|
|
525
|
+
if "enabled" in psafety and psafety["enabled"] is not None:
|
|
526
|
+
project_enabled = bool(psafety["enabled"])
|
|
527
|
+
prules = psafety.get("disabled_rules", [])
|
|
528
|
+
if isinstance(prules, list):
|
|
529
|
+
disabled_rules.extend(str(r) for r in prules if r)
|
|
530
|
+
except Exception:
|
|
531
|
+
pass
|
|
532
|
+
break
|
|
533
|
+
parent = os.path.dirname(current)
|
|
534
|
+
if parent == current:
|
|
535
|
+
break
|
|
536
|
+
current = parent
|
|
537
|
+
|
|
538
|
+
if project_enabled is not None:
|
|
539
|
+
enabled = project_enabled
|
|
540
|
+
|
|
541
|
+
return {"enabled": enabled, "disabled_rules": sorted(set(disabled_rules))}
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
_ESCAPE_HATCH_RE = re.compile(r"#\s*allow:[ \t]*([^\n]+)", re.IGNORECASE)
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def detect_escape_hatch(command: str) -> Optional[str]:
|
|
548
|
+
"""Return the reason if ``command`` contains a ``# allow: <reason>`` marker.
|
|
549
|
+
|
|
550
|
+
Non-empty reason required; matches the rest of the comment line so the
|
|
551
|
+
marker works on multi-line / chained commands too.
|
|
552
|
+
"""
|
|
553
|
+
if not command:
|
|
554
|
+
return None
|
|
555
|
+
m = _ESCAPE_HATCH_RE.search(command)
|
|
556
|
+
if not m:
|
|
557
|
+
return None
|
|
558
|
+
reason = m.group(1).strip()
|
|
559
|
+
return reason or None
|
|
560
|
+
|
|
561
|
+
|
|
441
562
|
# ============================================================================
|
|
442
563
|
# DECISION LADDERS
|
|
443
564
|
# ============================================================================
|
|
@@ -446,27 +567,57 @@ def load_config(
|
|
|
446
567
|
def check_command(command: str, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
447
568
|
"""Decide whether a bash command should be allowed/blocked/asked.
|
|
448
569
|
|
|
449
|
-
Returns ``{decision, reason, pattern, command}
|
|
570
|
+
Returns ``{decision, reason, pattern, command}`` plus optional ``id``,
|
|
571
|
+
``escape_reason``, ``escape``, ``disabled``.
|
|
450
572
|
|
|
451
573
|
Order:
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
574
|
+
0. Escape hatch (``# allow: <reason>``) → ALLOW (escape=True)
|
|
575
|
+
1. Kill switch (``config["safety"]["enabled"] is False``) → ALLOW (disabled=True)
|
|
576
|
+
2. Hard-blocked bash patterns (skip if ``id`` in ``disabled_rules``)
|
|
577
|
+
3. Ask patterns
|
|
578
|
+
4. Bypassable bash patterns → check allowlist for required operation
|
|
579
|
+
5. zeroAccessPaths → check allowlist with ``read`` permission
|
|
580
|
+
6. readOnlyPaths → match against READ_ONLY_BLOCKED operation patterns
|
|
581
|
+
7. noDeletePaths → match against NO_DELETE_BLOCKED patterns
|
|
458
582
|
"""
|
|
583
|
+
safety_cfg = config.get("safety", {}) if isinstance(config.get("safety"), dict) else {}
|
|
584
|
+
disabled_rules = set(safety_cfg.get("disabled_rules", []) or [])
|
|
585
|
+
is_enabled = safety_cfg.get("enabled", True)
|
|
586
|
+
|
|
587
|
+
escape_reason = detect_escape_hatch(command)
|
|
588
|
+
if escape_reason:
|
|
589
|
+
return {
|
|
590
|
+
"decision": "allow",
|
|
591
|
+
"reason": f"Escape hatch: {escape_reason}",
|
|
592
|
+
"pattern": None,
|
|
593
|
+
"command": command,
|
|
594
|
+
"escape": True,
|
|
595
|
+
"escape_reason": escape_reason,
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if is_enabled is False:
|
|
599
|
+
return {
|
|
600
|
+
"decision": "allow",
|
|
601
|
+
"reason": "safety disabled",
|
|
602
|
+
"pattern": None,
|
|
603
|
+
"command": command,
|
|
604
|
+
"disabled": True,
|
|
605
|
+
}
|
|
606
|
+
|
|
459
607
|
bash_patterns = config.get("bashToolPatterns", [])
|
|
460
608
|
zero_access = config.get("zeroAccessPaths", [])
|
|
461
609
|
read_only = config.get("readOnlyPaths", [])
|
|
462
610
|
no_delete = config.get("noDeletePaths", [])
|
|
463
611
|
allowed = load_allowed_paths(config)
|
|
464
612
|
|
|
465
|
-
bypassable_matches: List[Tuple[str, str]] = []
|
|
613
|
+
bypassable_matches: List[Tuple[str, str, Optional[str]]] = []
|
|
466
614
|
|
|
467
615
|
for pattern_obj in bash_patterns:
|
|
468
616
|
if not isinstance(pattern_obj, dict):
|
|
469
617
|
continue
|
|
618
|
+
rule_id = pattern_obj.get("id")
|
|
619
|
+
if rule_id and rule_id in disabled_rules:
|
|
620
|
+
continue
|
|
470
621
|
pattern = pattern_obj.get("pattern", "")
|
|
471
622
|
reason = pattern_obj.get("reason", "Matched pattern")
|
|
472
623
|
should_ask = pattern_obj.get("ask", False)
|
|
@@ -479,20 +630,22 @@ def check_command(command: str, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
479
630
|
"reason": reason,
|
|
480
631
|
"pattern": pattern,
|
|
481
632
|
"command": command,
|
|
633
|
+
"id": rule_id,
|
|
482
634
|
}
|
|
483
635
|
elif bypassable:
|
|
484
|
-
bypassable_matches.append((pattern, reason))
|
|
636
|
+
bypassable_matches.append((pattern, reason, rule_id))
|
|
485
637
|
else:
|
|
486
638
|
return {
|
|
487
639
|
"decision": "block",
|
|
488
640
|
"reason": reason,
|
|
489
641
|
"pattern": pattern,
|
|
490
642
|
"command": command,
|
|
643
|
+
"id": rule_id,
|
|
491
644
|
}
|
|
492
645
|
except re.error:
|
|
493
646
|
continue
|
|
494
647
|
|
|
495
|
-
for pattern, reason in bypassable_matches:
|
|
648
|
+
for pattern, reason, rule_id in bypassable_matches:
|
|
496
649
|
operation = _infer_operation_from_reason(reason)
|
|
497
650
|
if not is_command_path_allowed(command, allowed, operation):
|
|
498
651
|
return {
|
|
@@ -500,6 +653,7 @@ def check_command(command: str, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
500
653
|
"reason": reason,
|
|
501
654
|
"pattern": pattern,
|
|
502
655
|
"command": command,
|
|
656
|
+
"id": rule_id,
|
|
503
657
|
}
|
|
504
658
|
|
|
505
659
|
for path in zero_access:
|
|
@@ -548,6 +702,10 @@ def check_command(command: str, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
548
702
|
|
|
549
703
|
def check_path(file_path: str, config: Dict[str, Any]) -> Tuple[bool, str]:
|
|
550
704
|
"""File-path-only check used by edit/write hooks. Returns ``(blocked, reason)``."""
|
|
705
|
+
safety_cfg = config.get("safety", {}) if isinstance(config.get("safety"), dict) else {}
|
|
706
|
+
if safety_cfg.get("enabled", True) is False:
|
|
707
|
+
return False, ""
|
|
708
|
+
|
|
551
709
|
allowed = load_allowed_paths(config)
|
|
552
710
|
|
|
553
711
|
if is_path_allowed_for_op(file_path, allowed, "edit"):
|
|
@@ -591,6 +749,7 @@ def _resolve_tooldefs_dir():
|
|
|
591
749
|
|
|
592
750
|
def main() -> None:
|
|
593
751
|
config = load_config(_resolve_rules_dir(), _resolve_tooldefs_dir())
|
|
752
|
+
config["safety"] = load_safety_config()
|
|
594
753
|
|
|
595
754
|
try:
|
|
596
755
|
input_data = json.load(sys.stdin)
|
|
@@ -623,7 +782,10 @@ def main() -> None:
|
|
|
623
782
|
reason = result["reason"]
|
|
624
783
|
|
|
625
784
|
if decision == "block":
|
|
626
|
-
|
|
785
|
+
try:
|
|
786
|
+
log_blocked("Bash", command, reason, pattern=result.get("pattern"), rule_id=result.get("id"))
|
|
787
|
+
except TypeError:
|
|
788
|
+
log_blocked("Bash", command, reason)
|
|
627
789
|
print(f"SECURITY: Blocked: {reason}", file=sys.stderr)
|
|
628
790
|
print(f"Command: {command[:100]}{'...' if len(command) > 100 else ''}", file=sys.stderr)
|
|
629
791
|
sys.exit(2)
|
|
@@ -638,6 +800,12 @@ def main() -> None:
|
|
|
638
800
|
}
|
|
639
801
|
print(json.dumps(output))
|
|
640
802
|
sys.exit(0)
|
|
803
|
+
elif result.get("escape"):
|
|
804
|
+
log_escape("Bash", command, result.get("escape_reason") or "")
|
|
805
|
+
sys.exit(0)
|
|
806
|
+
elif result.get("disabled"):
|
|
807
|
+
log_disabled("Bash", command)
|
|
808
|
+
sys.exit(0)
|
|
641
809
|
else:
|
|
642
810
|
log_allowed("Bash", command, user_approved=False)
|
|
643
811
|
sys.exit(0)
|