agentwire-dev 1.28.1__tar.gz → 1.29.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.28.1 → agentwire_dev-1.29.0}/CHANGELOG.md +1 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/PKG-INFO +1 -1
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/__main__.py +161 -181
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +89 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +89 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +89 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/mcp_server.py +282 -119
- agentwire_dev-1.29.0/agentwire/missions/__init__.py +30 -0
- agentwire_dev-1.29.0/agentwire/missions/cli.py +521 -0
- agentwire_dev-1.29.0/agentwire/missions/config.py +93 -0
- agentwire_dev-1.29.0/agentwire/missions/dispatcher.py +325 -0
- agentwire_dev-1.29.0/agentwire/missions/eligibility.py +61 -0
- agentwire_dev-1.29.0/agentwire/missions/feedback_router.py +248 -0
- agentwire_dev-1.29.0/agentwire/missions/gc.py +228 -0
- agentwire_dev-1.29.0/agentwire/missions/github.py +252 -0
- agentwire_dev-1.29.0/agentwire/missions/naming.py +83 -0
- agentwire_dev-1.29.0/agentwire/missions/state.py +136 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/pane_manager.py +53 -31
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/safety/_core.py +89 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/scheduler.py +12 -239
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/server.py +42 -134
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/css/desktop.css +44 -205
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/desktop.js +2 -2
- agentwire_dev-1.29.0/agentwire/static/js/sidebar/missions-section.js +144 -0
- agentwire_dev-1.29.0/agentwire/static/js/sidebar/scheduler-section.js +179 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/INDEX.md +2 -3
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/architecture.md +17 -21
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/concepts.md +5 -9
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/glossary.md +2 -5
- agentwire_dev-1.29.0/docs/wiki/missions.md +263 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/quickstart.md +0 -1
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/scheduling/scheduled-workloads.md +3 -23
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/pyproject.toml +0 -2
- agentwire_dev-1.29.0/templates/launchd/dev.agentwire.mission-dispatcher.plist +70 -0
- agentwire_dev-1.29.0/templates/launchd/dev.agentwire.mission-feedback-router.plist +49 -0
- agentwire_dev-1.29.0/templates/launchd/dev.agentwire.mission-janitor.plist +51 -0
- agentwire_dev-1.29.0/tests/integration/test_missions_concurrency.py +150 -0
- agentwire_dev-1.29.0/tests/integration/test_missions_lifecycle.py +236 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_cli.py +403 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_config.py +97 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_dispatcher.py +244 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_eligibility.py +113 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_feedback_router.py +283 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_gc.py +276 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_github.py +174 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_naming.py +97 -0
- agentwire_dev-1.29.0/tests/unit/test_missions_state.py +120 -0
- agentwire_dev-1.29.0/tests/unit/test_safety_mission_worker.py +233 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_scheduler.py +4 -126
- agentwire_dev-1.28.1/agentwire/static/js/sidebar/scheduler-section.js +0 -101
- agentwire_dev-1.28.1/agentwire/static/js/sidebar/workflows-section.js +0 -114
- agentwire_dev-1.28.1/agentwire/static/js/windows/workflow-window.js +0 -166
- agentwire_dev-1.28.1/agentwire/workflows/__init__.py +0 -27
- agentwire_dev-1.28.1/agentwire/workflows/cli.py +0 -378
- agentwire_dev-1.28.1/agentwire/workflows/context.py +0 -52
- agentwire_dev-1.28.1/agentwire/workflows/definitions.py +0 -370
- agentwire_dev-1.28.1/agentwire/workflows/node.py +0 -137
- agentwire_dev-1.28.1/agentwire/workflows/outputs.py +0 -149
- agentwire_dev-1.28.1/agentwire/workflows/pi_runner.py +0 -245
- agentwire_dev-1.28.1/agentwire/workflows/runner.py +0 -378
- agentwire_dev-1.28.1/agentwire/workflows/runners/__init__.py +0 -56
- agentwire_dev-1.28.1/agentwire/workflows/runners/pi.py +0 -35
- agentwire_dev-1.28.1/agentwire/workflows/storage.py +0 -198
- agentwire_dev-1.28.1/docs/wiki/scheduling/workflows.md +0 -512
- agentwire_dev-1.28.1/tests/unit/test_pi_runner.py +0 -427
- agentwire_dev-1.28.1/tests/unit/test_runner_on_event.py +0 -86
- agentwire_dev-1.28.1/tests/unit/test_runners_registry.py +0 -108
- agentwire_dev-1.28.1/tests/unit/test_scheduler_workflow_dispatch.py +0 -213
- agentwire_dev-1.28.1/tests/unit/test_server_workflow_history.py +0 -173
- agentwire_dev-1.28.1/tests/unit/test_workflow_cli.py +0 -172
- agentwire_dev-1.28.1/tests/unit/test_workflow_storage.py +0 -128
- agentwire_dev-1.28.1/tests/unit/test_workflows.py +0 -487
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/.gitignore +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/CLA.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/Dockerfile.runpod +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/LICENSE +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/README.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/RELEASING.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/SECURITY.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/cli_safety.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/config.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/overnight.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/prompts/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/prompts/init.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/search.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-Echo--black.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-Echo--transparent.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-Echo.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-email-banner.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--transparent.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/favicon.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/android.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/automaton.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/bot.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/droid.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/drone.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/guardian.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/mech.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/probe.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/robot.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/machines/unit.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/blob.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/cloud.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/crystal.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/flame.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/horned.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/moon.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/slime.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/star.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/projects/winged.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/bear.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/cat.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/crown.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/deer.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/drone.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/fox.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/horse.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/lion.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/robot.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/components/icon-picker.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/components/list-card.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/components/type-tag.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/new-project-modal.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/quicktask-modal.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/utils/auto-refresh.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/static/js/windows/chat-window.js +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/stt/whisperkit.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/engines/qwen_base.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/engines/qwen_custom.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/engines/qwen_design.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts/runpod_handler.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/voices/darren.wav +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/voices/default.wav +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/voices/jessica.wav +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/voices/lisa.wav +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/voices/may.wav +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/logo.png +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/tts/runpod-tts.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/docs/wiki/tts/tts-self-hosted.md +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/requirements-tts.txt +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_cli_safety.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_overnight_resume_flags.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_search.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.28.1 → agentwire_dev-1.29.0}/tests/unit/test_worktree.py +0 -0
|
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Removed
|
|
11
11
|
|
|
12
|
+
- **Workflow engine** — entire `agentwire/workflows/` package (DAG runner, definitions, storage, pi runner, CLI), the `agentwire workflow` CLI subcommand, 5 MCP tools (`workflow_list/validate/run/history/show`), 3 portal endpoints (`/api/workflows/list|runs|runs/{id}`), the Workflows sidebar section + WorkflowWindow + ~230 lines of CSS, the scheduler's `workflow:` dispatch branch (`SchedulerTask.workflow`/`inputs` fields, `_dispatch_workflow_task`, `_render_workflow_inputs`, `_parse_workflow_summary`, `_workflow_failure_state`, validation block), 9 workflow test files plus the workflow-specific cases in `test_scheduler.py`, the `agentwire-workflows` skill, `docs/wiki/scheduling/workflows.md`, and ~120 dirs of historical runs under `~/.agentwire/workflows/`. The user's actual recurring automations all live as scheduler ensure tasks (`task:`); the engine was unused in practice and the empty sidebar surface was just noise. Scheduler is now ensure-only.
|
|
12
13
|
- **Inbound channel surface** — entire Telegram bridge (`agentwire/bridges/telegram.py`), Discord channel (`agentwire/channels/discord.py`), Slack channel (`agentwire/channels/slack.py`), Twilio SMS (`agentwire/channels/sms.py`), Webhook (`agentwire/channels/webhook.py`), outbound-Telegram (`agentwire/channels/telegram.py`), channel scaffolding template (`agentwire/channels/_template.py`), all `agentwire {telegram,discord,slack,sms,webhook}` CLI command groups, the `agentwire reply` command, MCP tools `discord_status` / `slack_status` / `sms_send` / `webhook_send`, the portal sidebar "socials" section, the `ServiceChannel` / `MessageQueueManager` / `QueuedMessage` / `compose_session_config` / `inject_instructions` / session-helper plumbing in `channels/base.py`, the TTS/STT primitives on the channel base class, the auto-injected `discord-dm` / `slack-dm` / `channel-admin` roles, the `OutputConfig.notify` task field plus its `_handle_task_notification` dispatcher (voice / alert / webhook / email / command), the doctor's Telegram bridge check, and the `aiogram` optional dep. Wire surface is now outbound-only: **email** (Resend) and **quo** (OpenPhone SMS) remain. Inbound user input flows through the portal. Security review traced the cut: Telegram bridge was secure (refuse-to-start on empty allowlist + silent default-deny), Discord/Slack fail-open on empty allowlist + unauthenticated channel `@mention`; rather than fix the gaps, the whole inbound surface comes out to keep the wire posture outbound-only.
|
|
13
14
|
- **Anthropic SDK surface** — entire `agentwire/sdk/` package, `agentwire/repl/` (Textual REPL), `agentwire/workflows/runners/{anthropic,human_gate}.py`, `sdk-bypass` / `sdk-prompted` / `sdk-restricted` session types, `sdk-watch` portal window + sidebar section, `--runner` workflow CLI override, and the `claude-agent-sdk` dependency. Anthropic moved Agent SDK + `claude -p` usage out of the monthly subscription tier on 2026-05-13 (now API-billed); the in-tree consumers were too expensive to keep running. The `pi` workflow runner is now the only runner. For Anthropic-quality scheduled work, use a `claude-bypass` tmux session via `.agentwire.yml` + scheduler. Mission [#184](https://github.com/dotdevdotdev/agentwire-dev/issues/184). Findings captured in `~/.agentwire/wiki/` (anthropic-agent-sdk, anthropic-runner-findings, textual-repl-retrospective, workflow-runner-choice, claude-code-print-mode).
|
|
14
15
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
import base64
|
|
5
|
-
from dataclasses import dataclass, field
|
|
6
5
|
import datetime
|
|
7
6
|
import importlib.resources
|
|
8
7
|
import json
|
|
@@ -17,6 +16,7 @@ import tempfile
|
|
|
17
16
|
import time
|
|
18
17
|
import urllib.error
|
|
19
18
|
import urllib.request
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
20
|
from pathlib import Path
|
|
21
21
|
|
|
22
22
|
from dotenv import load_dotenv
|
|
@@ -101,6 +101,17 @@ def _build_tmux_env_flags_shell(env: dict[str, str]) -> str:
|
|
|
101
101
|
return " ".join(parts) + " "
|
|
102
102
|
|
|
103
103
|
|
|
104
|
+
def _set_session_name_env(agent: "AgentCommand", session_name: str) -> None:
|
|
105
|
+
"""Stamp ``AGENTWIRE_SESSION_NAME`` onto an ``AgentCommand.env``.
|
|
106
|
+
|
|
107
|
+
Every session created via ``cmd_new`` / ``cmd_spawn`` / ``cmd_recreate``
|
|
108
|
+
/ ``cmd_fork`` / scheduler-spawn paths gets this so downstream tooling
|
|
109
|
+
(notably the mission-worker damage-control rules in ``safety/_core.py``)
|
|
110
|
+
can identify which agentwire session the running tool is part of.
|
|
111
|
+
"""
|
|
112
|
+
agent.env["AGENTWIRE_SESSION_NAME"] = session_name
|
|
113
|
+
|
|
114
|
+
|
|
104
115
|
def inject_session_env(session: str, env: dict[str, str], remote_host: str | None = None) -> None:
|
|
105
116
|
"""Set env vars on an existing tmux session for FUTURE shells in that session.
|
|
106
117
|
|
|
@@ -1386,9 +1397,10 @@ def cmd_tts_restart(args) -> int:
|
|
|
1386
1397
|
Used by CLI when venv_mismatch occurs during TTS request.
|
|
1387
1398
|
Supports both local and remote TTS servers.
|
|
1388
1399
|
"""
|
|
1389
|
-
from .network import NetworkContext
|
|
1390
1400
|
import time
|
|
1391
1401
|
|
|
1402
|
+
from .network import NetworkContext
|
|
1403
|
+
|
|
1392
1404
|
ctx = NetworkContext.from_config()
|
|
1393
1405
|
session_name = get_tts_session_name()
|
|
1394
1406
|
|
|
@@ -2907,40 +2919,14 @@ def cmd_send(args) -> int:
|
|
|
2907
2919
|
print(f"Session '{session}' not found", file=sys.stderr)
|
|
2908
2920
|
return 1
|
|
2909
2921
|
|
|
2910
|
-
#
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
subprocess.run(["tmux", "load-buffer", temp_path], check=True)
|
|
2919
|
-
subprocess.run(["tmux", "paste-buffer", "-t", session], check=True)
|
|
2920
|
-
finally:
|
|
2921
|
-
os.unlink(temp_path)
|
|
2922
|
-
else:
|
|
2923
|
-
subprocess.run(
|
|
2924
|
-
["tmux", "send-keys", "-t", session, "-l", prompt],
|
|
2925
|
-
check=True
|
|
2926
|
-
)
|
|
2927
|
-
|
|
2928
|
-
# Wait for text to be displayed before pressing Enter
|
|
2929
|
-
time.sleep(0.5)
|
|
2930
|
-
|
|
2931
|
-
subprocess.run(
|
|
2932
|
-
["tmux", "send-keys", "-t", session, "Enter"],
|
|
2933
|
-
check=True
|
|
2934
|
-
)
|
|
2935
|
-
|
|
2936
|
-
# For multi-line text, Claude Code shows "[Pasted text...]" and waits for Enter
|
|
2937
|
-
# Send another Enter after a short delay to confirm the paste
|
|
2938
|
-
if "\n" in prompt or len(prompt) > 200:
|
|
2939
|
-
time.sleep(0.5)
|
|
2940
|
-
subprocess.run(
|
|
2941
|
-
["tmux", "send-keys", "-t", session, "Enter"],
|
|
2942
|
-
check=True
|
|
2943
|
-
)
|
|
2922
|
+
# Delegate paste + Enter handling to the shared pane_manager helper so
|
|
2923
|
+
# send-to-session and send-to-pane stay in lockstep. The helper handles
|
|
2924
|
+
# buffer-vs-send-keys, settle delay, and the bracketed-paste double-Enter
|
|
2925
|
+
# in one place.
|
|
2926
|
+
try:
|
|
2927
|
+
pane_manager.send_to_target(session, prompt, enter=True)
|
|
2928
|
+
except RuntimeError as e:
|
|
2929
|
+
return _output_result(False, json_mode, str(e))
|
|
2944
2930
|
|
|
2945
2931
|
if json_mode:
|
|
2946
2932
|
print(json.dumps({"success": True, "session": session_full, "machine": None, "message": "Prompt sent"}))
|
|
@@ -3372,6 +3358,40 @@ def cmd_new(args) -> int:
|
|
|
3372
3358
|
# Simple session: ~/projects/project/
|
|
3373
3359
|
session_path = projects_dir / project
|
|
3374
3360
|
|
|
3361
|
+
# Safety: refuse to attach a new session to a path that is already the working
|
|
3362
|
+
# directory of another active session. Two agents sharing the same working tree
|
|
3363
|
+
# is the dangerous footgun (one's dirty state visible to the other, branches
|
|
3364
|
+
# mixing). Worktree sessions (project/branch) get unique paths and won't trip
|
|
3365
|
+
# this. --force overrides.
|
|
3366
|
+
if not args.force:
|
|
3367
|
+
target = str(session_path.resolve()) if session_path.exists() else str(session_path)
|
|
3368
|
+
panes_result = subprocess.run(
|
|
3369
|
+
["tmux", "list-panes", "-a", "-F", "#{session_name}\t#{pane_current_path}"],
|
|
3370
|
+
capture_output=True, text=True,
|
|
3371
|
+
)
|
|
3372
|
+
if panes_result.returncode == 0:
|
|
3373
|
+
conflicting: set[str] = set()
|
|
3374
|
+
for line in panes_result.stdout.splitlines():
|
|
3375
|
+
if "\t" not in line:
|
|
3376
|
+
continue
|
|
3377
|
+
sess, p = line.split("\t", 1)
|
|
3378
|
+
if sess == session_name:
|
|
3379
|
+
continue
|
|
3380
|
+
try:
|
|
3381
|
+
if str(Path(p).resolve()) == target:
|
|
3382
|
+
conflicting.add(sess)
|
|
3383
|
+
except (OSError, RuntimeError):
|
|
3384
|
+
continue
|
|
3385
|
+
if conflicting:
|
|
3386
|
+
others = ", ".join(sorted(conflicting))
|
|
3387
|
+
hint = (
|
|
3388
|
+
f"Refusing to attach session '{session_name}' to {session_path}: "
|
|
3389
|
+
f"already the working directory of active session(s): {others}. "
|
|
3390
|
+
"Use a 'project/branch' name to create an isolated worktree, "
|
|
3391
|
+
"pick a different path, or pass --force to override."
|
|
3392
|
+
)
|
|
3393
|
+
return _output_result(False, json_mode, hint)
|
|
3394
|
+
|
|
3375
3395
|
if not session_path.exists():
|
|
3376
3396
|
if args.force or path:
|
|
3377
3397
|
# Auto-create directory with -f flag or when custom path explicitly provided
|
|
@@ -3431,6 +3451,7 @@ def cmd_new(args) -> int:
|
|
|
3431
3451
|
model_override = getattr(args, 'model', None)
|
|
3432
3452
|
agent = build_agent_command(session_type, roles if roles else None, model=model_override)
|
|
3433
3453
|
agent.env.update(parse_env_args(getattr(args, 'env', None)))
|
|
3454
|
+
_set_session_name_env(agent, session_name)
|
|
3434
3455
|
|
|
3435
3456
|
agent_cmd = agent.command
|
|
3436
3457
|
|
|
@@ -6291,9 +6312,10 @@ def cmd_voiceclone_list(args) -> int:
|
|
|
6291
6312
|
"""List available voices."""
|
|
6292
6313
|
json_mode = getattr(args, 'json', False)
|
|
6293
6314
|
|
|
6294
|
-
from .voiceclone import is_runpod_backend, list_voices_runpod, get_tts_url
|
|
6295
6315
|
import requests
|
|
6296
6316
|
|
|
6317
|
+
from .voiceclone import get_tts_url, is_runpod_backend, list_voices_runpod
|
|
6318
|
+
|
|
6297
6319
|
if is_runpod_backend():
|
|
6298
6320
|
success, result = list_voices_runpod()
|
|
6299
6321
|
if success:
|
|
@@ -7754,22 +7776,16 @@ def cmd_ensure(args) -> int:
|
|
|
7754
7776
|
10. Handle retries on failure
|
|
7755
7777
|
"""
|
|
7756
7778
|
from .completion import (
|
|
7757
|
-
CompletionTimeout,
|
|
7758
|
-
generate_summary_filename,
|
|
7759
7779
|
get_summary_prompt,
|
|
7760
|
-
status_to_exit_code,
|
|
7761
7780
|
)
|
|
7762
7781
|
from .locking import LockConflict, LockTimeout, session_lock
|
|
7763
7782
|
from .tasks import (
|
|
7764
|
-
PreCommandError,
|
|
7765
7783
|
TaskNotFound,
|
|
7766
7784
|
TaskValidationError,
|
|
7767
7785
|
load_task,
|
|
7768
|
-
run_post_command,
|
|
7769
|
-
run_pre_command,
|
|
7770
7786
|
validate_task,
|
|
7771
7787
|
)
|
|
7772
|
-
from .templating import TemplateContext,
|
|
7788
|
+
from .templating import TemplateContext, preview_template
|
|
7773
7789
|
|
|
7774
7790
|
session_name = args.session
|
|
7775
7791
|
task_name = args.task
|
|
@@ -8109,7 +8125,7 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, json_mode) -
|
|
|
8109
8125
|
capture_output=True, text=True,
|
|
8110
8126
|
)
|
|
8111
8127
|
if fork_result.returncode != 0 and not json_mode:
|
|
8112
|
-
print(
|
|
8128
|
+
print("Warning: context fork failed, starting fresh session")
|
|
8113
8129
|
elif not json_mode:
|
|
8114
8130
|
print(f"Warning: starting_session '{task.starting_session}' not found, starting fresh")
|
|
8115
8131
|
|
|
@@ -8813,10 +8829,9 @@ def cmd_scheduler_board(args) -> int:
|
|
|
8813
8829
|
|
|
8814
8830
|
def cmd_scheduler_run(args) -> int:
|
|
8815
8831
|
"""Force-run a specific task now."""
|
|
8816
|
-
from .scheduler import
|
|
8832
|
+
from .scheduler import dispatch_task, load_board, save_board
|
|
8817
8833
|
|
|
8818
8834
|
json_mode = getattr(args, 'json', False)
|
|
8819
|
-
dry_run = getattr(args, 'dry_run', False)
|
|
8820
8835
|
name = args.name
|
|
8821
8836
|
|
|
8822
8837
|
try:
|
|
@@ -8830,40 +8845,6 @@ def cmd_scheduler_run(args) -> int:
|
|
|
8830
8845
|
f"Task '{name}' not found in board. Available: {', '.join(board.tasks.keys())}",
|
|
8831
8846
|
)
|
|
8832
8847
|
|
|
8833
|
-
task = board.tasks[name]
|
|
8834
|
-
|
|
8835
|
-
if dry_run:
|
|
8836
|
-
if not task.workflow:
|
|
8837
|
-
return _output_result(
|
|
8838
|
-
False, json_mode,
|
|
8839
|
-
f"--dry-run only applies to workflow tasks; '{name}' runs via ensure.",
|
|
8840
|
-
)
|
|
8841
|
-
from agentwire.workflows.definitions import resolve_workflow
|
|
8842
|
-
from agentwire.workflows.runner import run_workflow
|
|
8843
|
-
try:
|
|
8844
|
-
wf = resolve_workflow(task.workflow)
|
|
8845
|
-
except Exception as e:
|
|
8846
|
-
return _output_result(False, json_mode, f"Could not load workflow '{task.workflow}': {e}")
|
|
8847
|
-
rendered_inputs = _render_workflow_inputs(task.inputs, task)
|
|
8848
|
-
run = run_workflow(wf, runs_dir=None, inputs=rendered_inputs, dry_run=True)
|
|
8849
|
-
if json_mode:
|
|
8850
|
-
_output_json({
|
|
8851
|
-
"success": True,
|
|
8852
|
-
"task": name,
|
|
8853
|
-
"dry_run": True,
|
|
8854
|
-
"workflow": wf.name,
|
|
8855
|
-
"inputs": rendered_inputs,
|
|
8856
|
-
"nodes": [r.node_id for r in run.node_results],
|
|
8857
|
-
"status": run.status,
|
|
8858
|
-
})
|
|
8859
|
-
return 0
|
|
8860
|
-
print(f"Dry-run: {name} → workflow '{wf.name}'")
|
|
8861
|
-
if rendered_inputs:
|
|
8862
|
-
print(f" inputs: {rendered_inputs}")
|
|
8863
|
-
for r in run.node_results:
|
|
8864
|
-
print(f" - {r.node_id}: {r.final_text}")
|
|
8865
|
-
return 0
|
|
8866
|
-
|
|
8867
8848
|
if not json_mode:
|
|
8868
8849
|
print(f"Running: {name}")
|
|
8869
8850
|
|
|
@@ -8946,7 +8927,6 @@ def cmd_scheduler_history(args) -> int:
|
|
|
8946
8927
|
"last_status": state.last_status,
|
|
8947
8928
|
"last_duration": state.last_duration,
|
|
8948
8929
|
"run_count": state.run_count,
|
|
8949
|
-
"workflow": (task.workflow if task else "") or None,
|
|
8950
8930
|
})
|
|
8951
8931
|
_output_json({"success": True, "history": history})
|
|
8952
8932
|
return 0
|
|
@@ -8972,8 +8952,8 @@ def cmd_scheduler_history(args) -> int:
|
|
|
8972
8952
|
|
|
8973
8953
|
def cmd_scheduler_report(args) -> int:
|
|
8974
8954
|
"""Generate a morning report HTML artifact of recent task runs."""
|
|
8975
|
-
import re as _re
|
|
8976
8955
|
from html import escape as html_escape
|
|
8956
|
+
|
|
8977
8957
|
from .scheduler import _parse_duration, format_interval, load_board, read_events
|
|
8978
8958
|
|
|
8979
8959
|
json_mode = getattr(args, 'json', False)
|
|
@@ -9045,38 +9025,11 @@ def cmd_scheduler_report(args) -> int:
|
|
|
9045
9025
|
color = colors.get(status, "#78909c")
|
|
9046
9026
|
return f'<span style="background:{color};color:#fff;padding:2px 8px;border-radius:12px;font-size:0.85em">{status}</span>'
|
|
9047
9027
|
|
|
9048
|
-
def node_badges(nodes: list) -> str:
|
|
9049
|
-
if not nodes:
|
|
9050
|
-
return ""
|
|
9051
|
-
node_colors = {
|
|
9052
|
-
"success": "#00c853",
|
|
9053
|
-
"failure": "#ff5252",
|
|
9054
|
-
"timeout": "#ff7043",
|
|
9055
|
-
"skipped": "#78909c",
|
|
9056
|
-
}
|
|
9057
|
-
pieces = []
|
|
9058
|
-
for n in nodes:
|
|
9059
|
-
nid = html_escape(str(n.get("id", "?")))
|
|
9060
|
-
nstatus = str(n.get("status", "?"))
|
|
9061
|
-
color = node_colors.get(nstatus, "#556")
|
|
9062
|
-
pieces.append(
|
|
9063
|
-
f'<span style="background:{color};color:#fff;padding:1px 6px;border-radius:8px;font-size:0.75em;margin-right:3px">{nid}</span>'
|
|
9064
|
-
)
|
|
9065
|
-
return "".join(pieces)
|
|
9066
|
-
|
|
9067
9028
|
rows_html = ""
|
|
9068
9029
|
for r in runs:
|
|
9069
9030
|
duration_str = format_interval(r["duration"]) if r["duration"] else "-"
|
|
9070
9031
|
pr_link = f'<a href="{r["pr_url"]}" target="_blank" style="color:#00d4ff">{r["pr_url"][:40]}...</a>' if r.get("pr_url") else "-"
|
|
9071
|
-
branch_col = ""
|
|
9072
|
-
if r.get("workflow"):
|
|
9073
|
-
wf_label = html_escape(r["workflow"])
|
|
9074
|
-
run_id = html_escape(r.get("run_id", ""))
|
|
9075
|
-
badges = node_badges(r["nodes"])
|
|
9076
|
-
run_hint = f' <span style="color:#556;font-size:0.75em">({run_id[:20]}…)</span>' if run_id else ""
|
|
9077
|
-
branch_col = f'<code style="font-size:0.85em">workflow:{wf_label}</code>{run_hint}<div style="margin-top:4px">{badges}</div>'
|
|
9078
|
-
else:
|
|
9079
|
-
branch_col = f'<code style="font-size:0.85em">{r.get("work_branch") or "-"}</code>'
|
|
9032
|
+
branch_col = f'<code style="font-size:0.85em">{r.get("work_branch") or "-"}</code>'
|
|
9080
9033
|
summary_text = r["summary"][:120] if r["summary"] else "-"
|
|
9081
9034
|
rows_html += f"""
|
|
9082
9035
|
<tr>
|
|
@@ -9536,7 +9489,7 @@ def cmd_overnight_prepare(args) -> int:
|
|
|
9536
9489
|
"status": item.status,
|
|
9537
9490
|
})
|
|
9538
9491
|
else:
|
|
9539
|
-
print(
|
|
9492
|
+
print("Queued for overnight execution:")
|
|
9540
9493
|
print(f" ID: {item.id}")
|
|
9541
9494
|
print(f" Session: {item.session}")
|
|
9542
9495
|
print(f" Branch: {item.work_branch}")
|
|
@@ -9548,7 +9501,7 @@ def cmd_overnight_prepare(args) -> int:
|
|
|
9548
9501
|
|
|
9549
9502
|
def cmd_overnight_list(args) -> int:
|
|
9550
9503
|
"""List overnight queue items."""
|
|
9551
|
-
from .overnight import
|
|
9504
|
+
from .overnight import load_done, load_queue
|
|
9552
9505
|
|
|
9553
9506
|
json_mode = getattr(args, "json", False)
|
|
9554
9507
|
show_all = getattr(args, "all", False)
|
|
@@ -9587,7 +9540,7 @@ def cmd_overnight_list(args) -> int:
|
|
|
9587
9540
|
|
|
9588
9541
|
def cmd_overnight_status(args) -> int:
|
|
9589
9542
|
"""Show overnight orchestrator state and queue summary."""
|
|
9590
|
-
from .overnight import load_queue, read_live_state
|
|
9543
|
+
from .overnight import in_overnight_window, load_queue, read_live_state
|
|
9591
9544
|
|
|
9592
9545
|
json_mode = getattr(args, "json", False)
|
|
9593
9546
|
|
|
@@ -9633,7 +9586,7 @@ def cmd_overnight_status(args) -> int:
|
|
|
9633
9586
|
|
|
9634
9587
|
def cmd_overnight_cancel(args) -> int:
|
|
9635
9588
|
"""Cancel a queued overnight item."""
|
|
9636
|
-
from .overnight import
|
|
9589
|
+
from .overnight import delete_item, load_item
|
|
9637
9590
|
|
|
9638
9591
|
item_id = args.id
|
|
9639
9592
|
json_mode = getattr(args, "json", False)
|
|
@@ -10209,70 +10162,6 @@ def main() -> int:
|
|
|
10209
10162
|
)
|
|
10210
10163
|
dev_parser.set_defaults(func=cmd_dev)
|
|
10211
10164
|
|
|
10212
|
-
# === workflow command group ===
|
|
10213
|
-
from agentwire.workflows.cli import (
|
|
10214
|
-
cmd_workflow_history,
|
|
10215
|
-
cmd_workflow_list,
|
|
10216
|
-
cmd_workflow_run,
|
|
10217
|
-
cmd_workflow_show,
|
|
10218
|
-
cmd_workflow_validate,
|
|
10219
|
-
)
|
|
10220
|
-
|
|
10221
|
-
workflow_parser = subparsers.add_parser("workflow", help="Pi workflow engine")
|
|
10222
|
-
workflow_subparsers = workflow_parser.add_subparsers(dest="workflow_command")
|
|
10223
|
-
|
|
10224
|
-
wf_list = workflow_subparsers.add_parser("list", help="List discoverable workflows")
|
|
10225
|
-
wf_list.add_argument("--json", action="store_true", help="Output as JSON")
|
|
10226
|
-
wf_list.set_defaults(func=cmd_workflow_list)
|
|
10227
|
-
|
|
10228
|
-
wf_validate = workflow_subparsers.add_parser(
|
|
10229
|
-
"validate", help="Validate a workflow YAML without running it"
|
|
10230
|
-
)
|
|
10231
|
-
wf_validate.add_argument("workflow", help="Workflow name or path to YAML")
|
|
10232
|
-
wf_validate.set_defaults(func=cmd_workflow_validate)
|
|
10233
|
-
|
|
10234
|
-
wf_run = workflow_subparsers.add_parser("run", help="Execute a workflow")
|
|
10235
|
-
wf_run.add_argument("workflow", help="Workflow name or path to YAML")
|
|
10236
|
-
wf_run.add_argument(
|
|
10237
|
-
"--input", action="append", metavar="KEY=VALUE",
|
|
10238
|
-
help="Workflow input (repeatable). Overrides --input-file."
|
|
10239
|
-
)
|
|
10240
|
-
wf_run.add_argument(
|
|
10241
|
-
"--input-file", metavar="PATH",
|
|
10242
|
-
help="JSON file with inputs (object mapping name → value)"
|
|
10243
|
-
)
|
|
10244
|
-
wf_run.add_argument("--dry-run", action="store_true", help="Print plan without running")
|
|
10245
|
-
wf_run.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
|
|
10246
|
-
wf_run.add_argument("--json", action="store_true", help="Output as JSON")
|
|
10247
|
-
wf_run.set_defaults(func=cmd_workflow_run)
|
|
10248
|
-
|
|
10249
|
-
wf_history = workflow_subparsers.add_parser(
|
|
10250
|
-
"history", help="List past workflow runs"
|
|
10251
|
-
)
|
|
10252
|
-
wf_history.add_argument(
|
|
10253
|
-
"--workflow", metavar="NAME", help="Filter by workflow name"
|
|
10254
|
-
)
|
|
10255
|
-
wf_history.add_argument(
|
|
10256
|
-
"--limit", type=int, default=20, help="Max runs to show (default: 20)"
|
|
10257
|
-
)
|
|
10258
|
-
wf_history.add_argument("--json", action="store_true", help="Output as JSON")
|
|
10259
|
-
wf_history.set_defaults(func=cmd_workflow_history)
|
|
10260
|
-
|
|
10261
|
-
wf_show = workflow_subparsers.add_parser(
|
|
10262
|
-
"show", help="Inspect a past workflow run"
|
|
10263
|
-
)
|
|
10264
|
-
wf_show.add_argument("run_id", help="Run ID (from `workflow history`)")
|
|
10265
|
-
wf_show.add_argument(
|
|
10266
|
-
"--events", action="store_true",
|
|
10267
|
-
help="Dump raw event JSONL for all nodes",
|
|
10268
|
-
)
|
|
10269
|
-
wf_show.add_argument(
|
|
10270
|
-
"--node", metavar="ID",
|
|
10271
|
-
help="Filter events to one node id (implies --events)",
|
|
10272
|
-
)
|
|
10273
|
-
wf_show.add_argument("--json", action="store_true", help="Output as JSON")
|
|
10274
|
-
wf_show.set_defaults(func=cmd_workflow_show)
|
|
10275
|
-
|
|
10276
10165
|
# === listen command group ===
|
|
10277
10166
|
listen_parser = subparsers.add_parser("listen", help="Voice input recording")
|
|
10278
10167
|
listen_parser.add_argument(
|
|
@@ -10738,8 +10627,6 @@ def main() -> int:
|
|
|
10738
10627
|
sched_run = scheduler_subparsers.add_parser("run", help="Force-run a task now")
|
|
10739
10628
|
sched_run.add_argument("name", help="Task name from board")
|
|
10740
10629
|
sched_run.add_argument("--json", action="store_true", help="Output JSON")
|
|
10741
|
-
sched_run.add_argument("--dry-run", action="store_true",
|
|
10742
|
-
help="For workflow tasks: print the execution plan without running")
|
|
10743
10630
|
sched_run.set_defaults(func=cmd_scheduler_run)
|
|
10744
10631
|
|
|
10745
10632
|
# scheduler enable <name>
|
|
@@ -10782,6 +10669,95 @@ def main() -> int:
|
|
|
10782
10669
|
sched_report.add_argument("--json", action="store_true", help="Output JSON")
|
|
10783
10670
|
sched_report.set_defaults(func=cmd_scheduler_report)
|
|
10784
10671
|
|
|
10672
|
+
# === mission command group ===
|
|
10673
|
+
from .missions import cli as mission_cli
|
|
10674
|
+
|
|
10675
|
+
mission_parser = subparsers.add_parser(
|
|
10676
|
+
"mission",
|
|
10677
|
+
help="Manage agent-driven missions (issue→branch→draft PR cycles)",
|
|
10678
|
+
description=(
|
|
10679
|
+
"First-class auto-dispatcher: stateless orchestrators tick the GitHub "
|
|
10680
|
+
"issue board, spawn worker sessions in isolated worktrees, route PR "
|
|
10681
|
+
"feedback back, and gc when the PR closes. See docs/MISSIONS.md."
|
|
10682
|
+
),
|
|
10683
|
+
)
|
|
10684
|
+
mission_subparsers = mission_parser.add_subparsers(dest="mission_command")
|
|
10685
|
+
|
|
10686
|
+
# mission list
|
|
10687
|
+
m_list = mission_subparsers.add_parser("list", help="List active workers + eligible issues")
|
|
10688
|
+
m_list.add_argument("--json", action="store_true", help="Output JSON")
|
|
10689
|
+
m_list.set_defaults(func=mission_cli.cmd_mission_list)
|
|
10690
|
+
|
|
10691
|
+
# mission show <N>
|
|
10692
|
+
m_show = mission_subparsers.add_parser("show", help="Show one issue + dispatch + PR state")
|
|
10693
|
+
m_show.add_argument("number", type=int, help="GitHub issue number")
|
|
10694
|
+
m_show.add_argument("--repo", required=True, help="Repo short name (from missions config)")
|
|
10695
|
+
m_show.add_argument("--json", action="store_true", help="Output JSON")
|
|
10696
|
+
m_show.set_defaults(func=mission_cli.cmd_mission_show)
|
|
10697
|
+
|
|
10698
|
+
# mission status
|
|
10699
|
+
m_status = mission_subparsers.add_parser("status", help="Per-repo summary of active + eligible")
|
|
10700
|
+
m_status.add_argument("--json", action="store_true", help="Output JSON")
|
|
10701
|
+
m_status.set_defaults(func=mission_cli.cmd_mission_status)
|
|
10702
|
+
|
|
10703
|
+
# mission spawn <N>
|
|
10704
|
+
m_spawn = mission_subparsers.add_parser(
|
|
10705
|
+
"spawn", help="Force-dispatch an issue, bypassing eligibility"
|
|
10706
|
+
)
|
|
10707
|
+
m_spawn.add_argument("number", type=int, help="GitHub issue number")
|
|
10708
|
+
m_spawn.add_argument("--repo", required=True, help="Repo short name")
|
|
10709
|
+
m_spawn.add_argument("--json", action="store_true", help="Output JSON")
|
|
10710
|
+
m_spawn.set_defaults(func=mission_cli.cmd_mission_spawn)
|
|
10711
|
+
|
|
10712
|
+
# mission stall <N>
|
|
10713
|
+
m_stall = mission_subparsers.add_parser("stall", help="Stop dispatch for an issue with a reason")
|
|
10714
|
+
m_stall.add_argument("number", type=int, help="GitHub issue number")
|
|
10715
|
+
m_stall.add_argument("--repo", required=True, help="Repo short name")
|
|
10716
|
+
m_stall.add_argument("--reason", required=True, help="Reason (posted as comment)")
|
|
10717
|
+
m_stall.add_argument("--json", action="store_true", help="Output JSON")
|
|
10718
|
+
m_stall.set_defaults(func=mission_cli.cmd_mission_stall)
|
|
10719
|
+
|
|
10720
|
+
# mission resume <N>
|
|
10721
|
+
m_resume = mission_subparsers.add_parser("resume", help="Re-enable an issue for dispatch")
|
|
10722
|
+
m_resume.add_argument("number", type=int, help="GitHub issue number")
|
|
10723
|
+
m_resume.add_argument("--repo", required=True, help="Repo short name")
|
|
10724
|
+
m_resume.add_argument("--json", action="store_true", help="Output JSON")
|
|
10725
|
+
m_resume.set_defaults(func=mission_cli.cmd_mission_resume)
|
|
10726
|
+
|
|
10727
|
+
# mission kill <N>
|
|
10728
|
+
m_kill = mission_subparsers.add_parser(
|
|
10729
|
+
"kill", help="Kill worker session + worktree (does NOT close the PR)"
|
|
10730
|
+
)
|
|
10731
|
+
m_kill.add_argument("number", type=int, help="GitHub issue number")
|
|
10732
|
+
m_kill.add_argument("--repo", required=True, help="Repo short name")
|
|
10733
|
+
m_kill.add_argument("--json", action="store_true", help="Output JSON")
|
|
10734
|
+
m_kill.set_defaults(func=mission_cli.cmd_mission_kill)
|
|
10735
|
+
|
|
10736
|
+
# mission gc
|
|
10737
|
+
m_gc = mission_subparsers.add_parser("gc", help="Reap sessions whose PR is merged/closed")
|
|
10738
|
+
m_gc.add_argument("--json", action="store_true", help="Output JSON")
|
|
10739
|
+
m_gc.set_defaults(func=mission_cli.cmd_mission_gc)
|
|
10740
|
+
|
|
10741
|
+
# mission tick
|
|
10742
|
+
m_tick = mission_subparsers.add_parser("tick", help="Run one dispatcher tick now")
|
|
10743
|
+
m_tick.add_argument("--json", action="store_true", help="Output JSON")
|
|
10744
|
+
m_tick.set_defaults(func=mission_cli.cmd_mission_tick)
|
|
10745
|
+
|
|
10746
|
+
# mission route-feedback
|
|
10747
|
+
m_route = mission_subparsers.add_parser(
|
|
10748
|
+
"route-feedback", help="Run one PR-feedback router tick now"
|
|
10749
|
+
)
|
|
10750
|
+
m_route.add_argument("--json", action="store_true", help="Output JSON")
|
|
10751
|
+
m_route.set_defaults(func=mission_cli.cmd_mission_route_feedback)
|
|
10752
|
+
|
|
10753
|
+
# mission init <repo>
|
|
10754
|
+
m_init = mission_subparsers.add_parser(
|
|
10755
|
+
"init", help="Create the agent-ready label on a repo (idempotent)"
|
|
10756
|
+
)
|
|
10757
|
+
m_init.add_argument("repo", help="Repo short name (from config) or owner/repo form")
|
|
10758
|
+
m_init.add_argument("--json", action="store_true", help="Output JSON")
|
|
10759
|
+
m_init.set_defaults(func=mission_cli.cmd_mission_init)
|
|
10760
|
+
|
|
10785
10761
|
# === overnight command group ===
|
|
10786
10762
|
overnight_parser = subparsers.add_parser(
|
|
10787
10763
|
"overnight",
|
|
@@ -10918,6 +10894,10 @@ def main() -> int:
|
|
|
10918
10894
|
scheduler_parser.print_help()
|
|
10919
10895
|
return 0
|
|
10920
10896
|
|
|
10897
|
+
if args.command == "mission" and getattr(args, "mission_command", None) is None:
|
|
10898
|
+
mission_parser.print_help()
|
|
10899
|
+
return 0
|
|
10900
|
+
|
|
10921
10901
|
if args.command == "overnight" and getattr(args, "overnight_command", None) is None:
|
|
10922
10902
|
overnight_parser.print_help()
|
|
10923
10903
|
return 0
|
|
@@ -559,6 +559,82 @@ def detect_escape_hatch(command: str) -> Optional[str]:
|
|
|
559
559
|
return reason or None
|
|
560
560
|
|
|
561
561
|
|
|
562
|
+
# ============================================================================
|
|
563
|
+
# MISSION-WORKER RULES
|
|
564
|
+
# ============================================================================
|
|
565
|
+
#
|
|
566
|
+
# When a tmux session is a mission worker (its name is "{repo}/mission-{N}-{slug}",
|
|
567
|
+
# carried through to hooks as the ``AGENTWIRE_SESSION_NAME`` env var), tighten
|
|
568
|
+
# damage control beyond the standard ruleset:
|
|
569
|
+
#
|
|
570
|
+
# 1. Edit/Write must target a path inside a mission worktree
|
|
571
|
+
# (``{...}-worktrees/mission-{N}-{slug}/...``). No writing to the canonical
|
|
572
|
+
# repo, sibling projects, or arbitrary filesystem locations.
|
|
573
|
+
# 2. Bash ``git push --force`` (or ``--force-with-lease``) is blocked unless
|
|
574
|
+
# the target is a mission-* branch and not main/master/develop.
|
|
575
|
+
#
|
|
576
|
+
# Detection uses the session-name regex (set by ``cmd_new`` / spawn lifecycle);
|
|
577
|
+
# enforcement uses a separate path regex to allow simple realpath checks.
|
|
578
|
+
|
|
579
|
+
_MISSION_SESSION_RE = re.compile(r"^[^/]+/mission-\d+-")
|
|
580
|
+
_MISSION_WORKTREE_PATH_RE = re.compile(r"-worktrees/mission-\d+-")
|
|
581
|
+
_PROTECTED_BRANCH_RE = re.compile(r"\b(?:main|master|develop)\b")
|
|
582
|
+
_FORCE_PUSH_RE = re.compile(r"\bgit\s+push\b[^|;&]*--force(?:-with-lease)?\b", re.IGNORECASE)
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
def _is_mission_worker_session() -> bool:
|
|
586
|
+
"""True iff ``AGENTWIRE_SESSION_NAME`` env var matches the mission pattern."""
|
|
587
|
+
return bool(_MISSION_SESSION_RE.match(os.environ.get("AGENTWIRE_SESSION_NAME", "") or ""))
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def check_mission_worker_path(file_path: str) -> Tuple[bool, str]:
|
|
591
|
+
"""If we're in a mission worker, allow only paths under a mission worktree.
|
|
592
|
+
|
|
593
|
+
Returns ``(blocked, reason)``. ``(False, "")`` when not in a mission session
|
|
594
|
+
or when ``file_path`` resolves inside a ``*-worktrees/mission-N-...`` dir.
|
|
595
|
+
|
|
596
|
+
Realpath is used so symlink escapes from within the worktree still resolve
|
|
597
|
+
to their canonical location for the check.
|
|
598
|
+
"""
|
|
599
|
+
if not _is_mission_worker_session():
|
|
600
|
+
return False, ""
|
|
601
|
+
try:
|
|
602
|
+
abs_path = os.path.realpath(os.path.expanduser(file_path))
|
|
603
|
+
except (OSError, ValueError):
|
|
604
|
+
return False, ""
|
|
605
|
+
if _MISSION_WORKTREE_PATH_RE.search(abs_path):
|
|
606
|
+
return False, ""
|
|
607
|
+
return True, (
|
|
608
|
+
"mission worker may only write inside its assigned worktree "
|
|
609
|
+
"({repo}-worktrees/mission-{N}-{slug}/...)"
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def check_mission_worker_bash(command: str) -> Tuple[bool, str]:
|
|
614
|
+
"""If we're in a mission worker, gate force-pushes by target branch.
|
|
615
|
+
|
|
616
|
+
Rules:
|
|
617
|
+
- Any ``git push --force`` referencing ``main`` / ``master`` / ``develop``
|
|
618
|
+
is blocked outright.
|
|
619
|
+
- A ``git push --force`` targeting a ``mission-*`` branch is allowed
|
|
620
|
+
(the worker's own branch; rebases on top of merge-base happen here).
|
|
621
|
+
- All other ``git push --force`` patterns are blocked — mission workers
|
|
622
|
+
should never overwrite shared history.
|
|
623
|
+
|
|
624
|
+
Returns ``(blocked, reason)``; ``(False, "")`` if not in a mission session
|
|
625
|
+
or the command isn't a force-push.
|
|
626
|
+
"""
|
|
627
|
+
if not _is_mission_worker_session():
|
|
628
|
+
return False, ""
|
|
629
|
+
if not _FORCE_PUSH_RE.search(command):
|
|
630
|
+
return False, ""
|
|
631
|
+
if _PROTECTED_BRANCH_RE.search(command):
|
|
632
|
+
return True, "mission worker: --force push to main/master/develop is blocked"
|
|
633
|
+
if re.search(r"\bmission-\d+-", command):
|
|
634
|
+
return False, ""
|
|
635
|
+
return True, "mission worker: --force push allowed only on mission-* branches"
|
|
636
|
+
|
|
637
|
+
|
|
562
638
|
# ============================================================================
|
|
563
639
|
# DECISION LADDERS
|
|
564
640
|
# ============================================================================
|
|
@@ -604,6 +680,15 @@ def check_command(command: str, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
604
680
|
"disabled": True,
|
|
605
681
|
}
|
|
606
682
|
|
|
683
|
+
blocked, reason = check_mission_worker_bash(command)
|
|
684
|
+
if blocked:
|
|
685
|
+
return {
|
|
686
|
+
"decision": "block",
|
|
687
|
+
"reason": reason,
|
|
688
|
+
"pattern": "mission-worker:force-push",
|
|
689
|
+
"command": command,
|
|
690
|
+
}
|
|
691
|
+
|
|
607
692
|
bash_patterns = config.get("bashToolPatterns", [])
|
|
608
693
|
zero_access = config.get("zeroAccessPaths", [])
|
|
609
694
|
read_only = config.get("readOnlyPaths", [])
|
|
@@ -706,6 +791,10 @@ def check_path(file_path: str, config: Dict[str, Any]) -> Tuple[bool, str]:
|
|
|
706
791
|
if safety_cfg.get("enabled", True) is False:
|
|
707
792
|
return False, ""
|
|
708
793
|
|
|
794
|
+
blocked, reason = check_mission_worker_path(file_path)
|
|
795
|
+
if blocked:
|
|
796
|
+
return True, reason
|
|
797
|
+
|
|
709
798
|
allowed = load_allowed_paths(config)
|
|
710
799
|
|
|
711
800
|
if is_path_allowed_for_op(file_path, allowed, "edit"):
|