agentwire-dev 1.40.0__tar.gz → 1.42.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.40.0 → agentwire_dev-1.42.0}/PKG-INFO +1 -1
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/__main__.py +278 -31
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/cli_safety.py +43 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/config.py +11 -4
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/state.py +55 -1
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/view.py +22 -3
- agentwire_dev-1.42.0/agentwire/doctor_voice.py +383 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +126 -6
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +79 -6
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +79 -6
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-member.md +17 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/safety/_core.py +79 -6
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/scheduler.py +35 -6
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/server.py +157 -77
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/css/desktop.css +40 -1
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/css/mobile.css +3 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/command-palette.js +91 -4
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/council-window.js +45 -3
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/desktop.js +94 -21
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/mobile.js +32 -2
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/notifications-panel.js +19 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/service-classification.js +9 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/session-window.js +18 -3
- agentwire_dev-1.42.0/agentwire/static/js/sidebar/council-section.js +114 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/sessions-section.js +3 -2
- agentwire_dev-1.42.0/agentwire/static/js/utils/swipe.js +68 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tasks.py +11 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/gh.yaml +1 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/git.yaml +4 -0
- agentwire_dev-1.42.0/agentwire/tts/__init__.py +32 -0
- agentwire_dev-1.42.0/agentwire/tts/kokoro_server.py +135 -0
- agentwire_dev-1.42.0/agentwire/wiki_audit.py +361 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/damage-control.md +65 -1
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/troubleshooting.md +19 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/voice/tts-self-hosted.md +2 -2
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_damage_control_hooks.py +89 -0
- agentwire_dev-1.42.0/tests/unit/test_doctor_voice.py +213 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_portal_api.py +64 -6
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_scheduler.py +1 -1
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_server_async.py +8 -10
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_tts_local.py +101 -1
- agentwire_dev-1.42.0/tests/unit/test_wiki_audit.py +187 -0
- agentwire_dev-1.40.0/agentwire/static/js/sidebar/council-section.js +0 -89
- agentwire_dev-1.40.0/agentwire/tts/__init__.py +0 -13
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.gitignore +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/CLA.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/Dockerfile.runpod +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/LICENSE +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/README.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/RELEASING.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/SECURITY.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/inbox.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/msg_cli.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/prompts/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/prompts/init.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/worktree-session.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-Echo--black.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-Echo--transparent.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-Echo.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-email-banner.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--transparent.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/favicon.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/android.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/automaton.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/bot.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/droid.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/drone.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/guardian.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/mech.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/probe.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/robot.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/unit.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/blob.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/cloud.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/crystal.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/flame.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/horned.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/moon.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/slime.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/star.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/winged.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/bear.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/cat.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/crown.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/deer.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/drone.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/fox.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/horse.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/lion.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/robot.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/components/icon-picker.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/components/list-card.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/components/type-tag.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/utils/auto-refresh.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/qwen_base.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/qwen_custom.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/qwen_design.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/darren.wav +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/default.wav +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/jessica.wav +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/lisa.wav +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/may.wav +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/logo.png +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/messaging.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/pyproject.toml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/requirements-tts.txt +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/integration/test_worktree_cmd.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_cli_safety.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_inbox.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -103,6 +103,31 @@ class AgentCommand:
|
|
|
103
103
|
env: dict[str, str] = field(default_factory=dict) # Secrets to inject via tmux set-environment (keeps keys out of `ps`)
|
|
104
104
|
|
|
105
105
|
|
|
106
|
+
_UNATTENDED_ENV_KEYS = ("AGENTWIRE_UNATTENDED", "AGENTWIRE_UNATTENDED_ALLOW")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _with_unattended_env(env: dict[str, str]) -> dict[str, str]:
|
|
110
|
+
"""Propagate the unattended marker into a session being created.
|
|
111
|
+
|
|
112
|
+
The scheduler is the single place that decides a dispatch is unattended —
|
|
113
|
+
it seeds ``AGENTWIRE_UNATTENDED[=1]`` (and any per-task
|
|
114
|
+
``AGENTWIRE_UNATTENDED_ALLOW``) into the dispatch subprocess environment.
|
|
115
|
+
Every session-creation path funnels its env through here on the way to
|
|
116
|
+
``tmux new-session -e K=V``, so the marker lands in the new session BEFORE
|
|
117
|
+
the agent launches and the damage-control hook can read it. A child session
|
|
118
|
+
an unattended agent spawns inherits the marker too (defense in depth).
|
|
119
|
+
|
|
120
|
+
No leak into interactive sessions: a human's ``agentwire new`` has no such
|
|
121
|
+
var in its environment, so nothing is propagated.
|
|
122
|
+
"""
|
|
123
|
+
merged = dict(env)
|
|
124
|
+
for key in _UNATTENDED_ENV_KEYS:
|
|
125
|
+
val = os.environ.get(key)
|
|
126
|
+
if val and key not in merged:
|
|
127
|
+
merged[key] = val
|
|
128
|
+
return merged
|
|
129
|
+
|
|
130
|
+
|
|
106
131
|
def _build_tmux_env_flags(env: dict[str, str]) -> list[str]:
|
|
107
132
|
"""Build `-e KEY=VAL` flag pairs for `tmux new-session`.
|
|
108
133
|
|
|
@@ -114,16 +139,17 @@ def _build_tmux_env_flags(env: dict[str, str]) -> list[str]:
|
|
|
114
139
|
the var — and the agent command runs in that initial shell.
|
|
115
140
|
"""
|
|
116
141
|
flags: list[str] = []
|
|
117
|
-
for key, value in env.items():
|
|
142
|
+
for key, value in _with_unattended_env(env).items():
|
|
118
143
|
flags.extend(["-e", f"{key}={value}"])
|
|
119
144
|
return flags
|
|
120
145
|
|
|
121
146
|
|
|
122
147
|
def _build_tmux_env_flags_shell(env: dict[str, str]) -> str:
|
|
123
148
|
"""Shell-quoted `-e 'K=V' …` fragment for inlining via SSH. Trailing space when non-empty."""
|
|
124
|
-
|
|
149
|
+
merged = _with_unattended_env(env)
|
|
150
|
+
if not merged:
|
|
125
151
|
return ""
|
|
126
|
-
parts = [f"-e {shlex.quote(f'{k}={v}')}" for k, v in
|
|
152
|
+
parts = [f"-e {shlex.quote(f'{k}={v}')}" for k, v in merged.items()]
|
|
127
153
|
return " ".join(parts) + " "
|
|
128
154
|
|
|
129
155
|
|
|
@@ -543,6 +569,12 @@ def get_stt_session_name() -> str:
|
|
|
543
569
|
return config.get("services", {}).get("stt", {}).get("session_name", "agentwire-stt")
|
|
544
570
|
|
|
545
571
|
|
|
572
|
+
def get_kokoro_session_name() -> str:
|
|
573
|
+
"""Get default-tier Kokoro TTS shim tmux session name from config."""
|
|
574
|
+
config = load_config()
|
|
575
|
+
return config.get("services", {}).get("kokoro", {}).get("session_name", "agentwire-kokoro")
|
|
576
|
+
|
|
577
|
+
|
|
546
578
|
# === Wave 2: Remote Infrastructure Helpers ===
|
|
547
579
|
|
|
548
580
|
|
|
@@ -1929,6 +1961,148 @@ def cmd_stt_status(args) -> int:
|
|
|
1929
1961
|
return 1
|
|
1930
1962
|
|
|
1931
1963
|
|
|
1964
|
+
# === Kokoro (default-tier TTS shim) Commands ===
|
|
1965
|
+
|
|
1966
|
+
def cmd_kokoro_start(args) -> int:
|
|
1967
|
+
"""Start the default-tier Kokoro TTS shim in tmux (idempotent).
|
|
1968
|
+
|
|
1969
|
+
Mirrors ``agentwire stt start``: the portal's ``ensure_managed_tts`` calls
|
|
1970
|
+
this on startup, and the early-return on an existing session means a
|
|
1971
|
+
user-started shim is reused with no port clash."""
|
|
1972
|
+
session_name = get_kokoro_session_name()
|
|
1973
|
+
|
|
1974
|
+
if tmux_session_exists(session_name):
|
|
1975
|
+
print(f"Kokoro TTS shim already running in tmux session '{session_name}'")
|
|
1976
|
+
print(f" Attach: tmux attach -t {session_name}")
|
|
1977
|
+
return 0
|
|
1978
|
+
|
|
1979
|
+
port = args.port or 8102
|
|
1980
|
+
host = args.host or "0.0.0.0"
|
|
1981
|
+
|
|
1982
|
+
# Find agentwire source directory (for running from source venv)
|
|
1983
|
+
source_dir = get_source_dir()
|
|
1984
|
+
if not (source_dir / ".venv" / "bin" / "python").exists():
|
|
1985
|
+
print("Error: Cannot find agentwire source directory with .venv", file=sys.stderr)
|
|
1986
|
+
print(f"Configure dev.source_dir in ~/.agentwire/config.yaml (current: {source_dir})", file=sys.stderr)
|
|
1987
|
+
return 1
|
|
1988
|
+
agentwire_dir = source_dir
|
|
1989
|
+
|
|
1990
|
+
python_path = agentwire_dir / ".venv" / "bin" / "python"
|
|
1991
|
+
cmd = f"cd {agentwire_dir} && KOKORO_PORT={port} KOKORO_HOST={host} {python_path} -m agentwire.tts.kokoro_server"
|
|
1992
|
+
|
|
1993
|
+
subprocess.run([
|
|
1994
|
+
"tmux", "new-session", "-d", "-s", session_name, "-c", str(agentwire_dir)
|
|
1995
|
+
], check=True)
|
|
1996
|
+
|
|
1997
|
+
subprocess.run([
|
|
1998
|
+
"tmux", "send-keys", "-t", session_name, cmd, "Enter"
|
|
1999
|
+
], check=True)
|
|
2000
|
+
|
|
2001
|
+
print(f"Kokoro TTS shim starting in tmux session '{session_name}'")
|
|
2002
|
+
print(f" Port: {port}")
|
|
2003
|
+
print(f" Attach: tmux attach -t {session_name}")
|
|
2004
|
+
return 0
|
|
2005
|
+
|
|
2006
|
+
|
|
2007
|
+
def cmd_kokoro_serve(args) -> int:
|
|
2008
|
+
"""Run the Kokoro TTS shim directly (foreground)."""
|
|
2009
|
+
import uvicorn
|
|
2010
|
+
|
|
2011
|
+
port = args.port or 8102
|
|
2012
|
+
host = args.host or "0.0.0.0"
|
|
2013
|
+
|
|
2014
|
+
os.environ["KOKORO_PORT"] = str(port)
|
|
2015
|
+
os.environ["KOKORO_HOST"] = host
|
|
2016
|
+
|
|
2017
|
+
print(f"Starting Kokoro TTS shim on {host}:{port}...")
|
|
2018
|
+
uvicorn.run(
|
|
2019
|
+
"agentwire.tts.kokoro_server:app",
|
|
2020
|
+
host=host,
|
|
2021
|
+
port=port,
|
|
2022
|
+
log_level="info",
|
|
2023
|
+
)
|
|
2024
|
+
return 0
|
|
2025
|
+
|
|
2026
|
+
|
|
2027
|
+
def cmd_kokoro_stop(args) -> int:
|
|
2028
|
+
"""Stop the Kokoro TTS shim."""
|
|
2029
|
+
session_name = get_kokoro_session_name()
|
|
2030
|
+
|
|
2031
|
+
if not tmux_session_exists(session_name):
|
|
2032
|
+
print("Kokoro TTS shim is not running.")
|
|
2033
|
+
return 1
|
|
2034
|
+
|
|
2035
|
+
subprocess.run(["tmux", "kill-session", "-t", session_name])
|
|
2036
|
+
print("Kokoro TTS shim stopped.")
|
|
2037
|
+
return 0
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
def cmd_kokoro_status(args) -> int:
|
|
2041
|
+
"""Check Kokoro TTS shim status."""
|
|
2042
|
+
json_mode = getattr(args, 'json', False)
|
|
2043
|
+
session_name = get_kokoro_session_name()
|
|
2044
|
+
config = load_config()
|
|
2045
|
+
kokoro_url = config.get("tts", {}).get("url") or "http://localhost:8102"
|
|
2046
|
+
|
|
2047
|
+
probe_error = None
|
|
2048
|
+
try:
|
|
2049
|
+
req = urllib.request.Request(f"{kokoro_url}/health")
|
|
2050
|
+
with urllib.request.urlopen(req, timeout=3) as resp:
|
|
2051
|
+
data = json.loads(resp.read().decode())
|
|
2052
|
+
if json_mode:
|
|
2053
|
+
_output_json({
|
|
2054
|
+
"success": True,
|
|
2055
|
+
"running": True,
|
|
2056
|
+
"url": kokoro_url,
|
|
2057
|
+
"healthy": data.get("status") == "ok",
|
|
2058
|
+
"status": data.get("status", "unknown"),
|
|
2059
|
+
"percent": data.get("percent", 0),
|
|
2060
|
+
"session": session_name if tmux_session_exists(session_name) else None,
|
|
2061
|
+
})
|
|
2062
|
+
else:
|
|
2063
|
+
print("Kokoro TTS shim is running")
|
|
2064
|
+
print(f" State: {data.get('status', 'unknown')} ({data.get('percent', 0)}%)")
|
|
2065
|
+
print(f" URL: {kokoro_url}")
|
|
2066
|
+
if tmux_session_exists(session_name):
|
|
2067
|
+
print(f" Attach: tmux attach -t {session_name}")
|
|
2068
|
+
return 0
|
|
2069
|
+
except Exception as e:
|
|
2070
|
+
probe_error = _describe_probe_error(e)
|
|
2071
|
+
|
|
2072
|
+
if tmux_session_exists(session_name):
|
|
2073
|
+
if json_mode:
|
|
2074
|
+
_output_json({
|
|
2075
|
+
"success": True,
|
|
2076
|
+
"running": True,
|
|
2077
|
+
"url": kokoro_url,
|
|
2078
|
+
"healthy": False,
|
|
2079
|
+
"error": probe_error,
|
|
2080
|
+
"session": session_name,
|
|
2081
|
+
"starting": True,
|
|
2082
|
+
})
|
|
2083
|
+
else:
|
|
2084
|
+
print(f"Kokoro TTS shim is starting in tmux session '{session_name}'")
|
|
2085
|
+
if probe_error:
|
|
2086
|
+
print(f" Probe: {probe_error}")
|
|
2087
|
+
print(f" Attach: tmux attach -t {session_name}")
|
|
2088
|
+
return 0
|
|
2089
|
+
|
|
2090
|
+
if json_mode:
|
|
2091
|
+
_output_json({
|
|
2092
|
+
"success": True,
|
|
2093
|
+
"running": False,
|
|
2094
|
+
"url": kokoro_url,
|
|
2095
|
+
"healthy": False,
|
|
2096
|
+
"error": probe_error,
|
|
2097
|
+
})
|
|
2098
|
+
else:
|
|
2099
|
+
print("Kokoro TTS shim is not running.")
|
|
2100
|
+
if probe_error:
|
|
2101
|
+
print(f" Probe: {probe_error}")
|
|
2102
|
+
print(" Start: agentwire kokoro start")
|
|
2103
|
+
return 1
|
|
2104
|
+
|
|
2105
|
+
|
|
1932
2106
|
# === Telegram Commands ===
|
|
1933
2107
|
|
|
1934
2108
|
|
|
@@ -6830,6 +7004,15 @@ def cmd_safety_status(args) -> int:
|
|
|
6830
7004
|
return cli_safety.safety_status_cmd()
|
|
6831
7005
|
|
|
6832
7006
|
|
|
7007
|
+
def cmd_safety_notify_unattended_block(args) -> int:
|
|
7008
|
+
"""CLI command: agentwire safety notify-unattended-block (hook-invoked)"""
|
|
7009
|
+
return cli_safety.safety_notify_unattended_block_cmd(
|
|
7010
|
+
getattr(args, "reason", "") or "",
|
|
7011
|
+
getattr(args, "rule_id", "") or "",
|
|
7012
|
+
getattr(args, "command", "") or "",
|
|
7013
|
+
)
|
|
7014
|
+
|
|
7015
|
+
|
|
6833
7016
|
def cmd_safety_logs(args) -> int:
|
|
6834
7017
|
"""CLI command: agentwire safety logs"""
|
|
6835
7018
|
tail = getattr(args, 'tail', None)
|
|
@@ -6854,6 +7037,29 @@ def cmd_safety_tooldefs_show(args) -> int:
|
|
|
6854
7037
|
return cli_safety.safety_tooldefs_show_cmd(args.tool)
|
|
6855
7038
|
|
|
6856
7039
|
|
|
7040
|
+
def _render_voice_loop_section(config, ctx) -> int:
|
|
7041
|
+
"""Print the voice-loop (push-to-talk) preflight. Returns failures found.
|
|
7042
|
+
|
|
7043
|
+
Read-only pass/fail per stage with an actionable fix line when red — the
|
|
7044
|
+
existing infra sections keep the auto-fix prompts.
|
|
7045
|
+
"""
|
|
7046
|
+
from .doctor_voice import run_voice_loop_checks
|
|
7047
|
+
|
|
7048
|
+
print("\nChecking voice loop (push-to-talk)...")
|
|
7049
|
+
failures = 0
|
|
7050
|
+
for stage in run_voice_loop_checks(config, ctx):
|
|
7051
|
+
if stage.status == "ok":
|
|
7052
|
+
print(f" [ok] {stage.name}: {stage.detail}")
|
|
7053
|
+
elif stage.status == "info":
|
|
7054
|
+
print(f" [..] {stage.name}: {stage.detail}")
|
|
7055
|
+
else:
|
|
7056
|
+
print(f" [!!] {stage.name}: {stage.detail}")
|
|
7057
|
+
for fix in stage.fixes:
|
|
7058
|
+
print(f" Fix: {fix}")
|
|
7059
|
+
failures += 1
|
|
7060
|
+
return failures
|
|
7061
|
+
|
|
7062
|
+
|
|
6857
7063
|
def cmd_doctor(args) -> int:
|
|
6858
7064
|
"""Auto-diagnose and fix common issues."""
|
|
6859
7065
|
from .network import NetworkContext
|
|
@@ -6862,6 +7068,7 @@ def cmd_doctor(args) -> int:
|
|
|
6862
7068
|
|
|
6863
7069
|
dry_run = getattr(args, 'dry_run', False)
|
|
6864
7070
|
auto_confirm = getattr(args, 'yes', False)
|
|
7071
|
+
voice_only = getattr(args, 'voice', False)
|
|
6865
7072
|
|
|
6866
7073
|
print("AgentWire Doctor")
|
|
6867
7074
|
print("=" * 60)
|
|
@@ -6869,6 +7076,27 @@ def cmd_doctor(args) -> int:
|
|
|
6869
7076
|
issues_found = 0
|
|
6870
7077
|
issues_fixed = 0
|
|
6871
7078
|
|
|
7079
|
+
# --voice: run ONLY the end-to-end push-to-talk preflight (fast, no SSH
|
|
7080
|
+
# waits) — for tight first-run / break-a-dependency verification loops.
|
|
7081
|
+
if voice_only:
|
|
7082
|
+
try:
|
|
7083
|
+
from .config import load_config as load_config_typed
|
|
7084
|
+
config = load_config_typed()
|
|
7085
|
+
except Exception as e:
|
|
7086
|
+
print(f"\n [!!] Config file error: {e}")
|
|
7087
|
+
print(" Run: agentwire init")
|
|
7088
|
+
return 1
|
|
7089
|
+
try:
|
|
7090
|
+
ctx = NetworkContext.from_config()
|
|
7091
|
+
except Exception:
|
|
7092
|
+
ctx = None
|
|
7093
|
+
issues_found = _render_voice_loop_section(config, ctx)
|
|
7094
|
+
print()
|
|
7095
|
+
print("-" * 60)
|
|
7096
|
+
print("Voice loop ready!" if issues_found == 0
|
|
7097
|
+
else f"Voice loop: {issues_found} stage(s) need attention")
|
|
7098
|
+
return 0 if issues_found == 0 else 1
|
|
7099
|
+
|
|
6872
7100
|
# 1. Check Python version
|
|
6873
7101
|
print("\nChecking Python version...")
|
|
6874
7102
|
py_version = sys.version_info
|
|
@@ -7158,34 +7386,12 @@ def cmd_doctor(args) -> int:
|
|
|
7158
7386
|
else:
|
|
7159
7387
|
print(f" -> Service is remote, start it on {service_config.machine}")
|
|
7160
7388
|
|
|
7161
|
-
# 8b.
|
|
7162
|
-
#
|
|
7163
|
-
# STT shim
|
|
7164
|
-
#
|
|
7165
|
-
#
|
|
7166
|
-
|
|
7167
|
-
if getattr(stt_cfg, "backend", "default") == "custom":
|
|
7168
|
-
from agentwire.stt.server_backend import STTServerBackend
|
|
7169
|
-
|
|
7170
|
-
stt_url = stt_cfg.url
|
|
7171
|
-
if STTServerBackend.is_available(stt_url):
|
|
7172
|
-
print(f" [ok] Stt: responding on {stt_url}")
|
|
7173
|
-
else:
|
|
7174
|
-
print(f" [!!] Stt: not responding on {stt_url}")
|
|
7175
|
-
print(" Custom-tier push-to-talk will fail until it's back.")
|
|
7176
|
-
print(" Fix: agentwire stt start")
|
|
7177
|
-
print(" If it won't boot: uv pip install --python .venv/bin/python -e '.[stt]'")
|
|
7178
|
-
issues_found += 1
|
|
7179
|
-
elif getattr(stt_cfg, "backend", "default") == "cloud":
|
|
7180
|
-
cloud_cfg = getattr(stt_cfg, "cloud", None) or {}
|
|
7181
|
-
key_env = cloud_cfg.get("api_key_env", "OPENAI_API_KEY")
|
|
7182
|
-
if os.environ.get(key_env):
|
|
7183
|
-
print(f" [ok] Stt: cloud tier ({key_env} is set)")
|
|
7184
|
-
else:
|
|
7185
|
-
print(f" [!!] Stt: cloud tier but {key_env} is not set")
|
|
7186
|
-
print(" The portal will refuse to start until the key is in its environment.")
|
|
7187
|
-
print(" Fix: add the key to ~/.agentwire/.env (docs/wiki/security/secrets.md)")
|
|
7188
|
-
issues_found += 1
|
|
7389
|
+
# 8b. Voice loop (push-to-talk) — walk the live PTT path end to end and
|
|
7390
|
+
# report each stage pass/fail with a fix line when red: mic/audio capture,
|
|
7391
|
+
# the STT shim (incl. the default-tier Moonshine :8101 shim, invisible to
|
|
7392
|
+
# the services loop), portal/tunnel reachability, and tmux+PTT wiring. This
|
|
7393
|
+
# subsumes the old standalone STT probe — the STT stage covers all tiers.
|
|
7394
|
+
issues_found += _render_voice_loop_section(config, ctx)
|
|
7189
7395
|
|
|
7190
7396
|
# 8c. Secrets — for each configured feature that needs a key, report
|
|
7191
7397
|
# whether its env var is present. Names only, never values. Keys live in
|
|
@@ -10767,6 +10973,33 @@ def main() -> int:
|
|
|
10767
10973
|
stt_status.add_argument("--json", action="store_true", help="Output JSON")
|
|
10768
10974
|
stt_status.set_defaults(func=cmd_stt_status)
|
|
10769
10975
|
|
|
10976
|
+
# === kokoro command group (default-tier TTS shim) ===
|
|
10977
|
+
kokoro_parser = subparsers.add_parser(
|
|
10978
|
+
"kokoro", help="Manage the default-tier Kokoro TTS shim (process-isolated)"
|
|
10979
|
+
)
|
|
10980
|
+
kokoro_subparsers = kokoro_parser.add_subparsers(dest="kokoro_command")
|
|
10981
|
+
|
|
10982
|
+
# kokoro start
|
|
10983
|
+
kokoro_start = kokoro_subparsers.add_parser("start", help="Start Kokoro shim in tmux")
|
|
10984
|
+
kokoro_start.add_argument("--port", type=int, help="Server port (default: 8102)")
|
|
10985
|
+
kokoro_start.add_argument("--host", type=str, help="Server host (default: 0.0.0.0)")
|
|
10986
|
+
kokoro_start.set_defaults(func=cmd_kokoro_start)
|
|
10987
|
+
|
|
10988
|
+
# kokoro serve
|
|
10989
|
+
kokoro_serve = kokoro_subparsers.add_parser("serve", help="Run Kokoro shim in foreground")
|
|
10990
|
+
kokoro_serve.add_argument("--port", type=int, help="Server port (default: 8102)")
|
|
10991
|
+
kokoro_serve.add_argument("--host", type=str, help="Server host (default: 0.0.0.0)")
|
|
10992
|
+
kokoro_serve.set_defaults(func=cmd_kokoro_serve)
|
|
10993
|
+
|
|
10994
|
+
# kokoro stop
|
|
10995
|
+
kokoro_stop = kokoro_subparsers.add_parser("stop", help="Stop Kokoro shim")
|
|
10996
|
+
kokoro_stop.set_defaults(func=cmd_kokoro_stop)
|
|
10997
|
+
|
|
10998
|
+
# kokoro status
|
|
10999
|
+
kokoro_status = kokoro_subparsers.add_parser("status", help="Check Kokoro shim status")
|
|
11000
|
+
kokoro_status.add_argument("--json", action="store_true", help="Output JSON")
|
|
11001
|
+
kokoro_status.set_defaults(func=cmd_kokoro_status)
|
|
11002
|
+
|
|
10770
11003
|
# === quo command ===
|
|
10771
11004
|
from agentwire.channels.quo import cmd_quo
|
|
10772
11005
|
quo_parser = subparsers.add_parser("quo", help="Send SMS via Quo (OpenPhone)")
|
|
@@ -11357,6 +11590,16 @@ def main() -> int:
|
|
|
11357
11590
|
)
|
|
11358
11591
|
safety_status.set_defaults(func=cmd_safety_status)
|
|
11359
11592
|
|
|
11593
|
+
# safety notify-unattended-block (hook-invoked, not for humans)
|
|
11594
|
+
safety_notify = safety_subparsers.add_parser(
|
|
11595
|
+
"notify-unattended-block",
|
|
11596
|
+
help="Email the owner that an unattended action was blocked (hook-internal)",
|
|
11597
|
+
)
|
|
11598
|
+
safety_notify.add_argument("--reason", default="", help="Why the command was blocked")
|
|
11599
|
+
safety_notify.add_argument("--rule-id", dest="rule_id", default="", help="Matched rule id")
|
|
11600
|
+
safety_notify.add_argument("--command", default="", help="The blocked command")
|
|
11601
|
+
safety_notify.set_defaults(func=cmd_safety_notify_unattended_block)
|
|
11602
|
+
|
|
11360
11603
|
# safety logs
|
|
11361
11604
|
safety_logs = safety_subparsers.add_parser(
|
|
11362
11605
|
"logs", help="Query audit logs"
|
|
@@ -11406,6 +11649,10 @@ def main() -> int:
|
|
|
11406
11649
|
"-y", "--yes", action="store_true",
|
|
11407
11650
|
help="Auto-confirm all fixes without prompting"
|
|
11408
11651
|
)
|
|
11652
|
+
doctor_parser.add_argument(
|
|
11653
|
+
"--voice", action="store_true",
|
|
11654
|
+
help="Run only the voice loop (push-to-talk) preflight — fast, no SSH waits"
|
|
11655
|
+
)
|
|
11409
11656
|
doctor_parser.set_defaults(func=cmd_doctor)
|
|
11410
11657
|
|
|
11411
11658
|
# === generate-certs (top-level shortcut) ===
|
|
@@ -8,6 +8,7 @@ stay in sync.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
import os
|
|
11
12
|
import shutil
|
|
12
13
|
import sys
|
|
13
14
|
from datetime import datetime
|
|
@@ -342,6 +343,48 @@ def safety_status_cmd() -> int:
|
|
|
342
343
|
return 0
|
|
343
344
|
|
|
344
345
|
|
|
346
|
+
def safety_notify_unattended_block_cmd(
|
|
347
|
+
reason: str, rule_id: str, command: str
|
|
348
|
+
) -> int:
|
|
349
|
+
"""CLI command: ``agentwire safety notify-unattended-block``.
|
|
350
|
+
|
|
351
|
+
Invoked fire-and-forget by the bash damage-control hook when an
|
|
352
|
+
unattended (scheduler) run hits an ``ask``-tier command that isn't on the
|
|
353
|
+
allowlist. Emails the owner via the shared Resend wiring so the blocked
|
|
354
|
+
action surfaces immediately instead of silently disappearing.
|
|
355
|
+
"""
|
|
356
|
+
session = os.environ.get("AGENTWIRE_SESSION_NAME") or os.environ.get(
|
|
357
|
+
"AGENTWIRE_SESSION_ID", "unknown"
|
|
358
|
+
)
|
|
359
|
+
cwd = os.environ.get("PWD", "")
|
|
360
|
+
subject = f"[agentwire] Unattended action blocked: {reason[:80]}"
|
|
361
|
+
body = (
|
|
362
|
+
f"An unattended (scheduled) agent attempted an action that requires "
|
|
363
|
+
f"human confirmation, so it was **blocked** (fail-closed).\n\n"
|
|
364
|
+
f"- **Session:** {session}\n"
|
|
365
|
+
f"- **Working dir:** {cwd or 'unknown'}\n"
|
|
366
|
+
f"- **Rule:** {rule_id or 'unknown'}\n"
|
|
367
|
+
f"- **Reason:** {reason}\n"
|
|
368
|
+
f"- **Command:** `{command}`\n"
|
|
369
|
+
f"- **When:** {datetime.now().isoformat(timespec='seconds')}\n\n"
|
|
370
|
+
f"Nothing was executed. To permit this specific action for the task in "
|
|
371
|
+
f"future, add rule id `{rule_id}` to that task's `unattended_allow` in "
|
|
372
|
+
f"its `.agentwire.yml` (or to `safety.unattended_allow` globally)."
|
|
373
|
+
)
|
|
374
|
+
try:
|
|
375
|
+
from agentwire.channels.email import send_email
|
|
376
|
+
|
|
377
|
+
result = send_email(subject=subject, body=body)
|
|
378
|
+
if getattr(result, "success", False):
|
|
379
|
+
return 0
|
|
380
|
+
print(f"notify-unattended-block: email failed: "
|
|
381
|
+
f"{getattr(result, 'error', 'unknown')}", file=sys.stderr)
|
|
382
|
+
return 1
|
|
383
|
+
except Exception as e: # email not configured, etc. — never crash the notifier
|
|
384
|
+
print(f"notify-unattended-block: {e}", file=sys.stderr)
|
|
385
|
+
return 1
|
|
386
|
+
|
|
387
|
+
|
|
345
388
|
def safety_logs_cmd(
|
|
346
389
|
tail: Optional[int] = None,
|
|
347
390
|
session: Optional[str] = None,
|
|
@@ -164,13 +164,20 @@ def _validate_voice_backend(
|
|
|
164
164
|
class TTSConfig:
|
|
165
165
|
"""Text-to-speech configuration.
|
|
166
166
|
|
|
167
|
-
Two tiers: ``default`` speaks via
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
Two tiers: ``default`` speaks via Kokoro running in the portal-managed shim
|
|
168
|
+
**subprocess** (tmux ``agentwire-kokoro``, default ``:8102``) — the portal
|
|
169
|
+
ensures it's running on startup and talks to it over HTTP, with process
|
|
170
|
+
isolation keeping the ~200 MB download + ONNX warm-up off the event loop
|
|
171
|
+
(#398, mirroring the STT shim). Browser speechSynthesis (and an OS-voice
|
|
172
|
+
fallback when no browser is connected) covers speech while the model loads
|
|
173
|
+
or when Kokoro can't load (py3.14+). For this tier ``url`` is optional and
|
|
174
|
+
resolves to ``http://localhost:8102``; if an operator overrides the shim
|
|
175
|
+
port (``KOKORO_PORT``) or ``url``, the two must agree. ``custom`` POSTs to
|
|
176
|
+
any HTTP shim implementing the contract (docs/wiki/voice/shim-contract.md).
|
|
170
177
|
"""
|
|
171
178
|
|
|
172
179
|
backend: str = "default" # default | custom
|
|
173
|
-
url: str | None = None # shim URL (required for custom
|
|
180
|
+
url: str | None = None # shim URL (required for custom; optional override for default :8102)
|
|
174
181
|
default_voice: str = "default"
|
|
175
182
|
voices_dir: Path = field(default_factory=lambda: Path.home() / ".agentwire" / "voices")
|
|
176
183
|
# Session-default knobs; sent to custom shims inside `options`
|
|
@@ -69,6 +69,11 @@ def sitting_path(name: str) -> Path:
|
|
|
69
69
|
return council_dir(name) / "sitting.json"
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
def archive_path(name: str) -> Path:
|
|
73
|
+
"""Preserved record of a dismissed sitting (kept so threads stay browsable)."""
|
|
74
|
+
return council_dir(name) / "archive.json"
|
|
75
|
+
|
|
76
|
+
|
|
72
77
|
def workspace_dir(name: str) -> Path:
|
|
73
78
|
return council_dir(name) / "workspace"
|
|
74
79
|
|
|
@@ -195,13 +200,62 @@ def write_sitting(name: str, sitting: Sitting) -> None:
|
|
|
195
200
|
|
|
196
201
|
|
|
197
202
|
def clear_sitting(name: str) -> None:
|
|
198
|
-
"""End the sitting.
|
|
203
|
+
"""End the sitting. A thread that deliberated something is preserved to
|
|
204
|
+
``archive.json`` (so it stays browsable/re-askable from the UI), and the
|
|
205
|
+
``prompts/`` history is kept; only the live ``sitting.json`` is removed."""
|
|
206
|
+
sitting = read_sitting(name)
|
|
207
|
+
if sitting is not None and prompts_dir(name).is_dir():
|
|
208
|
+
data = sitting.to_dict()
|
|
209
|
+
data["dismissed_at"] = now_iso()
|
|
210
|
+
try:
|
|
211
|
+
_atomic_write(archive_path(name), data)
|
|
212
|
+
except OSError:
|
|
213
|
+
pass
|
|
199
214
|
try:
|
|
200
215
|
sitting_path(name).unlink()
|
|
201
216
|
except FileNotFoundError:
|
|
202
217
|
pass
|
|
203
218
|
|
|
204
219
|
|
|
220
|
+
def read_archive_dict(name: str) -> dict | None:
|
|
221
|
+
"""Raw archive record (incl. ``dismissed_at``), or None if not archived."""
|
|
222
|
+
path = archive_path(name)
|
|
223
|
+
if not path.exists():
|
|
224
|
+
return None
|
|
225
|
+
try:
|
|
226
|
+
with open(path) as f:
|
|
227
|
+
data = json.load(f)
|
|
228
|
+
except (json.JSONDecodeError, OSError):
|
|
229
|
+
return None
|
|
230
|
+
return data if isinstance(data, dict) else None
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def read_archived(name: str) -> Sitting | None:
|
|
234
|
+
"""The preserved record of a dismissed sitting as a ``Sitting``, or None."""
|
|
235
|
+
data = read_archive_dict(name)
|
|
236
|
+
return Sitting.from_dict(data) if data is not None else None
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _has_rounds(name: str) -> bool:
|
|
240
|
+
pdir = prompts_dir(name)
|
|
241
|
+
if not pdir.is_dir():
|
|
242
|
+
return False
|
|
243
|
+
return any(p.is_dir() and p.name.isdigit() for p in pdir.iterdir())
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def list_archive() -> list[str]:
|
|
247
|
+
"""Dismissed threads: have prompt history but no live ``sitting.json``."""
|
|
248
|
+
if not COUNCIL_ROOT.is_dir():
|
|
249
|
+
return []
|
|
250
|
+
out = []
|
|
251
|
+
for child in COUNCIL_ROOT.iterdir():
|
|
252
|
+
if not child.is_dir() or (child / "sitting.json").exists():
|
|
253
|
+
continue # absent or still live
|
|
254
|
+
if _has_rounds(child.name):
|
|
255
|
+
out.append(child.name)
|
|
256
|
+
return out
|
|
257
|
+
|
|
258
|
+
|
|
205
259
|
def allocate_prompt_id(name: str) -> int:
|
|
206
260
|
"""Bump and persist the sitting's prompt counter; return the new id.
|
|
207
261
|
|
|
@@ -143,13 +143,31 @@ def snapshot(
|
|
|
143
143
|
the sitting ``name``; the per-prompt ``meta.json.roster`` (falling back to
|
|
144
144
|
the sitting roster) fixes both soul order and grid size — nothing is
|
|
145
145
|
hardcoded to a roster of six.
|
|
146
|
+
|
|
147
|
+
The thread artifact outlives the compute: a dismissed sitting (no live
|
|
148
|
+
``sitting.json``) is still a fully readable thread, derived from the
|
|
149
|
+
preserved ``archive.json`` or, failing that, reconstructed from the
|
|
150
|
+
``prompts/`` tree. ``archived`` flags which case the caller is looking at.
|
|
146
151
|
"""
|
|
147
152
|
sitting = state.read_sitting(name)
|
|
153
|
+
archived = sitting is None
|
|
148
154
|
if sitting is None:
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
sitting = state.read_archived(name)
|
|
156
|
+
if sitting is None:
|
|
157
|
+
if not available_prompt_ids(name):
|
|
158
|
+
return None
|
|
159
|
+
sitting = state.Sitting(
|
|
160
|
+
orchestrator=state.orchestrator_for(name),
|
|
161
|
+
roster=[],
|
|
162
|
+
sessions={},
|
|
163
|
+
started_at="",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# available_prompt_ids (disk-derived) works for live and archived alike —
|
|
167
|
+
# the sitting.json prompt counter is gone once dismissed.
|
|
151
168
|
if prompt_id is None:
|
|
152
|
-
|
|
169
|
+
ids = available_prompt_ids(name)
|
|
170
|
+
prompt_id = ids[-1] if ids else None
|
|
153
171
|
|
|
154
172
|
dead_souls = dead_souls or set()
|
|
155
173
|
|
|
@@ -178,6 +196,7 @@ def snapshot(
|
|
|
178
196
|
"tiles": tiles,
|
|
179
197
|
"total": len(tiles),
|
|
180
198
|
"final": final,
|
|
199
|
+
"archived": archived,
|
|
181
200
|
}
|
|
182
201
|
|
|
183
202
|
|