agentwire-dev 1.59.0__tar.gz → 1.60.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.59.0 → agentwire_dev-1.60.0}/PKG-INFO +1 -1
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/doctor_cli.py +82 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/server.py +10 -8
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts_cli.py +107 -14
- agentwire_dev-1.60.0/tests/unit/test_shim_selfheal.py +202 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/.gitignore +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/AGENTS.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/LICENSE +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/README.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/RELEASING.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/SECURITY.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/chrome_tabs.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/config.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/core.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/council/minutes.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/inbox.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_chrome.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_msg.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/mcp_worktree.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/msg_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/worker-worktree.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/session_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/session_ready.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/desktop.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tabs_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tasks_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/council/minutes.html.j2 +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/logo.png +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/sessions/messaging.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/pyproject.toml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/integration/test_send_verified_tmux.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/integration/test_worktree_cmd.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_chrome_tabs.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_core_created_by_rooting.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_council_minutes.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_dangling_worktrees.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_doctor_task_migration.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_inbox.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_posture_default.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_session_ready.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_tasks_cli.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_window_cycling_binding.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_worktree_branch_cleanup.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_worktree_layout.py +0 -0
- {agentwire_dev-1.59.0 → agentwire_dev-1.60.0}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -404,6 +404,77 @@ def _render_task_migration_section() -> int:
|
|
|
404
404
|
return len(unmigrated)
|
|
405
405
|
|
|
406
406
|
|
|
407
|
+
def _find_dead_managed_shims() -> list[dict]:
|
|
408
|
+
"""Managed voice shims whose tmux session is alive but ``/health`` is dead.
|
|
409
|
+
|
|
410
|
+
The #734 failure mode: a wedged Kokoro (:8102) or Moonshine STT (:8101) shim
|
|
411
|
+
inside a live ``agentwire-kokoro``/``agentwire-stt`` session — say/transcribe
|
|
412
|
+
then silently fall back to browser voice/recognition with no error, and the
|
|
413
|
+
old session-existence-only ``ensure`` never relaunches it. Only the default
|
|
414
|
+
tier runs a managed shim, so we check that tier only, and reuse the same
|
|
415
|
+
``_shim_session_state`` liveness predicate as ``start`` (SSOT).
|
|
416
|
+
"""
|
|
417
|
+
from .config import load_config as load_config_typed
|
|
418
|
+
from .core import (
|
|
419
|
+
get_kokoro_session_name,
|
|
420
|
+
get_stt_session_name,
|
|
421
|
+
tmux_session_exists,
|
|
422
|
+
)
|
|
423
|
+
from .tts_cli import _shim_session_state
|
|
424
|
+
|
|
425
|
+
cfg = load_config_typed()
|
|
426
|
+
checks: list[tuple[str, str, int, str, str]] = []
|
|
427
|
+
|
|
428
|
+
if getattr(getattr(cfg, "tts", None), "backend", "default") == "default":
|
|
429
|
+
checks.append((
|
|
430
|
+
"Kokoro TTS", get_kokoro_session_name(), 8102,
|
|
431
|
+
"agentwire kokoro start", "say falls back to browser voice",
|
|
432
|
+
))
|
|
433
|
+
|
|
434
|
+
if getattr(getattr(cfg, "stt", None), "backend", "default") == "default":
|
|
435
|
+
# Only the Moonshine path runs a shim; without it the default tier
|
|
436
|
+
# transcribes in the browser and there is nothing to probe.
|
|
437
|
+
from .stt import moonshine_importable
|
|
438
|
+
|
|
439
|
+
if moonshine_importable():
|
|
440
|
+
checks.append((
|
|
441
|
+
"Moonshine STT", get_stt_session_name(), 8101,
|
|
442
|
+
"agentwire stt start",
|
|
443
|
+
"transcription falls back to browser recognition",
|
|
444
|
+
))
|
|
445
|
+
|
|
446
|
+
dead: list[dict] = []
|
|
447
|
+
for label, session, port, fix, impact in checks:
|
|
448
|
+
if not tmux_session_exists(session):
|
|
449
|
+
continue
|
|
450
|
+
live, status = _shim_session_state(session, port)
|
|
451
|
+
if not live:
|
|
452
|
+
dead.append({
|
|
453
|
+
"label": label, "session": session, "port": port,
|
|
454
|
+
"status": status, "fix": fix, "impact": impact,
|
|
455
|
+
})
|
|
456
|
+
return dead
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def _render_shim_liveness_section() -> int:
|
|
460
|
+
"""Doctor section: managed shim session alive but ``/health`` dead (#734)."""
|
|
461
|
+
dead = _find_dead_managed_shims()
|
|
462
|
+
if not dead:
|
|
463
|
+
print(" [ok] No dead-but-present voice shims")
|
|
464
|
+
return 0
|
|
465
|
+
for d in dead:
|
|
466
|
+
print(
|
|
467
|
+
f" [!!] {d['label']} shim session '{d['session']}' is alive but "
|
|
468
|
+
f":{d['port']}/health is not serving (state: "
|
|
469
|
+
f"{d['status'] or 'no response'}) — {d['impact']}."
|
|
470
|
+
)
|
|
471
|
+
print(
|
|
472
|
+
f" Self-heal: re-run `{dead[0]['fix']}` — it is now health-aware and "
|
|
473
|
+
"reaps a dead session before relaunching."
|
|
474
|
+
)
|
|
475
|
+
return len(dead)
|
|
476
|
+
|
|
477
|
+
|
|
407
478
|
def cmd_doctor(args) -> int:
|
|
408
479
|
"""Auto-diagnose and fix common issues."""
|
|
409
480
|
from .hooks_cli import _managed_file_state, _managed_hook_files, get_hooks_source
|
|
@@ -926,6 +997,17 @@ def cmd_doctor(args) -> int:
|
|
|
926
997
|
except Exception as e:
|
|
927
998
|
print(f" [..] Could not check project task migration: {e}")
|
|
928
999
|
|
|
1000
|
+
# 13. Managed voice shims (Kokoro :8102, Moonshine STT :8101) whose tmux
|
|
1001
|
+
# session is alive but whose /health is dead (#734). The old
|
|
1002
|
+
# session-existence-only idempotency masked a wedged engine forever, so
|
|
1003
|
+
# say/transcribe silently fell back to browser voice. Surfaced distinctly
|
|
1004
|
+
# here with the now-health-aware self-heal command.
|
|
1005
|
+
print("\nChecking managed voice shim liveness (#734)...")
|
|
1006
|
+
try:
|
|
1007
|
+
issues_found += _render_shim_liveness_section()
|
|
1008
|
+
except Exception as e:
|
|
1009
|
+
print(f" [..] Could not check managed voice shim liveness: {e}")
|
|
1010
|
+
|
|
929
1011
|
# Summary
|
|
930
1012
|
print()
|
|
931
1013
|
print("-" * 60)
|
|
@@ -387,10 +387,11 @@ class AgentWireServer(
|
|
|
387
387
|
"""Ensure the default-tier Moonshine shim subprocess is running.
|
|
388
388
|
|
|
389
389
|
Delegates to the CLI (single source of truth): ``agentwire stt start``
|
|
390
|
-
is idempotent — ``cmd_stt_start``
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
390
|
+
is idempotent and health-aware — ``cmd_stt_start`` reuses the
|
|
391
|
+
``agentwire-stt`` session only when it is actually serving, and reaps +
|
|
392
|
+
relaunches a dead-but-present one (#734), so a wedged shim self-heals on
|
|
393
|
+
the next ensure. The ~19s ONNX warm-up happens in that child process,
|
|
394
|
+
never on the portal's event loop. Mirrors ``autostart_custom_services``."""
|
|
394
395
|
await asyncio.sleep(5) # let the portal finish binding first
|
|
395
396
|
try:
|
|
396
397
|
success, result = await self.run_agentwire_cmd(["stt", "start"], json_output=False)
|
|
@@ -438,10 +439,11 @@ class AgentWireServer(
|
|
|
438
439
|
"""Ensure the default-tier Kokoro TTS shim subprocess is running.
|
|
439
440
|
|
|
440
441
|
Delegates to the CLI (single source of truth): ``agentwire kokoro start``
|
|
441
|
-
is idempotent — ``cmd_kokoro_start``
|
|
442
|
-
``agentwire-kokoro``
|
|
443
|
-
|
|
444
|
-
|
|
442
|
+
is idempotent and health-aware — ``cmd_kokoro_start`` reuses the
|
|
443
|
+
``agentwire-kokoro`` session only when it is actually serving, and reaps
|
|
444
|
+
+ relaunches a dead-but-present one (#734), so a wedged shim self-heals
|
|
445
|
+
on the next ensure. The ~200 MB download + ONNX warm-up happens in that
|
|
446
|
+
child process, never on the portal's event loop. Mirrors
|
|
445
447
|
``ensure_managed_stt``."""
|
|
446
448
|
await asyncio.sleep(5) # let the portal finish binding first
|
|
447
449
|
try:
|
|
@@ -459,19 +459,102 @@ def _resolve_shim_python() -> tuple[str | None, str | None, str | None]:
|
|
|
459
459
|
return sys.executable, None, None
|
|
460
460
|
|
|
461
461
|
|
|
462
|
+
# === Managed shim liveness (health-aware idempotency, #734) ===
|
|
463
|
+
#
|
|
464
|
+
# A managed voice shim (Kokoro TTS :8102, Moonshine STT :8101) runs uvicorn in
|
|
465
|
+
# a tmux session and warms its model in the background. The old start path was
|
|
466
|
+
# idempotent on *session existence* alone, so a dead/wedged process inside a
|
|
467
|
+
# live session was treated as healthy forever — say/transcribe then silently
|
|
468
|
+
# fell back to browser voice. These helpers make start/ensure health-aware:
|
|
469
|
+
# reuse a session only when it is actually serving (or too young to have bound
|
|
470
|
+
# its port yet); otherwise reap it and relaunch.
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def _probe_shim_health(port: int, timeout: float = 2.0) -> tuple[bool, str | None]:
|
|
474
|
+
"""Probe a managed shim's ``/health`` on localhost.
|
|
475
|
+
|
|
476
|
+
Returns ``(responded, status)``: ``responded`` is True when the HTTP server
|
|
477
|
+
answered at all (even mid-warmup); ``status`` is the reported state string
|
|
478
|
+
(``ok``/``loading``/``downloading``/``absent``/``failed``/…) or None when
|
|
479
|
+
nothing answered (process dead, wedged, or the port not yet bound)."""
|
|
480
|
+
try:
|
|
481
|
+
req = urllib.request.Request(f"http://localhost:{port}/health")
|
|
482
|
+
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
|
483
|
+
data = json.loads(resp.read().decode())
|
|
484
|
+
return True, data.get("status")
|
|
485
|
+
except Exception:
|
|
486
|
+
return False, None
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def _tmux_session_age(session_name: str) -> float | None:
|
|
490
|
+
"""Seconds since the tmux session was created, or None if unknowable."""
|
|
491
|
+
import time
|
|
492
|
+
|
|
493
|
+
result = subprocess.run(
|
|
494
|
+
["tmux", "display-message", "-p", "-t", session_name, "#{session_created}"],
|
|
495
|
+
capture_output=True,
|
|
496
|
+
text=True,
|
|
497
|
+
)
|
|
498
|
+
if result.returncode != 0:
|
|
499
|
+
return None
|
|
500
|
+
try:
|
|
501
|
+
return time.time() - int(result.stdout.strip())
|
|
502
|
+
except (ValueError, TypeError):
|
|
503
|
+
return None
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def _shim_session_state(
|
|
507
|
+
session_name: str, port: int, *, warmup_grace: float = 25.0
|
|
508
|
+
) -> tuple[bool, str | None]:
|
|
509
|
+
"""``(live, status)`` for an EXISTING managed-shim tmux session.
|
|
510
|
+
|
|
511
|
+
The single liveness predicate shared by ``start`` (reuse-vs-reap) and
|
|
512
|
+
``doctor`` (flag-a-dead-shim). A session is *live* when its ``/health``
|
|
513
|
+
answers a non-``failed`` status, OR it is younger than ``warmup_grace`` (the
|
|
514
|
+
port may not be bound yet). A process that never answers past the grace, or
|
|
515
|
+
reports a terminal ``failed``, is NOT live. ``status`` is the ``/health``
|
|
516
|
+
state, ``"starting"`` for a still-booting young session, or None for a dead
|
|
517
|
+
one — carried through for human-readable diagnostics."""
|
|
518
|
+
responded, status = _probe_shim_health(port)
|
|
519
|
+
if responded:
|
|
520
|
+
return (status != "failed", status)
|
|
521
|
+
age = _tmux_session_age(session_name)
|
|
522
|
+
if age is not None and age < warmup_grace:
|
|
523
|
+
return (True, "starting")
|
|
524
|
+
return (False, status)
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
def _reap_shim_session(session_name: str) -> None:
|
|
528
|
+
"""Kill a dead shim tmux session so a fresh one can bind the port."""
|
|
529
|
+
import time
|
|
530
|
+
|
|
531
|
+
subprocess.run(["tmux", "kill-session", "-t", session_name], capture_output=True)
|
|
532
|
+
time.sleep(0.5)
|
|
533
|
+
|
|
534
|
+
|
|
462
535
|
# === STT Commands ===
|
|
463
536
|
|
|
464
537
|
def cmd_stt_start(args) -> int:
|
|
465
538
|
"""Start the STT server in tmux."""
|
|
466
539
|
session_name = get_stt_session_name()
|
|
540
|
+
port = args.port or 8101
|
|
541
|
+
host = args.host or "0.0.0.0"
|
|
467
542
|
|
|
468
543
|
if tmux_session_exists(session_name):
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
544
|
+
live, status = _shim_session_state(session_name, port)
|
|
545
|
+
if live:
|
|
546
|
+
print(f"STT server already running in tmux session '{session_name}'")
|
|
547
|
+
print(f" Attach: tmux attach -t {session_name}")
|
|
548
|
+
return 0
|
|
549
|
+
# Session exists but :{port}/health isn't serving (dead/wedged) —
|
|
550
|
+
# self-heal by reaping and relaunching instead of masking a dead
|
|
551
|
+
# engine behind mere session existence (#734).
|
|
552
|
+
print(
|
|
553
|
+
f"STT server session '{session_name}' is present but not serving "
|
|
554
|
+
f"(state: {status or 'no response'}) — relaunching."
|
|
555
|
+
)
|
|
556
|
+
_reap_shim_session(session_name)
|
|
472
557
|
|
|
473
|
-
port = args.port or 8101
|
|
474
|
-
host = args.host or "0.0.0.0"
|
|
475
558
|
config = load_config()
|
|
476
559
|
stt_config = config.get("stt", {})
|
|
477
560
|
model = args.model or stt_config.get("model", "base")
|
|
@@ -576,21 +659,31 @@ def cmd_stt_status(args) -> int:
|
|
|
576
659
|
# === Kokoro (default-tier TTS shim) Commands ===
|
|
577
660
|
|
|
578
661
|
def cmd_kokoro_start(args) -> int:
|
|
579
|
-
"""Start the default-tier Kokoro TTS shim in tmux (idempotent).
|
|
662
|
+
"""Start the default-tier Kokoro TTS shim in tmux (idempotent, health-aware).
|
|
580
663
|
|
|
581
664
|
Mirrors ``agentwire stt start``: the portal's ``ensure_managed_tts`` calls
|
|
582
|
-
this on startup
|
|
583
|
-
|
|
665
|
+
this on startup. An existing session is reused only when it is actually
|
|
666
|
+
serving (``/health`` ok/warming); a dead-but-present session is reaped and
|
|
667
|
+
relaunched so a wedged shim self-heals instead of masking forever (#734)."""
|
|
584
668
|
session_name = get_kokoro_session_name()
|
|
585
|
-
|
|
586
|
-
if tmux_session_exists(session_name):
|
|
587
|
-
print(f"Kokoro TTS shim already running in tmux session '{session_name}'")
|
|
588
|
-
print(f" Attach: tmux attach -t {session_name}")
|
|
589
|
-
return 0
|
|
590
|
-
|
|
591
669
|
port = args.port or 8102
|
|
592
670
|
host = args.host or "0.0.0.0"
|
|
593
671
|
|
|
672
|
+
if tmux_session_exists(session_name):
|
|
673
|
+
live, status = _shim_session_state(session_name, port)
|
|
674
|
+
if live:
|
|
675
|
+
print(f"Kokoro TTS shim already running in tmux session '{session_name}'")
|
|
676
|
+
print(f" Attach: tmux attach -t {session_name}")
|
|
677
|
+
return 0
|
|
678
|
+
# Session exists but :{port}/health isn't serving (dead/wedged) —
|
|
679
|
+
# self-heal by reaping and relaunching instead of masking a dead
|
|
680
|
+
# engine behind mere session existence (#734).
|
|
681
|
+
print(
|
|
682
|
+
f"Kokoro TTS shim session '{session_name}' is present but not serving "
|
|
683
|
+
f"(state: {status or 'no response'}) — relaunching."
|
|
684
|
+
)
|
|
685
|
+
_reap_shim_session(session_name)
|
|
686
|
+
|
|
594
687
|
# Resolve an interpreter that can run the shim: dev-checkout venv when one
|
|
595
688
|
# exists, otherwise the installed package's interpreter.
|
|
596
689
|
python_path, cwd, error = _resolve_shim_python()
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Health-aware managed-shim self-heal (#734).
|
|
2
|
+
|
|
3
|
+
A dead/wedged Kokoro (:8102) or Moonshine STT (:8101) shim inside a live tmux
|
|
4
|
+
session used to be treated as healthy forever (idempotency keyed on session
|
|
5
|
+
existence alone), so say/transcribe silently fell back to browser voice. These
|
|
6
|
+
tests pin the liveness predicate, the reuse-vs-reap decision in ``start``, and
|
|
7
|
+
the doctor surfacing — without touching any real tmux session or port.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from types import SimpleNamespace
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from agentwire import tts_cli
|
|
15
|
+
|
|
16
|
+
# === _shim_session_state: the shared liveness predicate ====================
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _patch_probe(monkeypatch, *, responded, status):
|
|
20
|
+
monkeypatch.setattr(
|
|
21
|
+
tts_cli, "_probe_shim_health", lambda port, timeout=2.0: (responded, status)
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_state_ok_is_live(monkeypatch):
|
|
26
|
+
_patch_probe(monkeypatch, responded=True, status="ok")
|
|
27
|
+
assert tts_cli._shim_session_state("s", 8102) == (True, "ok")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.mark.parametrize("warming", ["loading", "downloading", "absent"])
|
|
31
|
+
def test_state_warming_is_live(monkeypatch, warming):
|
|
32
|
+
# A shim mid-warmup still answers /health — reuse it, never reap it.
|
|
33
|
+
_patch_probe(monkeypatch, responded=True, status=warming)
|
|
34
|
+
live, status = tts_cli._shim_session_state("s", 8102)
|
|
35
|
+
assert live is True
|
|
36
|
+
assert status == warming
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_state_failed_is_not_live(monkeypatch):
|
|
40
|
+
# Terminal engine failure: the process answers but will never be ready.
|
|
41
|
+
_patch_probe(monkeypatch, responded=True, status="failed")
|
|
42
|
+
assert tts_cli._shim_session_state("s", 8102) == (False, "failed")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_state_no_response_young_is_live(monkeypatch):
|
|
46
|
+
# Just launched: the port may not be bound yet — give it the grace window.
|
|
47
|
+
_patch_probe(monkeypatch, responded=False, status=None)
|
|
48
|
+
monkeypatch.setattr(tts_cli, "_tmux_session_age", lambda s: 3.0)
|
|
49
|
+
assert tts_cli._shim_session_state("s", 8102, warmup_grace=25.0) == (True, "starting")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_state_no_response_old_is_dead(monkeypatch):
|
|
53
|
+
# Session has existed for hours but nothing answers — dead/wedged.
|
|
54
|
+
_patch_probe(monkeypatch, responded=False, status=None)
|
|
55
|
+
monkeypatch.setattr(tts_cli, "_tmux_session_age", lambda s: 9000.0)
|
|
56
|
+
assert tts_cli._shim_session_state("s", 8102, warmup_grace=25.0) == (False, None)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_state_no_response_unknown_age_is_dead(monkeypatch):
|
|
60
|
+
# Age unknowable (session vanished mid-probe) → not live.
|
|
61
|
+
_patch_probe(monkeypatch, responded=False, status=None)
|
|
62
|
+
monkeypatch.setattr(tts_cli, "_tmux_session_age", lambda s: None)
|
|
63
|
+
assert tts_cli._shim_session_state("s", 8102) == (False, None)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# === start commands: reuse when live, reap+relaunch when dead ==============
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class _StartHarness:
|
|
70
|
+
"""Records whether start reaped the session / launched a fresh one."""
|
|
71
|
+
|
|
72
|
+
def __init__(self, monkeypatch, module=tts_cli):
|
|
73
|
+
self.reaped = False
|
|
74
|
+
self.launched = False
|
|
75
|
+
monkeypatch.setattr(module, "tmux_session_exists", lambda s: True)
|
|
76
|
+
monkeypatch.setattr(module, "_reap_shim_session", self._reap)
|
|
77
|
+
monkeypatch.setattr(
|
|
78
|
+
module, "_resolve_shim_python", lambda: ("/usr/bin/python3", None, None)
|
|
79
|
+
)
|
|
80
|
+
monkeypatch.setattr(module, "load_config", lambda: {"stt": {}})
|
|
81
|
+
monkeypatch.setattr(module.subprocess, "run", self._run)
|
|
82
|
+
|
|
83
|
+
def _reap(self, session):
|
|
84
|
+
self.reaped = True
|
|
85
|
+
|
|
86
|
+
def _run(self, cmd, *a, **k):
|
|
87
|
+
# `tmux new-session` is the launch of a fresh shim.
|
|
88
|
+
if isinstance(cmd, list) and "new-session" in cmd:
|
|
89
|
+
self.launched = True
|
|
90
|
+
return SimpleNamespace(returncode=0, stdout="", stderr="")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _kokoro_args():
|
|
94
|
+
return SimpleNamespace(port=None, host=None)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _stt_args():
|
|
98
|
+
return SimpleNamespace(port=None, host=None, model=None, backend=None)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_kokoro_start_reuses_live_session(monkeypatch, capsys):
|
|
102
|
+
h = _StartHarness(monkeypatch)
|
|
103
|
+
monkeypatch.setattr(tts_cli, "_shim_session_state", lambda s, p: (True, "ok"))
|
|
104
|
+
rc = tts_cli.cmd_kokoro_start(_kokoro_args())
|
|
105
|
+
assert rc == 0
|
|
106
|
+
assert h.reaped is False and h.launched is False
|
|
107
|
+
assert "already running" in capsys.readouterr().out
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_kokoro_start_reaps_and_relaunches_dead_session(monkeypatch, capsys):
|
|
111
|
+
h = _StartHarness(monkeypatch)
|
|
112
|
+
monkeypatch.setattr(tts_cli, "_shim_session_state", lambda s, p: (False, None))
|
|
113
|
+
rc = tts_cli.cmd_kokoro_start(_kokoro_args())
|
|
114
|
+
assert rc == 0
|
|
115
|
+
assert h.reaped is True and h.launched is True
|
|
116
|
+
out = capsys.readouterr().out
|
|
117
|
+
assert "not serving" in out and "already running" not in out
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_stt_start_reuses_live_session(monkeypatch, capsys):
|
|
121
|
+
h = _StartHarness(monkeypatch)
|
|
122
|
+
monkeypatch.setattr(tts_cli, "_shim_session_state", lambda s, p: (True, "ok"))
|
|
123
|
+
rc = tts_cli.cmd_stt_start(_stt_args())
|
|
124
|
+
assert rc == 0
|
|
125
|
+
assert h.reaped is False and h.launched is False
|
|
126
|
+
assert "already running" in capsys.readouterr().out
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def test_stt_start_reaps_and_relaunches_dead_session(monkeypatch, capsys):
|
|
130
|
+
h = _StartHarness(monkeypatch)
|
|
131
|
+
monkeypatch.setattr(tts_cli, "_shim_session_state", lambda s, p: (False, "failed"))
|
|
132
|
+
rc = tts_cli.cmd_stt_start(_stt_args())
|
|
133
|
+
assert rc == 0
|
|
134
|
+
assert h.reaped is True and h.launched is True
|
|
135
|
+
out = capsys.readouterr().out
|
|
136
|
+
assert "not serving" in out and "already running" not in out
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# === doctor: flag a present-but-dead shim, ignore warming / absent =========
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _patch_doctor(monkeypatch, *, tts="default", stt="default", moonshine=True):
|
|
143
|
+
from agentwire import doctor_cli
|
|
144
|
+
|
|
145
|
+
cfg = SimpleNamespace(
|
|
146
|
+
tts=SimpleNamespace(backend=tts),
|
|
147
|
+
stt=SimpleNamespace(backend=stt),
|
|
148
|
+
)
|
|
149
|
+
# _find_dead_managed_shims imports these lazily from their home modules.
|
|
150
|
+
import agentwire.config as cfg_mod
|
|
151
|
+
import agentwire.core as core_mod
|
|
152
|
+
import agentwire.stt as stt_mod
|
|
153
|
+
|
|
154
|
+
monkeypatch.setattr(cfg_mod, "load_config", lambda: cfg)
|
|
155
|
+
monkeypatch.setattr(core_mod, "get_kokoro_session_name", lambda: "agentwire-kokoro")
|
|
156
|
+
monkeypatch.setattr(core_mod, "get_stt_session_name", lambda: "agentwire-stt")
|
|
157
|
+
monkeypatch.setattr(stt_mod, "moonshine_importable", lambda: moonshine)
|
|
158
|
+
return doctor_cli
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_doctor_flags_dead_kokoro_shim(monkeypatch):
|
|
162
|
+
doctor_cli = _patch_doctor(monkeypatch, stt="none")
|
|
163
|
+
from agentwire import core as core_mod
|
|
164
|
+
|
|
165
|
+
monkeypatch.setattr(core_mod, "tmux_session_exists", lambda s: True)
|
|
166
|
+
monkeypatch.setattr(tts_cli, "_shim_session_state", lambda s, p: (False, None))
|
|
167
|
+
|
|
168
|
+
dead = doctor_cli._find_dead_managed_shims()
|
|
169
|
+
assert len(dead) == 1
|
|
170
|
+
assert dead[0]["label"] == "Kokoro TTS" and dead[0]["port"] == 8102
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_doctor_ignores_warming_shim(monkeypatch):
|
|
174
|
+
doctor_cli = _patch_doctor(monkeypatch, stt="none")
|
|
175
|
+
from agentwire import core as core_mod
|
|
176
|
+
|
|
177
|
+
monkeypatch.setattr(core_mod, "tmux_session_exists", lambda s: True)
|
|
178
|
+
monkeypatch.setattr(tts_cli, "_shim_session_state", lambda s, p: (True, "loading"))
|
|
179
|
+
|
|
180
|
+
assert doctor_cli._find_dead_managed_shims() == []
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def test_doctor_ignores_absent_session(monkeypatch):
|
|
184
|
+
doctor_cli = _patch_doctor(monkeypatch)
|
|
185
|
+
from agentwire import core as core_mod
|
|
186
|
+
|
|
187
|
+
# No tmux session → nothing to self-heal, not a dead shim.
|
|
188
|
+
monkeypatch.setattr(core_mod, "tmux_session_exists", lambda s: False)
|
|
189
|
+
monkeypatch.setattr(tts_cli, "_shim_session_state", lambda s, p: (False, None))
|
|
190
|
+
|
|
191
|
+
assert doctor_cli._find_dead_managed_shims() == []
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def test_doctor_skips_stt_when_moonshine_absent(monkeypatch):
|
|
195
|
+
# STT default tier without Moonshine transcribes in-browser: no shim to flag.
|
|
196
|
+
doctor_cli = _patch_doctor(monkeypatch, tts="custom", moonshine=False)
|
|
197
|
+
from agentwire import core as core_mod
|
|
198
|
+
|
|
199
|
+
monkeypatch.setattr(core_mod, "tmux_session_exists", lambda s: True)
|
|
200
|
+
monkeypatch.setattr(tts_cli, "_shim_session_state", lambda s, p: (False, None))
|
|
201
|
+
|
|
202
|
+
assert doctor_cli._find_dead_managed_shims() == []
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|