agentwire-dev 1.25.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.25.0 → agentwire_dev-1.27.0}/PKG-INFO +1 -1
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/__main__.py +37 -18
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/cli_safety.py +4 -1
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/config.py +22 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/audit_logger.py +46 -1
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +185 -17
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +178 -16
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +178 -16
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/project_config.py +18 -2
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/safety/_core.py +171 -15
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/server.py +117 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/css/desktop.css +812 -166
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/desktop.js +13 -0
- agentwire_dev-1.27.0/agentwire/static/js/quicktask-modal.js +257 -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.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/session-window.js +40 -4
- agentwire_dev-1.27.0/agentwire/static/js/sidebar/config-section.js +63 -0
- agentwire_dev-1.27.0/agentwire/static/js/sidebar/safety-section.js +131 -0
- agentwire_dev-1.27.0/agentwire/static/js/terminal-font-prefs.js +43 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/templates/desktop.html +3 -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.25.0/agentwire/static/js/sidebar/config-section.js +0 -20
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/.gitignore +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/CHANGELOG.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/CLA.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/Dockerfile.runpod +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/LICENSE +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/README.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/RELEASING.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/SECURITY.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/bridges/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/bridges/telegram.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/_template.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/discord.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/slack.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/sms.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/telegram.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/channels/webhook.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/overnight.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/prompts/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/prompts/init.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/app.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/commands.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/context.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/mentions.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/persistence.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/state.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/textual_app.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/views/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/repl/views/fanout.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/channel-admin.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/discord-dm.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/slack-dm.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/scheduler.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/capabilities.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/client.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/damage_control.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/errors.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/events.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/render.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/sinks/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/sinks/base.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/sinks/textual.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/sdk/state.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/search.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-Echo--black.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-Echo--transparent.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-Echo.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-email-banner.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--transparent.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/favicon.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/android.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/automaton.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/bot.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/droid.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/drone.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/guardian.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/mech.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/probe.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/robot.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/machines/unit.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/blob.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/cloud.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/crystal.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/flame.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/horned.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/moon.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/slime.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/star.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/projects/winged.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/bear.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/cat.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/crown.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/deer.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/drone.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/fox.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/horse.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/lion.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/robot.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/components/icon-picker.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/components/list-card.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/components/type-tag.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/sdk-sessions-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/socials-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar/workflows-section.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/utils/auto-refresh.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/windows/chat-window.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/windows/sdk-watch-window.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/static/js/windows/workflow-window.js +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/stt/whisperkit.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/qwen_base.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/qwen_custom.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/qwen_design.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts/runpod_handler.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/voices/darren.wav +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/voices/default.wav +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/voices/jessica.wav +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/voices/lisa.wav +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/voices/may.wav +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/cli.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/context.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/definitions.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/node.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/outputs.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/pi_runner.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/runner.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/runners/__init__.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/runners/anthropic.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/runners/human_gate.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/runners/pi.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/workflows/storage.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/logo.png +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/scheduling/workflows.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/sessions/repl-tui.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/tts/runpod-tts.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/docs/wiki/tts/tts-self-hosted.md +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/pyproject.toml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/requirements-tts.txt +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/integration/test_anthropic_runner_live.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/integration/test_channels_cli.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/snapshot/__snapshots__/test_repl_snapshots/test_empty_boot_snapshot.raw +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/snapshot/apps/repl_empty.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/snapshot/test_repl_snapshots.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_anthropic_capabilities.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_anthropic_classify.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_anthropic_events.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_cli_safety.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_human_gate_runner.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_overnight_resume_flags.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_pi_runner.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_commands.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_context.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_damage_control.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_fanout.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_mentions.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_persistence.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_sdk.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_sink_wrap.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_tail.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_repl_textual_app.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_runner_on_event.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_runner_override.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_runners_registry.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_scheduler_workflow_dispatch.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_sdk_session_types.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_search.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_server_sdk_watch.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_server_workflow_history.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_workflow_cli.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_workflow_storage.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_workflows.py +0 -0
- {agentwire_dev-1.25.0 → agentwire_dev-1.27.0}/tests/unit/test_worktree.py +0 -0
|
@@ -3650,6 +3650,34 @@ def cmd_new(args) -> int:
|
|
|
3650
3650
|
|
|
3651
3651
|
# Local session
|
|
3652
3652
|
# Resolve path
|
|
3653
|
+
base_branch = getattr(args, 'base', 'main') or 'main'
|
|
3654
|
+
pull_first = getattr(args, 'pull_first', True)
|
|
3655
|
+
|
|
3656
|
+
def _spawn_worktree(project_path: Path, session_path: Path) -> tuple[bool, str | None]:
|
|
3657
|
+
"""Fetch origin/<base> if requested, then create worktree starting at that ref."""
|
|
3658
|
+
worktree_commit: str | None = None
|
|
3659
|
+
if pull_first:
|
|
3660
|
+
fetch = subprocess.run(
|
|
3661
|
+
["git", "fetch", "origin", base_branch],
|
|
3662
|
+
cwd=project_path,
|
|
3663
|
+
capture_output=True,
|
|
3664
|
+
text=True,
|
|
3665
|
+
)
|
|
3666
|
+
if fetch.returncode != 0:
|
|
3667
|
+
stderr = (fetch.stderr or fetch.stdout or "").strip()
|
|
3668
|
+
return False, f"git fetch origin {base_branch} failed: {stderr}"
|
|
3669
|
+
worktree_commit = f"origin/{base_branch}"
|
|
3670
|
+
ok = ensure_worktree(
|
|
3671
|
+
project_path,
|
|
3672
|
+
branch,
|
|
3673
|
+
session_path,
|
|
3674
|
+
auto_create_branch=auto_create_branch,
|
|
3675
|
+
commit=worktree_commit,
|
|
3676
|
+
)
|
|
3677
|
+
if not ok:
|
|
3678
|
+
return False, f"Failed to create worktree for branch '{branch}' in {project_path}"
|
|
3679
|
+
return True, None
|
|
3680
|
+
|
|
3653
3681
|
if path and branch and worktrees_enabled:
|
|
3654
3682
|
# Path + branch: use provided path as main repo, create worktree from it
|
|
3655
3683
|
project_path = Path(path).expanduser().resolve()
|
|
@@ -3659,15 +3687,9 @@ def cmd_new(args) -> int:
|
|
|
3659
3687
|
if not session_path.exists():
|
|
3660
3688
|
if not project_path.exists():
|
|
3661
3689
|
return _output_result(False, json_mode, f"Project path does not exist: {project_path}")
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
branch,
|
|
3666
|
-
session_path,
|
|
3667
|
-
auto_create_branch=auto_create_branch,
|
|
3668
|
-
)
|
|
3669
|
-
if not success:
|
|
3670
|
-
return _output_result(False, json_mode, f"Failed to create worktree for branch '{branch}' in {project_path}")
|
|
3690
|
+
ok, err = _spawn_worktree(project_path, session_path)
|
|
3691
|
+
if not ok:
|
|
3692
|
+
return _output_result(False, json_mode, err or "worktree creation failed")
|
|
3671
3693
|
elif path:
|
|
3672
3694
|
session_path = Path(path).expanduser().resolve()
|
|
3673
3695
|
elif branch and worktrees_enabled:
|
|
@@ -3679,15 +3701,9 @@ def cmd_new(args) -> int:
|
|
|
3679
3701
|
if not session_path.exists():
|
|
3680
3702
|
if not project_path.exists():
|
|
3681
3703
|
return _output_result(False, json_mode, f"Project path does not exist: {project_path}")
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
branch,
|
|
3686
|
-
session_path,
|
|
3687
|
-
auto_create_branch=auto_create_branch,
|
|
3688
|
-
)
|
|
3689
|
-
if not success:
|
|
3690
|
-
return _output_result(False, json_mode, f"Failed to create worktree for branch '{branch}' in {project_path}")
|
|
3704
|
+
ok, err = _spawn_worktree(project_path, session_path)
|
|
3705
|
+
if not ok:
|
|
3706
|
+
return _output_result(False, json_mode, err or "worktree creation failed")
|
|
3691
3707
|
else:
|
|
3692
3708
|
# Simple session: ~/projects/project/
|
|
3693
3709
|
session_path = projects_dir / project
|
|
@@ -10552,6 +10568,9 @@ def main() -> int:
|
|
|
10552
10568
|
new_parser.add_argument("--model", help="Model override (e.g., haiku, sonnet, opus)")
|
|
10553
10569
|
new_parser.add_argument("--persist", action="store_true", help="Write --type/--roles to .agentwire.yml (default: session-level override only)")
|
|
10554
10570
|
new_parser.add_argument("--env", action="append", metavar="KEY=VAL", help="Inject env var via `tmux set-environment` (repeatable, keeps secrets out of `ps`)")
|
|
10571
|
+
new_parser.add_argument("--base", default="main", help="For worktree sessions: base branch to fork the new branch from (default: main)")
|
|
10572
|
+
new_parser.add_argument("--pull-first", dest="pull_first", action="store_true", default=True, help="For worktree sessions: fetch origin/<base> before branching (default)")
|
|
10573
|
+
new_parser.add_argument("--no-pull-first", dest="pull_first", action="store_false", help="Skip the fetch — branch from the local copy of <base> as-is")
|
|
10555
10574
|
new_parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
10556
10575
|
new_parser.set_defaults(func=cmd_new)
|
|
10557
10576
|
|
|
@@ -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.25.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)
|