agentwire-dev 1.50.1__tar.gz → 1.51.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.51.0/.agentwire.yml.example +14 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/PKG-INFO +5 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/README.md +4 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/inbox.py +226 -35
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_msg.py +35 -5
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/msg_cli.py +42 -3
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/notify_cli.py +0 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/onboarding.py +1 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/pane_cli.py +9 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/project_config.py +21 -12
- agentwire_dev-1.51.0/agentwire/roles/contributor.md +83 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/session_cli.py +28 -13
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/session_ready.py +59 -2
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/system_cli.py +19 -4
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/quickstart.md +10 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/sessions/messaging.md +43 -3
- agentwire_dev-1.51.0/tests/integration/test_send_verified_tmux.py +186 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_inbox.py +207 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_project_config.py +30 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_roles.py +1 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_session_ready.py +38 -0
- agentwire_dev-1.51.0/tests/unit/test_shared_dir_guard.py +44 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/.gitignore +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/AGENTS.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/LICENSE +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/RELEASING.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/SECURITY.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/config.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/core.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/doctor_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_voiceclone.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/mcp_worktree.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles/worktree-session.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/scheduler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/favicon.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/desktop.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/voices/darren.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/voices/default.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/voices/jessica.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/voices/lisa.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/voices/may.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/logo.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/pyproject.toml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/integration/test_worktree_cmd.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.51.0}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# agentwire-dev project config — committed template (#620).
|
|
2
|
+
#
|
|
3
|
+
# This `.agentwire.yml.example` is the default config a fresh clone uses out of
|
|
4
|
+
# the box: `agentwire new` here spawns a contributor session (repo-aware
|
|
5
|
+
# onboarding + issue-filing + fork-based PR coaching).
|
|
6
|
+
#
|
|
7
|
+
# To override locally, create a real `.agentwire.yml` next to this file. It is
|
|
8
|
+
# gitignored, so it stays personal and never ships — and it WINS over this
|
|
9
|
+
# template (a live `.agentwire.yml` is resolved before the `.example` fallback).
|
|
10
|
+
# The repo owner uses this to layer an untracked owner-override role:
|
|
11
|
+
# roles: [contributor, owner-override]
|
|
12
|
+
type: claude-bypass
|
|
13
|
+
roles:
|
|
14
|
+
- contributor
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentwire-dev
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.51.0
|
|
4
4
|
Summary: Multi-session voice web interface for AI coding agents
|
|
5
5
|
Project-URL: Homepage, https://agentwire.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/dotdevdotdev/agentwire-dev
|
|
@@ -345,6 +345,10 @@ agentwire init
|
|
|
345
345
|
# Run
|
|
346
346
|
agentwire portal start
|
|
347
347
|
# Open http://127.0.0.1:8765 in Chrome — your cockpit is live (voice works immediately too)
|
|
348
|
+
|
|
349
|
+
# New here? Start a guided helper session — it walks you through setup,
|
|
350
|
+
# wires up your projects, explains the system, and helps you file issues or fork.
|
|
351
|
+
agentwire dev
|
|
348
352
|
```
|
|
349
353
|
|
|
350
354
|
**Requirements:** Python 3.10+, tmux, ffmpeg, Claude Code
|
|
@@ -82,6 +82,10 @@ agentwire init
|
|
|
82
82
|
# Run
|
|
83
83
|
agentwire portal start
|
|
84
84
|
# Open http://127.0.0.1:8765 in Chrome — your cockpit is live (voice works immediately too)
|
|
85
|
+
|
|
86
|
+
# New here? Start a guided helper session — it walks you through setup,
|
|
87
|
+
# wires up your projects, explains the system, and helps you file issues or fork.
|
|
88
|
+
agentwire dev
|
|
85
89
|
```
|
|
86
90
|
|
|
87
91
|
**Requirements:** Python 3.10+, tmux, ffmpeg, Claude Code
|
|
@@ -114,9 +114,23 @@ class Message:
|
|
|
114
114
|
"ref": self.ref,
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
def short_id(self) -> str:
|
|
118
|
+
"""The 6-char uuid tail of ``id`` (the ``{epoch_ns}-{uuid6}`` suffix)."""
|
|
119
|
+
return self.id.rsplit("-", 1)[-1]
|
|
120
|
+
|
|
117
121
|
def render(self) -> str:
|
|
118
|
-
"""The one-line
|
|
119
|
-
|
|
122
|
+
"""The one-line message injected on delivery (mirrors [NOTIFY from …]).
|
|
123
|
+
|
|
124
|
+
The trailing ``⟨#id6⟩`` token makes every delivered line UNIQUE on the
|
|
125
|
+
recipient's screen (#621). Idempotent-redelivery dedup matches the full
|
|
126
|
+
rendered line on scrollback; without a unique tail a shorter message
|
|
127
|
+
whose text is a prefix of a longer same-sender/kind one (or two
|
|
128
|
+
identical-text report-backs) would substring-collide and be consumed
|
|
129
|
+
without delivery. The token is appended at the END so the prefix-based
|
|
130
|
+
landing checks (``derive_check_fragment`` / ``message_visible``) are
|
|
131
|
+
unchanged.
|
|
132
|
+
"""
|
|
133
|
+
return f"[MSG from {self.sender} · {self.kind}] {self.text} ⟨#{self.short_id()}⟩"
|
|
120
134
|
|
|
121
135
|
|
|
122
136
|
def _now_ms() -> int:
|
|
@@ -293,6 +307,111 @@ def purge_dead(session: "str | None" = None, before_ms: "int | None" = None) ->
|
|
|
293
307
|
return removed
|
|
294
308
|
|
|
295
309
|
|
|
310
|
+
def purge_pending(session: str) -> int:
|
|
311
|
+
"""Drop a session's *pending* (undelivered) messages; return how many.
|
|
312
|
+
|
|
313
|
+
The self-heal escape hatch (#621): when a recipient is wedged into a
|
|
314
|
+
redelivery loop, the only prior recovery was hand-moving JSON files — which
|
|
315
|
+
the recipient's own Bash hook blocks (``rm``). This drops the pending queue
|
|
316
|
+
outright, no empty-box gate, no delivery. Passive (``ingest/``) and dead
|
|
317
|
+
(``dead/``) messages are untouched — this is strictly the active drain queue.
|
|
318
|
+
"""
|
|
319
|
+
# Serialize against an in-flight flush_session via the per-session drain lock
|
|
320
|
+
# so we don't yank a file mid-delivery. If a flush holds the lock we still
|
|
321
|
+
# proceed (the operator wants the queue gone) — unlinking under it is benign
|
|
322
|
+
# because flush copies messages into memory first and its own unlink is
|
|
323
|
+
# missing_ok.
|
|
324
|
+
lock = _acquire_lock(session)
|
|
325
|
+
try:
|
|
326
|
+
paths = pending_files(session)
|
|
327
|
+
removed = 0
|
|
328
|
+
for path in paths:
|
|
329
|
+
try:
|
|
330
|
+
path.unlink()
|
|
331
|
+
removed += 1
|
|
332
|
+
except OSError:
|
|
333
|
+
pass
|
|
334
|
+
if removed:
|
|
335
|
+
_log_event("purged_pending", session=session, count=removed)
|
|
336
|
+
return removed
|
|
337
|
+
finally:
|
|
338
|
+
_release_lock(lock)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def gc_sender(sender: str) -> dict:
|
|
342
|
+
"""Garbage-collect an exited sender's still-pending outbound (#621).
|
|
343
|
+
|
|
344
|
+
Messages live keyed by *recipient*, so when a worktree/session exits nothing
|
|
345
|
+
reaps the report-backs it left undelivered across every inbox — they
|
|
346
|
+
accumulate. This scans all pending queues for that sender and clears them:
|
|
347
|
+
load-bearing kinds (``done``/``request``/``escalation``) are dead-lettered
|
|
348
|
+
(which escalates via the owner-email path so the loss is never silent); the
|
|
349
|
+
rest are dropped. Passive (``ingest``) messages are never auto-delivered, so
|
|
350
|
+
they're left for the recipient to pull. Returns ``{dead, dropped}`` counts.
|
|
351
|
+
"""
|
|
352
|
+
dead = dropped = 0
|
|
353
|
+
if not INBOX_ROOT.exists():
|
|
354
|
+
return {"dead": dead, "dropped": dropped}
|
|
355
|
+
|
|
356
|
+
# Group this sender's pending files by recipient so each inbox is mutated
|
|
357
|
+
# under its per-session drain lock — serializing against an in-flight
|
|
358
|
+
# flush_session. Without it a kill landing mid-delivery could dead-letter +
|
|
359
|
+
# email "never delivered" for a message that WAS just delivered.
|
|
360
|
+
by_recipient: dict[str, list[Path]] = {}
|
|
361
|
+
for path in INBOX_ROOT.rglob("*.json"):
|
|
362
|
+
parts = path.relative_to(INBOX_ROOT).parts
|
|
363
|
+
if any(p in _RESERVED_DIRS for p in parts[:-1]):
|
|
364
|
+
continue # skip dead/ sent/ ingest/ .lock/
|
|
365
|
+
msg = _read_message(path)
|
|
366
|
+
if msg is None or msg.sender != sender:
|
|
367
|
+
continue
|
|
368
|
+
recipient = "/".join(parts[:-1])
|
|
369
|
+
if recipient:
|
|
370
|
+
by_recipient.setdefault(recipient, []).append(path)
|
|
371
|
+
|
|
372
|
+
for recipient, paths in by_recipient.items():
|
|
373
|
+
lock = _acquire_lock(recipient)
|
|
374
|
+
if lock is None:
|
|
375
|
+
# A flush is draining this inbox right now — its messages are being
|
|
376
|
+
# delivered, not lost. Skip GC for this recipient this round.
|
|
377
|
+
continue
|
|
378
|
+
try:
|
|
379
|
+
for path in paths:
|
|
380
|
+
if not path.exists():
|
|
381
|
+
continue # delivered + unlinked just before we locked
|
|
382
|
+
msg = _read_message(path)
|
|
383
|
+
if msg is None or msg.sender != sender:
|
|
384
|
+
continue
|
|
385
|
+
if msg.kind in ESCALATE_KINDS:
|
|
386
|
+
msg.dead_ts = _now_ms()
|
|
387
|
+
msg.reason = "sender_exited"
|
|
388
|
+
target = dead_dir(msg.to or "unknown") / path.name
|
|
389
|
+
try:
|
|
390
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
391
|
+
_write_message(target, msg)
|
|
392
|
+
path.unlink(missing_ok=True)
|
|
393
|
+
_log_event(
|
|
394
|
+
"dead_letter", id=msg.id, to=msg.to, kind=msg.kind,
|
|
395
|
+
attempts=msg.attempts, reason="sender_exited",
|
|
396
|
+
)
|
|
397
|
+
dead += 1
|
|
398
|
+
_escalate_dead_letter(msg, "sender_exited")
|
|
399
|
+
except OSError:
|
|
400
|
+
pass
|
|
401
|
+
else:
|
|
402
|
+
try:
|
|
403
|
+
path.unlink()
|
|
404
|
+
dropped += 1
|
|
405
|
+
except OSError:
|
|
406
|
+
pass
|
|
407
|
+
finally:
|
|
408
|
+
_release_lock(lock)
|
|
409
|
+
|
|
410
|
+
if dead or dropped:
|
|
411
|
+
_log_event("gc_sender", sender=sender, dead=dead, dropped=dropped)
|
|
412
|
+
return {"dead": dead, "dropped": dropped}
|
|
413
|
+
|
|
414
|
+
|
|
296
415
|
# =============================================================================
|
|
297
416
|
# Enqueue + broadcast
|
|
298
417
|
# =============================================================================
|
|
@@ -494,12 +613,52 @@ def _bump_attempts(messages: list[Message], reason: str = "") -> int:
|
|
|
494
613
|
return dead
|
|
495
614
|
|
|
496
615
|
|
|
497
|
-
def
|
|
616
|
+
def _dedup_landed(session: str, messages: list[Message]) -> list[Message]:
|
|
617
|
+
"""Consume (unlink) every message whose render() is already on scrollback.
|
|
618
|
+
|
|
619
|
+
The load-bearing #621 fix. ``safe_deliver`` confirms submission by polling
|
|
620
|
+
the input box back to empty; under host load that confirm false-negatives
|
|
621
|
+
even though the paste *landed* and the recipient saw it. Retaining a landed
|
|
622
|
+
message re-injects it on every idle tick — forever. So before (and after) a
|
|
623
|
+
paste we check the recipient's scrollback per-message: any message whose own
|
|
624
|
+
first-line fragment is visible has demonstrably landed → unlink it. Only
|
|
625
|
+
truly-absent messages stay pending.
|
|
626
|
+
|
|
627
|
+
Per-message keying (not the coalesced blob) so a partial landing consumes
|
|
628
|
+
exactly the visible subset. A strict fragment check (never the generic
|
|
629
|
+
``"[Pasted text"`` placeholder fallback) so a stray placeholder can't mark
|
|
630
|
+
every message delivered. A message that scrolled past the 200-line window
|
|
631
|
+
reads as not-visible → kept (safe direction: retry, never silent-drop).
|
|
632
|
+
"""
|
|
633
|
+
from .session_ready import message_on_scrollback, scrollback
|
|
634
|
+
|
|
635
|
+
capture = scrollback(session, 0)
|
|
636
|
+
consumed: list[Message] = []
|
|
637
|
+
for msg in messages:
|
|
638
|
+
if msg.path is None:
|
|
639
|
+
continue
|
|
640
|
+
if message_on_scrollback(capture, msg.render()):
|
|
641
|
+
msg.path.unlink(missing_ok=True)
|
|
642
|
+
consumed.append(msg)
|
|
643
|
+
if consumed:
|
|
644
|
+
_log_event(
|
|
645
|
+
"delivered_dedup", to=session, count=len(consumed),
|
|
646
|
+
kinds=[m.kind for m in consumed],
|
|
647
|
+
)
|
|
648
|
+
return consumed
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def flush_session(session: str, force: bool = False) -> dict:
|
|
498
652
|
"""Attempt to drain one session's inbox now.
|
|
499
653
|
|
|
500
654
|
Delivers oldest-first, coalescing all queued messages into a single paste
|
|
501
655
|
(one submit) when the box is empty. On any refusal the messages stay put,
|
|
502
656
|
their ``attempts`` bump, and over the cap they dead-letter. Never raises.
|
|
657
|
+
|
|
658
|
+
*force* (the ``msg flush --force`` escape hatch) bypasses the empty-box /
|
|
659
|
+
busy gate and pastes regardless — for an operator un-wedging a stuck queue,
|
|
660
|
+
accepting that it may land mid-draft. The ``safe_deliver`` safety guards
|
|
661
|
+
(gone / parked / non-agent / live-dialog) are never bypassed.
|
|
503
662
|
"""
|
|
504
663
|
from . import prompt_router
|
|
505
664
|
|
|
@@ -511,42 +670,74 @@ def flush_session(session: str) -> dict:
|
|
|
511
670
|
if not messages:
|
|
512
671
|
return {"session": session, "delivered": 0, "deferred": False, "reason": "empty"}
|
|
513
672
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
#
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
673
|
+
pre_consumed = 0
|
|
674
|
+
if not force:
|
|
675
|
+
# Collision guard FIRST (cheap, and refuses dialogs/busy too via None).
|
|
676
|
+
# But first: a prior tick may have LANDED these and false-negatived the
|
|
677
|
+
# confirm (#621). If they're already on scrollback, consume them now
|
|
678
|
+
# instead of waiting for the box to free up to re-paste a duplicate.
|
|
679
|
+
consumed = _dedup_landed(session, messages)
|
|
680
|
+
if consumed:
|
|
681
|
+
pre_consumed = len(consumed)
|
|
682
|
+
messages = [m for m in messages if m.path is not None and m.path.exists()]
|
|
683
|
+
if not messages:
|
|
684
|
+
return {
|
|
685
|
+
"session": session, "delivered": pre_consumed,
|
|
686
|
+
"deferred": False, "reason": "delivered",
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
visible = prompt_router.capture(session, 0)
|
|
690
|
+
box_content = prompt_router.input_box_content(visible)
|
|
691
|
+
|
|
692
|
+
if box_content is None:
|
|
693
|
+
# Target is busy (input box not located). Defer.
|
|
694
|
+
dead = _bump_attempts(messages, "target_busy")
|
|
695
|
+
_log_event("deferred", to=session, count=len(messages), reason="target_busy")
|
|
696
|
+
return {
|
|
697
|
+
"session": session, "delivered": pre_consumed, "deferred": True,
|
|
698
|
+
"reason": "target_busy", "dead": dead,
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if box_content != "":
|
|
702
|
+
# Box is not empty. We never bypass this to protect human drafts. But
|
|
703
|
+
# the "queued messages" placeholder is a BUSY signal, not a draft:
|
|
704
|
+
# defer WITHOUT penalty (like target_busy) so a generating-with-queued
|
|
705
|
+
# session doesn't burn report-backs toward dead-letter. Either way we
|
|
706
|
+
# never paste — only the penalty decision differs.
|
|
707
|
+
placeholder = prompt_router.is_queued_placeholder(box_content)
|
|
708
|
+
reason = "queued_placeholder" if placeholder else "box_not_empty"
|
|
709
|
+
dead = _bump_attempts(messages, reason)
|
|
710
|
+
_log_event("deferred", to=session, count=len(messages), reason=reason)
|
|
711
|
+
return {
|
|
712
|
+
"session": session, "delivered": pre_consumed, "deferred": True,
|
|
713
|
+
"reason": reason, "dead": dead,
|
|
714
|
+
}
|
|
541
715
|
|
|
542
716
|
rendered = "\n".join(m.render() for m in messages)
|
|
543
717
|
delivered, reason = prompt_router.safe_deliver(session, 0, rendered)
|
|
544
718
|
if not delivered:
|
|
545
|
-
|
|
546
|
-
|
|
719
|
+
# delivery_unverified means the box-cleared confirm failed — but the
|
|
720
|
+
# paste may have LANDED. Consume any message now visible on scrollback
|
|
721
|
+
# (idempotent delivery) so a false-negative can't cause re-injection.
|
|
722
|
+
# Other reasons (gone/parked/non-agent/dialog) never pasted, so there's
|
|
723
|
+
# nothing to dedup.
|
|
724
|
+
consumed = (
|
|
725
|
+
_dedup_landed(session, messages)
|
|
726
|
+
if reason == "delivery_unverified"
|
|
727
|
+
else []
|
|
728
|
+
)
|
|
729
|
+
consumed_ids = {m.id for m in consumed}
|
|
730
|
+
remaining = [m for m in messages if m.id not in consumed_ids]
|
|
731
|
+
if not remaining:
|
|
732
|
+
return {
|
|
733
|
+
"session": session, "delivered": pre_consumed + len(consumed),
|
|
734
|
+
"deferred": False, "reason": "delivered",
|
|
735
|
+
}
|
|
736
|
+
dead = _bump_attempts(remaining, reason)
|
|
737
|
+
_log_event("deferred", to=session, count=len(remaining), reason=reason)
|
|
547
738
|
return {
|
|
548
|
-
"session": session, "delivered":
|
|
549
|
-
"reason": reason, "dead": dead,
|
|
739
|
+
"session": session, "delivered": pre_consumed + len(consumed),
|
|
740
|
+
"deferred": True, "reason": reason, "dead": dead,
|
|
550
741
|
}
|
|
551
742
|
|
|
552
743
|
for msg in messages:
|
|
@@ -557,7 +748,7 @@ def flush_session(session: str) -> dict:
|
|
|
557
748
|
kinds=[m.kind for m in messages],
|
|
558
749
|
)
|
|
559
750
|
return {
|
|
560
|
-
"session": session, "delivered": len(messages),
|
|
751
|
+
"session": session, "delivered": pre_consumed + len(messages),
|
|
561
752
|
"deferred": False, "reason": "delivered",
|
|
562
753
|
}
|
|
563
754
|
except Exception as exc: # draining must never break the watchdog
|
|
@@ -184,16 +184,44 @@ def msg_dead(session: str | None = None) -> str:
|
|
|
184
184
|
|
|
185
185
|
|
|
186
186
|
@mcp.tool()
|
|
187
|
-
def
|
|
188
|
-
"""
|
|
187
|
+
def msg_purge(session: str | None = None) -> str:
|
|
188
|
+
"""Drop a session's PENDING polite messages — the self-heal escape hatch.
|
|
189
|
+
|
|
190
|
+
Use this to un-wedge a recipient stuck re-seeing the same messages (or to
|
|
191
|
+
clear an inbox you know is stale). It drops the active drain queue outright —
|
|
192
|
+
no empty-box gate, no delivery. Dead-lettered (`msg_dead`) and passive
|
|
193
|
+
`ingest` messages are untouched; this is strictly the pending queue.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
session: Session whose pending queue to drop (default: the caller).
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
How many pending messages were dropped.
|
|
200
|
+
"""
|
|
201
|
+
caller = session or get_caller_session()
|
|
202
|
+
args = ["msg", "purge"]
|
|
203
|
+
if caller:
|
|
204
|
+
args.append(caller)
|
|
205
|
+
data = run_agentwire_cmd(args)
|
|
206
|
+
if not data.get("success"):
|
|
207
|
+
return f"Failed to purge: {data.get('error', 'Unknown error')}"
|
|
208
|
+
return f"Purged {data.get('purged', 0)} pending message(s) from {data.get('session')}."
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@mcp.tool()
|
|
212
|
+
def msg_flush(session: str | None = None, force: bool = False) -> str:
|
|
213
|
+
"""Attempt a polite-message drain now (gated on an empty box + safe target).
|
|
189
214
|
|
|
190
215
|
Messages drain automatically every ≤60s via the watchdog; use this to force a
|
|
191
|
-
pass without waiting.
|
|
192
|
-
non-agent recipient is still deferred. Passive `ingest` messages
|
|
193
|
-
drained (pull them with msg_pull).
|
|
216
|
+
pass without waiting. By default it does NOT bypass the safety gates — a
|
|
217
|
+
busy/parked/non-agent recipient is still deferred. Passive `ingest` messages
|
|
218
|
+
are never drained (pull them with msg_pull).
|
|
194
219
|
|
|
195
220
|
Args:
|
|
196
221
|
session: Session to flush (default: all sessions with queued messages).
|
|
222
|
+
force: Bypass the empty-box gate and paste anyway (requires `session`;
|
|
223
|
+
may land mid-draft). For un-wedging a stuck queue. Safety guards
|
|
224
|
+
(gone/parked/non-agent/live-dialog) are never bypassed.
|
|
197
225
|
|
|
198
226
|
Returns:
|
|
199
227
|
What was delivered or deferred.
|
|
@@ -201,6 +229,8 @@ def msg_flush(session: str | None = None) -> str:
|
|
|
201
229
|
args = ["msg", "flush"]
|
|
202
230
|
if session:
|
|
203
231
|
args += ["-s", session]
|
|
232
|
+
if force:
|
|
233
|
+
args.append("--force")
|
|
204
234
|
data = run_agentwire_cmd(args)
|
|
205
235
|
if not data.get("success"):
|
|
206
236
|
return f"Failed to flush: {data.get('error', 'Unknown error')}"
|
|
@@ -244,11 +244,35 @@ def cmd_msg_dead(args) -> int:
|
|
|
244
244
|
return 0
|
|
245
245
|
|
|
246
246
|
|
|
247
|
+
def cmd_msg_purge(args) -> int:
|
|
248
|
+
"""Drop a session's pending (undelivered) messages — the self-heal escape hatch."""
|
|
249
|
+
session = getattr(args, "session", None) or _current_session()
|
|
250
|
+
if not session:
|
|
251
|
+
print("No session (use the session name, or run inside one)")
|
|
252
|
+
if getattr(args, "json", False):
|
|
253
|
+
print(json.dumps({"success": False, "error": "no session"}))
|
|
254
|
+
return 1
|
|
255
|
+
removed = inbox.purge_pending(session)
|
|
256
|
+
if getattr(args, "json", False):
|
|
257
|
+
print(json.dumps({"success": True, "session": session, "purged": removed}))
|
|
258
|
+
return 0
|
|
259
|
+
print(f"Purged {removed} pending message(s) from {session}")
|
|
260
|
+
return 0
|
|
261
|
+
|
|
262
|
+
|
|
247
263
|
def cmd_msg_flush(args) -> int:
|
|
248
|
-
"""Attempt a drain now (
|
|
264
|
+
"""Attempt a drain now (gated on an empty box + safe target unless --force)."""
|
|
249
265
|
session = getattr(args, "session", None)
|
|
266
|
+
force = getattr(args, "force", False)
|
|
267
|
+
if force and not session:
|
|
268
|
+
msg = "--force requires -s <session> (refuses to force-drain every inbox)"
|
|
269
|
+
if getattr(args, "json", False):
|
|
270
|
+
print(json.dumps({"success": False, "error": msg}))
|
|
271
|
+
else:
|
|
272
|
+
print(msg)
|
|
273
|
+
return 1
|
|
250
274
|
if session:
|
|
251
|
-
result = inbox.flush_session(session)
|
|
275
|
+
result = inbox.flush_session(session, force=force)
|
|
252
276
|
payload = {"success": True, **result}
|
|
253
277
|
else:
|
|
254
278
|
result = inbox.tick()
|
|
@@ -340,10 +364,25 @@ def register_msg_parser(subparsers) -> None:
|
|
|
340
364
|
dead_parser.add_argument("--json", action="store_true", help="Output JSON")
|
|
341
365
|
dead_parser.set_defaults(func=cmd_msg_dead)
|
|
342
366
|
|
|
343
|
-
|
|
367
|
+
purge_parser = msg_sub.add_parser(
|
|
368
|
+
"purge",
|
|
369
|
+
help="Drop a session's pending messages (self-heal a wedged inbox)",
|
|
370
|
+
)
|
|
371
|
+
purge_parser.add_argument(
|
|
372
|
+
"session", nargs="?", default=None,
|
|
373
|
+
help="Session to purge (default: current)",
|
|
374
|
+
)
|
|
375
|
+
purge_parser.add_argument("--json", action="store_true", help="Output JSON")
|
|
376
|
+
purge_parser.set_defaults(func=cmd_msg_purge)
|
|
377
|
+
|
|
378
|
+
flush_parser = msg_sub.add_parser("flush", help="Attempt a drain now (gated unless --force)")
|
|
344
379
|
flush_parser.add_argument(
|
|
345
380
|
"-s", "--session", default=None, help="Session to flush (default: all)"
|
|
346
381
|
)
|
|
382
|
+
flush_parser.add_argument(
|
|
383
|
+
"--force", action="store_true",
|
|
384
|
+
help="Bypass the empty-box gate and paste anyway (requires -s; may land mid-draft)",
|
|
385
|
+
)
|
|
347
386
|
flush_parser.add_argument("--json", action="store_true", help="Output JSON")
|
|
348
387
|
flush_parser.set_defaults(func=cmd_msg_flush)
|
|
349
388
|
|
|
@@ -470,6 +470,7 @@ services:
|
|
|
470
470
|
print(f"{BOLD}Next steps:{RESET}")
|
|
471
471
|
print(f" 1. {CYAN}agentwire portal start{RESET}")
|
|
472
472
|
print(f" 2. Open {CYAN}{portal_open_url}{RESET} in Chrome — voice works immediately")
|
|
473
|
+
print(f" 3. {CYAN}agentwire dev{RESET} — a helper session that walks you through setup, wires up your projects, and explains the system")
|
|
473
474
|
print()
|
|
474
475
|
print_info("Run 'agentwire init --assisted' to configure TTS/STT with Claude's help.")
|
|
475
476
|
return 0
|
|
@@ -722,6 +722,15 @@ def cmd_kill(args) -> int:
|
|
|
722
722
|
except OSError:
|
|
723
723
|
pass
|
|
724
724
|
|
|
725
|
+
# GC this sender's still-pending outbound across every recipient inbox (#621)
|
|
726
|
+
# so report-backs it left undelivered don't accumulate. Load-bearing kinds
|
|
727
|
+
# dead-letter (and escalate via owner email); the rest are dropped.
|
|
728
|
+
try:
|
|
729
|
+
from . import inbox
|
|
730
|
+
inbox.gc_sender(session)
|
|
731
|
+
except Exception:
|
|
732
|
+
pass
|
|
733
|
+
|
|
725
734
|
_notify_portal_sessions_changed()
|
|
726
735
|
|
|
727
736
|
if json_mode:
|
|
@@ -193,13 +193,19 @@ class ProjectConfig:
|
|
|
193
193
|
|
|
194
194
|
|
|
195
195
|
def find_project_config(start_path: Optional[Path] = None) -> Optional[Path]:
|
|
196
|
-
"""Find
|
|
196
|
+
"""Find project config by walking up from start_path.
|
|
197
|
+
|
|
198
|
+
At each directory level, a local untracked ``.agentwire.yml`` wins over a
|
|
199
|
+
committed ``.agentwire.yml.example`` template. The ``.example`` fallback lets
|
|
200
|
+
a repo (e.g. agentwire-dev itself) ship a sensible default config that a
|
|
201
|
+
fresh clone uses out of the box, while the owner's personal, gitignored
|
|
202
|
+
``.agentwire.yml`` overrides it when present. See #620.
|
|
197
203
|
|
|
198
204
|
Args:
|
|
199
205
|
start_path: Directory to start searching from. Defaults to cwd.
|
|
200
206
|
|
|
201
207
|
Returns:
|
|
202
|
-
Path to
|
|
208
|
+
Path to the resolved config file if found, None otherwise.
|
|
203
209
|
"""
|
|
204
210
|
if start_path is None:
|
|
205
211
|
start_path = Path.cwd()
|
|
@@ -207,17 +213,17 @@ def find_project_config(start_path: Optional[Path] = None) -> Optional[Path]:
|
|
|
207
213
|
start_path = Path(start_path).resolve()
|
|
208
214
|
|
|
209
215
|
current = start_path
|
|
210
|
-
while
|
|
211
|
-
|
|
212
|
-
if
|
|
213
|
-
return
|
|
216
|
+
while True:
|
|
217
|
+
live = current / ".agentwire.yml"
|
|
218
|
+
if live.exists():
|
|
219
|
+
return live
|
|
220
|
+
example = current / ".agentwire.yml.example"
|
|
221
|
+
if example.exists():
|
|
222
|
+
return example
|
|
223
|
+
if current == current.parent:
|
|
224
|
+
break
|
|
214
225
|
current = current.parent
|
|
215
226
|
|
|
216
|
-
# Check root
|
|
217
|
-
config_file = current / ".agentwire.yml"
|
|
218
|
-
if config_file.exists():
|
|
219
|
-
return config_file
|
|
220
|
-
|
|
221
227
|
return None
|
|
222
228
|
|
|
223
229
|
|
|
@@ -234,7 +240,10 @@ def load_project_config(path: Optional[Path] = None) -> Optional[ProjectConfig]:
|
|
|
234
240
|
if path is None:
|
|
235
241
|
config_path = find_project_config()
|
|
236
242
|
elif path.is_dir():
|
|
237
|
-
|
|
243
|
+
# Local .agentwire.yml wins over a committed .agentwire.yml.example (#620).
|
|
244
|
+
live = path / ".agentwire.yml"
|
|
245
|
+
example = path / ".agentwire.yml.example"
|
|
246
|
+
config_path = live if live.exists() else example
|
|
238
247
|
else:
|
|
239
248
|
config_path = path
|
|
240
249
|
|