agentwire-dev 1.50.1__tar.gz → 1.52.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.52.0/.agentwire.yml.example +14 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.gitignore +3 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/PKG-INFO +5 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/README.md +4 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/agents/tmux.py +3 -3
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/config.py +7 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/inbox.py +249 -37
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/listen.py +67 -26
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_msg.py +35 -5
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/msg_cli.py +42 -3
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/notify_cli.py +0 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/onboarding.py +1 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/pane_cli.py +9 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/project_config.py +21 -12
- agentwire_dev-1.52.0/agentwire/roles/contributor.md +83 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/voice.py +14 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/security.py +165 -4
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/send_cli.py +3 -3
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/server.py +36 -19
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/session_cli.py +28 -13
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/session_ready.py +59 -2
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/artifact-window.js +21 -24
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/stt/__init__.py +19 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/system_cli.py +19 -4
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/engines/kokoro.py +29 -6
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/voiceclone.py +64 -18
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/communication/hammerspoon.md +1 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/quickstart.md +10 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/sessions/messaging.md +43 -3
- agentwire_dev-1.52.0/tests/integration/test_send_verified_tmux.py +186 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_inbox.py +255 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_portal_api.py +138 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_project_config.py +30 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_roles.py +1 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_security.py +107 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_session_ready.py +38 -0
- agentwire_dev-1.52.0/tests/unit/test_shared_dir_guard.py +44 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_stt_backend.py +21 -1
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_tts_local.py +31 -3
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/AGENTS.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/LICENSE +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/RELEASING.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/SECURITY.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/core.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/doctor_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_voiceclone.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/mcp_worktree.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/prompt_router.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles/worktree-session.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/scheduler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/favicon.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/desktop.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/voices/darren.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/voices/default.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/voices/jessica.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/voices/lisa.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/voices/may.wav +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/logo.png +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/pyproject.toml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/conftest.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/integration/test_worktree_cmd.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_cli_commands.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_msg_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.50.1 → agentwire_dev-1.52.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.52.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
|
|
@@ -236,11 +236,11 @@ class TmuxAgent(AgentBackend):
|
|
|
236
236
|
# Use base64 + load-buffer on remote to avoid PTY flooding
|
|
237
237
|
import base64
|
|
238
238
|
encoded = base64.b64encode(text.encode()).decode()
|
|
239
|
+
# Pipe straight into the tmux buffer — no on-disk temp that could
|
|
240
|
+
# expose message content or be pre-planted on the remote host
|
|
239
241
|
cmd = (
|
|
240
|
-
f"echo {shlex.quote(encoded)} | base64 -d
|
|
241
|
-
f"tmux load-buffer /tmp/aw-send-$$.txt && "
|
|
242
|
+
f"echo {shlex.quote(encoded)} | base64 -d | tmux load-buffer - && "
|
|
242
243
|
f"tmux paste-buffer -t {shlex.quote(session_name)} && "
|
|
243
|
-
f"rm -f /tmp/aw-send-$$.txt && "
|
|
244
244
|
f"sleep 0.2 && "
|
|
245
245
|
f"tmux send-keys -t {shlex.quote(session_name)} Enter"
|
|
246
246
|
)
|
|
@@ -74,6 +74,12 @@ class ServerConfig:
|
|
|
74
74
|
# bearer token then transits in cleartext. Required to start a non-loopback
|
|
75
75
|
# bind without TLS — the BYO-tunnel case where the tunnel terminates TLS.
|
|
76
76
|
allow_insecure: bool = False
|
|
77
|
+
# Emit HTTP Strict-Transport-Security. Leave OFF for self-signed /
|
|
78
|
+
# localhost / LAN — HSTS + a self-signed cert locks the browser out of the
|
|
79
|
+
# portal if the cert ever rotates. Enable ONLY when serving a real
|
|
80
|
+
# (CA-signed) cert directly. Behind Cloudflare Tunnel / a reverse proxy,
|
|
81
|
+
# set HSTS at the edge instead.
|
|
82
|
+
hsts: bool = False
|
|
77
83
|
|
|
78
84
|
|
|
79
85
|
@dataclass
|
|
@@ -590,6 +596,7 @@ def _dict_to_config(data: dict) -> Config:
|
|
|
590
596
|
# "" (explicit disable) must survive — don't collapse it to None.
|
|
591
597
|
auth_token=server_data.get("auth_token"),
|
|
592
598
|
allow_insecure=bool(server_data.get("allow_insecure", False)),
|
|
599
|
+
hsts=bool(server_data.get("hsts", False)),
|
|
593
600
|
)
|
|
594
601
|
|
|
595
602
|
# Projects
|
|
@@ -30,6 +30,7 @@ from __future__ import annotations
|
|
|
30
30
|
import errno
|
|
31
31
|
import json
|
|
32
32
|
import os
|
|
33
|
+
import re
|
|
33
34
|
import time
|
|
34
35
|
import uuid
|
|
35
36
|
from dataclasses import dataclass
|
|
@@ -114,9 +115,23 @@ class Message:
|
|
|
114
115
|
"ref": self.ref,
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
def short_id(self) -> str:
|
|
119
|
+
"""The 6-char uuid tail of ``id`` (the ``{epoch_ns}-{uuid6}`` suffix)."""
|
|
120
|
+
return self.id.rsplit("-", 1)[-1]
|
|
121
|
+
|
|
117
122
|
def render(self) -> str:
|
|
118
|
-
"""The one-line
|
|
119
|
-
|
|
123
|
+
"""The one-line message injected on delivery (mirrors [NOTIFY from …]).
|
|
124
|
+
|
|
125
|
+
The trailing ``⟨#id6⟩`` token makes every delivered line UNIQUE on the
|
|
126
|
+
recipient's screen (#621). Idempotent-redelivery dedup matches the full
|
|
127
|
+
rendered line on scrollback; without a unique tail a shorter message
|
|
128
|
+
whose text is a prefix of a longer same-sender/kind one (or two
|
|
129
|
+
identical-text report-backs) would substring-collide and be consumed
|
|
130
|
+
without delivery. The token is appended at the END so the prefix-based
|
|
131
|
+
landing checks (``derive_check_fragment`` / ``message_visible``) are
|
|
132
|
+
unchanged.
|
|
133
|
+
"""
|
|
134
|
+
return f"[MSG from {self.sender} · {self.kind}] {self.text} ⟨#{self.short_id()}⟩"
|
|
120
135
|
|
|
121
136
|
|
|
122
137
|
def _now_ms() -> int:
|
|
@@ -134,8 +149,28 @@ def _short_uuid() -> str:
|
|
|
134
149
|
return uuid.uuid4().hex[:6]
|
|
135
150
|
|
|
136
151
|
|
|
152
|
+
# Session names are agent-controlled (msg_send `to`), so they must never be
|
|
153
|
+
# able to path-traverse out of INBOX_ROOT. Worktree session names legitimately
|
|
154
|
+
# contain `/` (they nest one directory level per segment — see module
|
|
155
|
+
# docstring), so segments are validated individually; `..`, absolute paths,
|
|
156
|
+
# and empty names/segments are rejected.
|
|
157
|
+
_SESSION_RE = re.compile(r"^[A-Za-z0-9._@-]+(?:/[A-Za-z0-9._@-]+)*$")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _validate_session(session: str) -> str:
|
|
161
|
+
if not session or not _SESSION_RE.match(session) or ".." in session.split("/"):
|
|
162
|
+
raise ValueError(f"invalid session name: {session!r}")
|
|
163
|
+
return session
|
|
164
|
+
|
|
165
|
+
|
|
137
166
|
def session_dir(session: str) -> Path:
|
|
138
|
-
|
|
167
|
+
_validate_session(session)
|
|
168
|
+
path = INBOX_ROOT / session
|
|
169
|
+
# Belt and braces: the regex already forbids traversal, but confine the
|
|
170
|
+
# result to INBOX_ROOT so a validator regression can't escape it.
|
|
171
|
+
if not path.resolve().is_relative_to(INBOX_ROOT.resolve()):
|
|
172
|
+
raise ValueError(f"invalid session name: {session!r}")
|
|
173
|
+
return path
|
|
139
174
|
|
|
140
175
|
|
|
141
176
|
def dead_dir(session: str) -> Path:
|
|
@@ -293,6 +328,111 @@ def purge_dead(session: "str | None" = None, before_ms: "int | None" = None) ->
|
|
|
293
328
|
return removed
|
|
294
329
|
|
|
295
330
|
|
|
331
|
+
def purge_pending(session: str) -> int:
|
|
332
|
+
"""Drop a session's *pending* (undelivered) messages; return how many.
|
|
333
|
+
|
|
334
|
+
The self-heal escape hatch (#621): when a recipient is wedged into a
|
|
335
|
+
redelivery loop, the only prior recovery was hand-moving JSON files — which
|
|
336
|
+
the recipient's own Bash hook blocks (``rm``). This drops the pending queue
|
|
337
|
+
outright, no empty-box gate, no delivery. Passive (``ingest/``) and dead
|
|
338
|
+
(``dead/``) messages are untouched — this is strictly the active drain queue.
|
|
339
|
+
"""
|
|
340
|
+
# Serialize against an in-flight flush_session via the per-session drain lock
|
|
341
|
+
# so we don't yank a file mid-delivery. If a flush holds the lock we still
|
|
342
|
+
# proceed (the operator wants the queue gone) — unlinking under it is benign
|
|
343
|
+
# because flush copies messages into memory first and its own unlink is
|
|
344
|
+
# missing_ok.
|
|
345
|
+
lock = _acquire_lock(session)
|
|
346
|
+
try:
|
|
347
|
+
paths = pending_files(session)
|
|
348
|
+
removed = 0
|
|
349
|
+
for path in paths:
|
|
350
|
+
try:
|
|
351
|
+
path.unlink()
|
|
352
|
+
removed += 1
|
|
353
|
+
except OSError:
|
|
354
|
+
pass
|
|
355
|
+
if removed:
|
|
356
|
+
_log_event("purged_pending", session=session, count=removed)
|
|
357
|
+
return removed
|
|
358
|
+
finally:
|
|
359
|
+
_release_lock(lock)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def gc_sender(sender: str) -> dict:
|
|
363
|
+
"""Garbage-collect an exited sender's still-pending outbound (#621).
|
|
364
|
+
|
|
365
|
+
Messages live keyed by *recipient*, so when a worktree/session exits nothing
|
|
366
|
+
reaps the report-backs it left undelivered across every inbox — they
|
|
367
|
+
accumulate. This scans all pending queues for that sender and clears them:
|
|
368
|
+
load-bearing kinds (``done``/``request``/``escalation``) are dead-lettered
|
|
369
|
+
(which escalates via the owner-email path so the loss is never silent); the
|
|
370
|
+
rest are dropped. Passive (``ingest``) messages are never auto-delivered, so
|
|
371
|
+
they're left for the recipient to pull. Returns ``{dead, dropped}`` counts.
|
|
372
|
+
"""
|
|
373
|
+
dead = dropped = 0
|
|
374
|
+
if not INBOX_ROOT.exists():
|
|
375
|
+
return {"dead": dead, "dropped": dropped}
|
|
376
|
+
|
|
377
|
+
# Group this sender's pending files by recipient so each inbox is mutated
|
|
378
|
+
# under its per-session drain lock — serializing against an in-flight
|
|
379
|
+
# flush_session. Without it a kill landing mid-delivery could dead-letter +
|
|
380
|
+
# email "never delivered" for a message that WAS just delivered.
|
|
381
|
+
by_recipient: dict[str, list[Path]] = {}
|
|
382
|
+
for path in INBOX_ROOT.rglob("*.json"):
|
|
383
|
+
parts = path.relative_to(INBOX_ROOT).parts
|
|
384
|
+
if any(p in _RESERVED_DIRS for p in parts[:-1]):
|
|
385
|
+
continue # skip dead/ sent/ ingest/ .lock/
|
|
386
|
+
msg = _read_message(path)
|
|
387
|
+
if msg is None or msg.sender != sender:
|
|
388
|
+
continue
|
|
389
|
+
recipient = "/".join(parts[:-1])
|
|
390
|
+
if recipient:
|
|
391
|
+
by_recipient.setdefault(recipient, []).append(path)
|
|
392
|
+
|
|
393
|
+
for recipient, paths in by_recipient.items():
|
|
394
|
+
lock = _acquire_lock(recipient)
|
|
395
|
+
if lock is None:
|
|
396
|
+
# A flush is draining this inbox right now — its messages are being
|
|
397
|
+
# delivered, not lost. Skip GC for this recipient this round.
|
|
398
|
+
continue
|
|
399
|
+
try:
|
|
400
|
+
for path in paths:
|
|
401
|
+
if not path.exists():
|
|
402
|
+
continue # delivered + unlinked just before we locked
|
|
403
|
+
msg = _read_message(path)
|
|
404
|
+
if msg is None or msg.sender != sender:
|
|
405
|
+
continue
|
|
406
|
+
if msg.kind in ESCALATE_KINDS:
|
|
407
|
+
msg.dead_ts = _now_ms()
|
|
408
|
+
msg.reason = "sender_exited"
|
|
409
|
+
target = dead_dir(msg.to or "unknown") / path.name
|
|
410
|
+
try:
|
|
411
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
412
|
+
_write_message(target, msg)
|
|
413
|
+
path.unlink(missing_ok=True)
|
|
414
|
+
_log_event(
|
|
415
|
+
"dead_letter", id=msg.id, to=msg.to, kind=msg.kind,
|
|
416
|
+
attempts=msg.attempts, reason="sender_exited",
|
|
417
|
+
)
|
|
418
|
+
dead += 1
|
|
419
|
+
_escalate_dead_letter(msg, "sender_exited")
|
|
420
|
+
except OSError:
|
|
421
|
+
pass
|
|
422
|
+
else:
|
|
423
|
+
try:
|
|
424
|
+
path.unlink()
|
|
425
|
+
dropped += 1
|
|
426
|
+
except OSError:
|
|
427
|
+
pass
|
|
428
|
+
finally:
|
|
429
|
+
_release_lock(lock)
|
|
430
|
+
|
|
431
|
+
if dead or dropped:
|
|
432
|
+
_log_event("gc_sender", sender=sender, dead=dead, dropped=dropped)
|
|
433
|
+
return {"dead": dead, "dropped": dropped}
|
|
434
|
+
|
|
435
|
+
|
|
296
436
|
# =============================================================================
|
|
297
437
|
# Enqueue + broadcast
|
|
298
438
|
# =============================================================================
|
|
@@ -321,7 +461,7 @@ def resolve_targets(to: str, sender: "str | None") -> list[str]:
|
|
|
321
461
|
"""
|
|
322
462
|
if to == BROADCAST_TOKEN:
|
|
323
463
|
return [s for s in _live_agent_sessions() if s != sender]
|
|
324
|
-
return [to]
|
|
464
|
+
return [_validate_session(to)]
|
|
325
465
|
|
|
326
466
|
|
|
327
467
|
def enqueue(
|
|
@@ -494,12 +634,52 @@ def _bump_attempts(messages: list[Message], reason: str = "") -> int:
|
|
|
494
634
|
return dead
|
|
495
635
|
|
|
496
636
|
|
|
497
|
-
def
|
|
637
|
+
def _dedup_landed(session: str, messages: list[Message]) -> list[Message]:
|
|
638
|
+
"""Consume (unlink) every message whose render() is already on scrollback.
|
|
639
|
+
|
|
640
|
+
The load-bearing #621 fix. ``safe_deliver`` confirms submission by polling
|
|
641
|
+
the input box back to empty; under host load that confirm false-negatives
|
|
642
|
+
even though the paste *landed* and the recipient saw it. Retaining a landed
|
|
643
|
+
message re-injects it on every idle tick — forever. So before (and after) a
|
|
644
|
+
paste we check the recipient's scrollback per-message: any message whose own
|
|
645
|
+
first-line fragment is visible has demonstrably landed → unlink it. Only
|
|
646
|
+
truly-absent messages stay pending.
|
|
647
|
+
|
|
648
|
+
Per-message keying (not the coalesced blob) so a partial landing consumes
|
|
649
|
+
exactly the visible subset. A strict fragment check (never the generic
|
|
650
|
+
``"[Pasted text"`` placeholder fallback) so a stray placeholder can't mark
|
|
651
|
+
every message delivered. A message that scrolled past the 200-line window
|
|
652
|
+
reads as not-visible → kept (safe direction: retry, never silent-drop).
|
|
653
|
+
"""
|
|
654
|
+
from .session_ready import message_on_scrollback, scrollback
|
|
655
|
+
|
|
656
|
+
capture = scrollback(session, 0)
|
|
657
|
+
consumed: list[Message] = []
|
|
658
|
+
for msg in messages:
|
|
659
|
+
if msg.path is None:
|
|
660
|
+
continue
|
|
661
|
+
if message_on_scrollback(capture, msg.render()):
|
|
662
|
+
msg.path.unlink(missing_ok=True)
|
|
663
|
+
consumed.append(msg)
|
|
664
|
+
if consumed:
|
|
665
|
+
_log_event(
|
|
666
|
+
"delivered_dedup", to=session, count=len(consumed),
|
|
667
|
+
kinds=[m.kind for m in consumed],
|
|
668
|
+
)
|
|
669
|
+
return consumed
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def flush_session(session: str, force: bool = False) -> dict:
|
|
498
673
|
"""Attempt to drain one session's inbox now.
|
|
499
674
|
|
|
500
675
|
Delivers oldest-first, coalescing all queued messages into a single paste
|
|
501
676
|
(one submit) when the box is empty. On any refusal the messages stay put,
|
|
502
677
|
their ``attempts`` bump, and over the cap they dead-letter. Never raises.
|
|
678
|
+
|
|
679
|
+
*force* (the ``msg flush --force`` escape hatch) bypasses the empty-box /
|
|
680
|
+
busy gate and pastes regardless — for an operator un-wedging a stuck queue,
|
|
681
|
+
accepting that it may land mid-draft. The ``safe_deliver`` safety guards
|
|
682
|
+
(gone / parked / non-agent / live-dialog) are never bypassed.
|
|
503
683
|
"""
|
|
504
684
|
from . import prompt_router
|
|
505
685
|
|
|
@@ -511,42 +691,74 @@ def flush_session(session: str) -> dict:
|
|
|
511
691
|
if not messages:
|
|
512
692
|
return {"session": session, "delivered": 0, "deferred": False, "reason": "empty"}
|
|
513
693
|
|
|
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
|
-
|
|
694
|
+
pre_consumed = 0
|
|
695
|
+
if not force:
|
|
696
|
+
# Collision guard FIRST (cheap, and refuses dialogs/busy too via None).
|
|
697
|
+
# But first: a prior tick may have LANDED these and false-negatived the
|
|
698
|
+
# confirm (#621). If they're already on scrollback, consume them now
|
|
699
|
+
# instead of waiting for the box to free up to re-paste a duplicate.
|
|
700
|
+
consumed = _dedup_landed(session, messages)
|
|
701
|
+
if consumed:
|
|
702
|
+
pre_consumed = len(consumed)
|
|
703
|
+
messages = [m for m in messages if m.path is not None and m.path.exists()]
|
|
704
|
+
if not messages:
|
|
705
|
+
return {
|
|
706
|
+
"session": session, "delivered": pre_consumed,
|
|
707
|
+
"deferred": False, "reason": "delivered",
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
visible = prompt_router.capture(session, 0)
|
|
711
|
+
box_content = prompt_router.input_box_content(visible)
|
|
712
|
+
|
|
713
|
+
if box_content is None:
|
|
714
|
+
# Target is busy (input box not located). Defer.
|
|
715
|
+
dead = _bump_attempts(messages, "target_busy")
|
|
716
|
+
_log_event("deferred", to=session, count=len(messages), reason="target_busy")
|
|
717
|
+
return {
|
|
718
|
+
"session": session, "delivered": pre_consumed, "deferred": True,
|
|
719
|
+
"reason": "target_busy", "dead": dead,
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if box_content != "":
|
|
723
|
+
# Box is not empty. We never bypass this to protect human drafts. But
|
|
724
|
+
# the "queued messages" placeholder is a BUSY signal, not a draft:
|
|
725
|
+
# defer WITHOUT penalty (like target_busy) so a generating-with-queued
|
|
726
|
+
# session doesn't burn report-backs toward dead-letter. Either way we
|
|
727
|
+
# never paste — only the penalty decision differs.
|
|
728
|
+
placeholder = prompt_router.is_queued_placeholder(box_content)
|
|
729
|
+
reason = "queued_placeholder" if placeholder else "box_not_empty"
|
|
730
|
+
dead = _bump_attempts(messages, reason)
|
|
731
|
+
_log_event("deferred", to=session, count=len(messages), reason=reason)
|
|
732
|
+
return {
|
|
733
|
+
"session": session, "delivered": pre_consumed, "deferred": True,
|
|
734
|
+
"reason": reason, "dead": dead,
|
|
735
|
+
}
|
|
541
736
|
|
|
542
737
|
rendered = "\n".join(m.render() for m in messages)
|
|
543
738
|
delivered, reason = prompt_router.safe_deliver(session, 0, rendered)
|
|
544
739
|
if not delivered:
|
|
545
|
-
|
|
546
|
-
|
|
740
|
+
# delivery_unverified means the box-cleared confirm failed — but the
|
|
741
|
+
# paste may have LANDED. Consume any message now visible on scrollback
|
|
742
|
+
# (idempotent delivery) so a false-negative can't cause re-injection.
|
|
743
|
+
# Other reasons (gone/parked/non-agent/dialog) never pasted, so there's
|
|
744
|
+
# nothing to dedup.
|
|
745
|
+
consumed = (
|
|
746
|
+
_dedup_landed(session, messages)
|
|
747
|
+
if reason == "delivery_unverified"
|
|
748
|
+
else []
|
|
749
|
+
)
|
|
750
|
+
consumed_ids = {m.id for m in consumed}
|
|
751
|
+
remaining = [m for m in messages if m.id not in consumed_ids]
|
|
752
|
+
if not remaining:
|
|
753
|
+
return {
|
|
754
|
+
"session": session, "delivered": pre_consumed + len(consumed),
|
|
755
|
+
"deferred": False, "reason": "delivered",
|
|
756
|
+
}
|
|
757
|
+
dead = _bump_attempts(remaining, reason)
|
|
758
|
+
_log_event("deferred", to=session, count=len(remaining), reason=reason)
|
|
547
759
|
return {
|
|
548
|
-
"session": session, "delivered":
|
|
549
|
-
"reason": reason, "dead": dead,
|
|
760
|
+
"session": session, "delivered": pre_consumed + len(consumed),
|
|
761
|
+
"deferred": True, "reason": reason, "dead": dead,
|
|
550
762
|
}
|
|
551
763
|
|
|
552
764
|
for msg in messages:
|
|
@@ -557,7 +769,7 @@ def flush_session(session: str) -> dict:
|
|
|
557
769
|
kinds=[m.kind for m in messages],
|
|
558
770
|
)
|
|
559
771
|
return {
|
|
560
|
-
"session": session, "delivered": len(messages),
|
|
772
|
+
"session": session, "delivered": pre_consumed + len(messages),
|
|
561
773
|
"deferred": False, "reason": "delivered",
|
|
562
774
|
}
|
|
563
775
|
except Exception as exc: # draining must never break the watchdog
|