agentwire-dev 1.54.0__tar.gz → 1.55.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.54.0 → agentwire_dev-1.55.0}/PKG-INFO +1 -1
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/inbox.py +59 -7
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_msg.py +20 -6
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_worktree.py +30 -4
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/msg_cli.py +35 -8
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/pane_manager.py +8 -1
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/prompt_router.py +13 -7
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler/schedule.py +12 -2
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/session_cli.py +37 -9
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/session_ready.py +239 -94
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/desktop.js +22 -29
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/shortcuts.js +1 -1
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/sessions/messaging.md +66 -24
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/conftest.py +16 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/integration/test_send_verified_tmux.py +89 -28
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_cli_commands.py +77 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_inbox.py +96 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_mcp_tools_args.py +63 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_msg_cli.py +96 -2
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_prompt_router.py +34 -5
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_scheduler.py +15 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_session_ready.py +306 -60
- agentwire_dev-1.55.0/tests/unit/test_window_cycling_binding.py +65 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/.gitignore +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/AGENTS.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/LICENSE +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/README.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/RELEASING.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/SECURITY.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/agents/tmux.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/channels_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/config.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/core.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/doctor_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/handoff/instructions.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/history.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/idle-handler.sh +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/hooks_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/limits_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_core.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_voiceclone.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/notify_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/onboarding.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles/worktree-session.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/projects.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/sessions_admin.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/routes/voice.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/safety/_core.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/safety_commands.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/security.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/services.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/stt/stt_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/kokoro_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tts_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/utils/paths.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/voice_status.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/voiceclone.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/logo.png +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/deployment/remote-machines.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/internals/damage-control.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/internals/troubleshooting.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/sessions/pi.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/sessions/prompt-routing.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/usage-limit-recovery.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/voice/shim-contract.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/pyproject.toml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/integration/test_worktree_cmd.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_config.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_control_plane_protection.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_damage_control_hooks.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_handoff_instructions.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_hooks_install.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_mcp_server.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_safety_heal.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_skill_install.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.54.0 → agentwire_dev-1.55.0}/tests/unit/test_worktree_registry.py +0 -0
|
@@ -62,6 +62,13 @@ BROADCAST_TOKEN = "@all"
|
|
|
62
62
|
# being permanently busy/typed-in).
|
|
63
63
|
MAX_ATTEMPTS = 40
|
|
64
64
|
|
|
65
|
+
# A recipient that positively does not exist gets a much shorter window (#694):
|
|
66
|
+
# a gone session can't clear its box by itself — it only comes back if someone
|
|
67
|
+
# recreates it — so the grace is ~5 watchdog ticks (≈5 min), enough for a
|
|
68
|
+
# restart/recreate to land, not the 40-minute busy cap. Counted separately
|
|
69
|
+
# (``Message.gone_attempts``) so prior busy penalties don't erode the grace.
|
|
70
|
+
GONE_MAX_ATTEMPTS = 5
|
|
71
|
+
|
|
65
72
|
# Defer reasons that DON'T penalize: the target is legitimately busy — running a
|
|
66
73
|
# long command (unparseable box → "target_busy") or generating with human-queued
|
|
67
74
|
# input (the "queued messages" placeholder → "queued_placeholder"), or the box
|
|
@@ -106,6 +113,7 @@ class Message:
|
|
|
106
113
|
text: str
|
|
107
114
|
ts: int # epoch ms
|
|
108
115
|
attempts: int = 0
|
|
116
|
+
gone_attempts: int = 0 # ticks the drain observed the target session gone
|
|
109
117
|
reason: str = "" # last defer reason (why delivery kept failing)
|
|
110
118
|
dead_ts: int = 0 # epoch ms when dead-lettered (0 = still live)
|
|
111
119
|
ref: str = "" # optional machine-readable pointer (e.g. a report path) — for ingest
|
|
@@ -120,6 +128,7 @@ class Message:
|
|
|
120
128
|
"text": self.text,
|
|
121
129
|
"ts": self.ts,
|
|
122
130
|
"attempts": self.attempts,
|
|
131
|
+
"gone_attempts": self.gone_attempts,
|
|
123
132
|
"reason": self.reason,
|
|
124
133
|
"dead_ts": self.dead_ts,
|
|
125
134
|
"ref": self.ref,
|
|
@@ -251,6 +260,7 @@ def _read_message(path: Path) -> "Message | None":
|
|
|
251
260
|
text=str(data.get("text", "")),
|
|
252
261
|
ts=int(data.get("ts", 0)),
|
|
253
262
|
attempts=int(data.get("attempts", 0)),
|
|
263
|
+
gone_attempts=int(data.get("gone_attempts", 0)),
|
|
254
264
|
reason=str(data.get("reason", "")),
|
|
255
265
|
dead_ts=int(data.get("dead_ts", 0)),
|
|
256
266
|
ref=str(data.get("ref", "")),
|
|
@@ -484,19 +494,34 @@ def gc_sender(sender: str) -> dict:
|
|
|
484
494
|
# =============================================================================
|
|
485
495
|
|
|
486
496
|
|
|
487
|
-
def
|
|
488
|
-
"""Every tmux session
|
|
489
|
-
|
|
497
|
+
def live_sessions() -> "set[str] | None":
|
|
498
|
+
"""Every live tmux session name, or None when tmux is unreachable.
|
|
499
|
+
|
|
500
|
+
``None`` (no server / no tmux) is deliberately distinct from ``set()``:
|
|
501
|
+
the gone fast-path (#694) and the send-time warning only fire on POSITIVE
|
|
502
|
+
knowledge that tmux is reachable but the target isn't there. With the
|
|
503
|
+
server down everything is equally unreachable — that's an outage, not a
|
|
504
|
+
gone recipient, so callers fall back to the ordinary defer path.
|
|
505
|
+
"""
|
|
490
506
|
from .usage_limit import _tmux
|
|
491
507
|
|
|
492
508
|
try:
|
|
493
509
|
result = _tmux(["list-sessions", "-F", "#{session_name}"])
|
|
494
510
|
except Exception:
|
|
495
|
-
return
|
|
511
|
+
return None
|
|
496
512
|
if result.returncode != 0:
|
|
513
|
+
return None
|
|
514
|
+
return {s for s in result.stdout.split("\n") if s.strip()}
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
def _live_agent_sessions() -> list[str]:
|
|
518
|
+
"""Every tmux session whose pane 0 runs an agent (Claude/pi)."""
|
|
519
|
+
from . import prompt_router
|
|
520
|
+
|
|
521
|
+
sessions = live_sessions()
|
|
522
|
+
if not sessions:
|
|
497
523
|
return []
|
|
498
|
-
|
|
499
|
-
return [s for s in sessions if prompt_router.is_agent_pane(s, 0)]
|
|
524
|
+
return [s for s in sorted(sessions) if prompt_router.is_agent_pane(s, 0)]
|
|
500
525
|
|
|
501
526
|
|
|
502
527
|
def resolve_targets(to: str, sender: "str | None") -> list[str]:
|
|
@@ -639,6 +664,15 @@ def _bump_attempts(messages: list[Message], reason: str = "") -> int:
|
|
|
639
664
|
``reason`` is the defer reason that caused this pass; it's stamped onto the
|
|
640
665
|
message so a dead-lettered one carries *why* it never got delivered.
|
|
641
666
|
Returns the number dead-lettered this pass.
|
|
667
|
+
|
|
668
|
+
``target_gone`` additionally bumps the per-message ``gone_attempts``
|
|
669
|
+
counter and dead-letters at the fast ``GONE_MAX_ATTEMPTS`` cap (#694) — a
|
|
670
|
+
gone session can't un-go by itself, so it gets minutes of grace (enough
|
|
671
|
+
for a recreate to land), not the 40-minute busy window. The counter is
|
|
672
|
+
separate from ``attempts`` so busy penalties accrued while the target
|
|
673
|
+
lived don't erode the grace, and cumulative across gone observations —
|
|
674
|
+
a target that flaps in and out without ever accepting delivery still
|
|
675
|
+
burns out on schedule.
|
|
642
676
|
"""
|
|
643
677
|
dead = 0
|
|
644
678
|
for msg in messages:
|
|
@@ -657,7 +691,9 @@ def _bump_attempts(messages: list[Message], reason: str = "") -> int:
|
|
|
657
691
|
|
|
658
692
|
msg.attempts += 1
|
|
659
693
|
msg.reason = reason
|
|
660
|
-
if
|
|
694
|
+
if reason == "target_gone":
|
|
695
|
+
msg.gone_attempts += 1
|
|
696
|
+
if msg.attempts >= MAX_ATTEMPTS or msg.gone_attempts >= GONE_MAX_ATTEMPTS:
|
|
661
697
|
msg.dead_ts = _now_ms()
|
|
662
698
|
target = dead_dir(msg.to or "unknown") / msg.path.name
|
|
663
699
|
try:
|
|
@@ -737,6 +773,22 @@ def flush_session(session: str, force: bool = False) -> dict:
|
|
|
737
773
|
if not messages:
|
|
738
774
|
return {"session": session, "delivered": 0, "deferred": False, "reason": "empty"}
|
|
739
775
|
|
|
776
|
+
# Gone gate FIRST (#694): a recipient that positively doesn't exist can
|
|
777
|
+
# never clear a box, and the ordinary gates misread it — capturing a
|
|
778
|
+
# gone session parses as "no box" → target_busy, a NO-penalty defer, so
|
|
779
|
+
# a done to a stale parent once sat queued ~24h instead of burning out.
|
|
780
|
+
# Gone is its own penalized reason with the fast GONE_MAX_ATTEMPTS cap.
|
|
781
|
+
# Only positive knowledge counts: with tmux unreachable live_sessions()
|
|
782
|
+
# is None and the ordinary defer path applies.
|
|
783
|
+
live = live_sessions()
|
|
784
|
+
if live is not None and session not in live:
|
|
785
|
+
dead = _bump_attempts(messages, "target_gone")
|
|
786
|
+
_log_event("deferred", to=session, count=len(messages), reason="target_gone")
|
|
787
|
+
return {
|
|
788
|
+
"session": session, "delivered": 0, "deferred": True,
|
|
789
|
+
"reason": "target_gone", "dead": dead,
|
|
790
|
+
}
|
|
791
|
+
|
|
740
792
|
pre_consumed = 0
|
|
741
793
|
if not force:
|
|
742
794
|
# Collision guard FIRST (cheap, and refuses dialogs/busy too via None).
|
|
@@ -17,6 +17,12 @@ def msg_send(to: str, text: str, kind: str = "note", ref: str = "") -> str:
|
|
|
17
17
|
is empty and the pane is safe, so it can never clobber a human who is
|
|
18
18
|
mid-typing. Delivery is at the next safe boundary (≤60s), not instant.
|
|
19
19
|
|
|
20
|
+
Sending to a named session that doesn't currently exist still queues (the
|
|
21
|
+
session may be about to be created), but the confirmation carries a
|
|
22
|
+
warning: unless the session appears, the message dead-letters within a few
|
|
23
|
+
minutes (and load-bearing kinds email the owner). Heed the warning — a
|
|
24
|
+
gone recipient usually means a stale session name; check sessions_list.
|
|
25
|
+
|
|
20
26
|
Prefer `session_send` ONLY when you must forcibly drive a session right
|
|
21
27
|
now (it pastes + Enter immediately, overwriting any uncommitted draft).
|
|
22
28
|
|
|
@@ -34,7 +40,8 @@ def msg_send(to: str, text: str, kind: str = "note", ref: str = "") -> str:
|
|
|
34
40
|
so the recipient can open the file without parsing free text.
|
|
35
41
|
|
|
36
42
|
Returns:
|
|
37
|
-
Confirmation of which sessions were queued
|
|
43
|
+
Confirmation of which sessions were queued — plus a warning when a
|
|
44
|
+
named recipient doesn't currently exist — or an error.
|
|
38
45
|
"""
|
|
39
46
|
caller = get_caller_session()
|
|
40
47
|
args = ["msg", "send", "--to", to, "--kind", kind]
|
|
@@ -48,7 +55,10 @@ def msg_send(to: str, text: str, kind: str = "note", ref: str = "") -> str:
|
|
|
48
55
|
recipients = data.get("recipients") or []
|
|
49
56
|
if not recipients:
|
|
50
57
|
return f"No live recipients for '{to}'."
|
|
51
|
-
|
|
58
|
+
out = f"Queued {kind} → {', '.join(recipients)} (delivers when their box is clear)."
|
|
59
|
+
for warning in data.get("warnings") or []:
|
|
60
|
+
out += f"\nWarning: {warning}"
|
|
61
|
+
return out
|
|
52
62
|
return f"Failed to queue message: {data.get('error', 'Unknown error')}"
|
|
53
63
|
|
|
54
64
|
|
|
@@ -149,12 +159,16 @@ def msg_dead(session: str | None = None) -> str:
|
|
|
149
159
|
"""List dead-lettered polite messages — ones dropped after retrying out.
|
|
150
160
|
|
|
151
161
|
A `msg` whose recipient never cleared its input box (or stayed parked /
|
|
152
|
-
non-agent) is retried for ~40 minutes
|
|
153
|
-
|
|
162
|
+
non-agent) is retried for ~40 minutes; one whose recipient doesn't exist
|
|
163
|
+
dead-letters after only a few minutes (`target_gone`). Either way the drop
|
|
164
|
+
is recorded here rather than lost silently. Use this to see what never
|
|
165
|
+
reached someone, and why.
|
|
154
166
|
|
|
155
167
|
Args:
|
|
156
|
-
session:
|
|
157
|
-
every session that has dead-lettered messages
|
|
168
|
+
session: Scope to one session's graveyard. Omitted means GLOBAL —
|
|
169
|
+
every session that has dead-lettered messages (#693: it never
|
|
170
|
+
defaults to the calling session, so a monitoring loop inside a
|
|
171
|
+
session still sees the whole graveyard).
|
|
158
172
|
|
|
159
173
|
Returns:
|
|
160
174
|
The dead-lettered messages with their drop reason + timestamp, or a
|
|
@@ -52,15 +52,41 @@ def worktree_create(
|
|
|
52
52
|
caller = get_caller_session()
|
|
53
53
|
if caller:
|
|
54
54
|
args += ["--created-by", caller]
|
|
55
|
-
# Seeding waits for agent boot (
|
|
56
|
-
|
|
55
|
+
# Seeding waits for agent boot (up to 60s) and, on a failed seed, runs the
|
|
56
|
+
# clear-box + inbox-fallback recovery (#695) — give the CLI room to finish
|
|
57
|
+
# the loud-failure path instead of masking it with a subprocess timeout.
|
|
58
|
+
data = run_agentwire_cmd(args, timeout=180)
|
|
57
59
|
if not data.get("success"):
|
|
58
60
|
return f"Failed to create worktree: {data.get('error', 'Unknown error')}"
|
|
59
61
|
session = data.get("session", name)
|
|
60
62
|
path = data.get("path", "")
|
|
61
|
-
seeded = " (seeded)" if prompt and data.get("first_message_delivered") else ""
|
|
62
63
|
if data.get("reattached"):
|
|
63
|
-
|
|
64
|
+
note = (
|
|
65
|
+
" NOTE: the session was already live, so the seed prompt was NOT "
|
|
66
|
+
"pasted — send it with msg_send if still needed."
|
|
67
|
+
if prompt
|
|
68
|
+
else ""
|
|
69
|
+
)
|
|
70
|
+
return f"Reattached to existing worktree session '{session}' at {path}.{note}"
|
|
71
|
+
# Seed failure must be LOUD (#695): a silently-missing "(seeded)" suffix is
|
|
72
|
+
# invisible to an orchestrator skimming results, and the session then sits
|
|
73
|
+
# idle with the task never delivered.
|
|
74
|
+
if prompt and not data.get("first_message_delivered"):
|
|
75
|
+
if data.get("first_message_fallback") == "inbox":
|
|
76
|
+
return (
|
|
77
|
+
f"Created worktree session '{session}' at {path}. "
|
|
78
|
+
"WARNING: seed prompt NOT delivered — the input box was not ready. "
|
|
79
|
+
"The prompt was queued to the session's msg inbox and the watchdog "
|
|
80
|
+
"will deliver it once the box is ready; verify with msg_inbox / "
|
|
81
|
+
"session_output before assuming the task started."
|
|
82
|
+
)
|
|
83
|
+
return (
|
|
84
|
+
f"Created worktree session '{session}' at {path}. "
|
|
85
|
+
"WARNING: seed prompt NOT delivered and could NOT be queued — the "
|
|
86
|
+
f"session is idle with no task. Deliver it manually (session_send to "
|
|
87
|
+
f"'{session}')."
|
|
88
|
+
)
|
|
89
|
+
seeded = " (seeded)" if prompt else ""
|
|
64
90
|
return f"Created worktree session '{session}'{seeded} at {path}."
|
|
65
91
|
|
|
66
92
|
|
|
@@ -66,15 +66,36 @@ def cmd_msg_send(args) -> int:
|
|
|
66
66
|
print(f"Nothing queued — {reason}.")
|
|
67
67
|
return 0
|
|
68
68
|
|
|
69
|
+
# Send-time existence signal (#694): queueing to a named session that
|
|
70
|
+
# doesn't currently exist is legal (it may be created shortly), but the
|
|
71
|
+
# sender must learn the target is gone instead of reading a bare "Queued"
|
|
72
|
+
# as delivery-in-progress. @all targets are live by construction, and with
|
|
73
|
+
# tmux unreachable (live is None) we can't positively say gone — no warning.
|
|
74
|
+
live = inbox.live_sessions()
|
|
75
|
+
missing = (
|
|
76
|
+
[]
|
|
77
|
+
if args.to == inbox.BROADCAST_TOKEN or live is None
|
|
78
|
+
else sorted({m.to for m in written} - live)
|
|
79
|
+
)
|
|
80
|
+
warnings = [
|
|
81
|
+
f"session '{t}' does not currently exist — message will dead-letter "
|
|
82
|
+
f"in ~{inbox.GONE_MAX_ATTEMPTS} min unless it appears"
|
|
83
|
+
for t in missing
|
|
84
|
+
]
|
|
85
|
+
|
|
69
86
|
if getattr(args, "json", False):
|
|
70
87
|
print(json.dumps({
|
|
71
88
|
"success": True,
|
|
72
89
|
"queued": [m.to_dict() for m in written],
|
|
73
90
|
"recipients": [m.to for m in written],
|
|
91
|
+
"missing": missing,
|
|
92
|
+
"warnings": warnings,
|
|
74
93
|
}))
|
|
75
94
|
else:
|
|
76
95
|
recips = ", ".join(m.to for m in written)
|
|
77
96
|
print(f"Queued {args.kind} from {sender} → {recips}")
|
|
97
|
+
for warning in warnings:
|
|
98
|
+
print(f"Warning: {warning}")
|
|
78
99
|
return 0
|
|
79
100
|
|
|
80
101
|
|
|
@@ -171,8 +192,8 @@ def _parse_duration(text: str) -> "int | None":
|
|
|
171
192
|
|
|
172
193
|
def _purge_dead(args) -> int:
|
|
173
194
|
"""Clear dead-lettered corpses. ``-s`` scopes to one session; without it the
|
|
174
|
-
whole graveyard is cleared
|
|
175
|
-
|
|
195
|
+
whole graveyard is cleared — same no-``-s``-means-global rule as the lister
|
|
196
|
+
(#693), and purge never guesses a session for a delete."""
|
|
176
197
|
import sys
|
|
177
198
|
import time
|
|
178
199
|
|
|
@@ -203,13 +224,19 @@ def cmd_msg_dead(args) -> int:
|
|
|
203
224
|
"""List (or, with ``--purge``, clear) dead-lettered messages.
|
|
204
225
|
|
|
205
226
|
These are messages a recipient never accepted — its input box stayed busy,
|
|
206
|
-
|
|
207
|
-
where silent data loss became visible. ``--purge`` is the
|
|
208
|
-
for the graveyard `doctor` surfaces.
|
|
227
|
+
it was parked/non-agent the whole time, or it didn't exist. They are *not*
|
|
228
|
+
retried; this is where silent data loss became visible. ``--purge`` is the
|
|
229
|
+
human/ops cleanup for the graveyard `doctor` surfaces.
|
|
230
|
+
|
|
231
|
+
Omitted ``-s`` means GLOBAL — every session's graveyard (#693). It never
|
|
232
|
+
falls back to the caller's session: every agent runs inside tmux, so a
|
|
233
|
+
caller-scoped default made the global view unreachable exactly where
|
|
234
|
+
monitoring loops run, silently reporting "no dead letters" while other
|
|
235
|
+
sessions' graveyards grew.
|
|
209
236
|
"""
|
|
210
237
|
if getattr(args, "purge", False):
|
|
211
238
|
return _purge_dead(args)
|
|
212
|
-
session = getattr(args, "session", None)
|
|
239
|
+
session = getattr(args, "session", None)
|
|
213
240
|
sessions = [session] if session else inbox.dead_sessions()
|
|
214
241
|
|
|
215
242
|
grouped = [(s, inbox.list_dead(s)) for s in sessions]
|
|
@@ -350,8 +377,8 @@ def register_msg_parser(subparsers) -> None:
|
|
|
350
377
|
)
|
|
351
378
|
dead_parser.add_argument(
|
|
352
379
|
"-s", "--session", default=None,
|
|
353
|
-
help="
|
|
354
|
-
"
|
|
380
|
+
help="Scope to one session (default: every session's graveyard, "
|
|
381
|
+
"for both list and --purge)",
|
|
355
382
|
)
|
|
356
383
|
dead_parser.add_argument(
|
|
357
384
|
"--purge", action="store_true",
|
|
@@ -280,7 +280,14 @@ def send_to_target(target: str, text: str, enter: bool = True) -> None:
|
|
|
280
280
|
result = run_command(["tmux", "load-buffer", temp_path], timeout=5)
|
|
281
281
|
if not result.success:
|
|
282
282
|
raise RuntimeError(f"Failed to load buffer: {result.stderr.strip()}")
|
|
283
|
-
|
|
283
|
+
# -p wraps the paste in bracketed-paste delimiters when the app has
|
|
284
|
+
# requested them (Claude Code always does; tmux falls back to a
|
|
285
|
+
# plain paste otherwise). Without the explicit end-of-paste marker,
|
|
286
|
+
# Claude Code detects the paste heuristically as an input burst,
|
|
287
|
+
# and an Enter arriving inside that window is coalesced INTO the
|
|
288
|
+
# paste as a newline instead of submitting — the swallowed-Enter
|
|
289
|
+
# root cause behind the #698 stress-test failures.
|
|
290
|
+
result = run_command(["tmux", "paste-buffer", "-p", "-t", target], timeout=5)
|
|
284
291
|
if not result.success:
|
|
285
292
|
raise RuntimeError(f"Target '{target}' not found: {result.stderr.strip()}")
|
|
286
293
|
finally:
|
|
@@ -775,20 +775,26 @@ def _flush_stuck_box(session: str, pane_index: int, visible: str) -> bool:
|
|
|
775
775
|
|
|
776
776
|
- the box parses and holds non-empty, non-placeholder content,
|
|
777
777
|
- the content starts with a machine-injected header (never a human draft),
|
|
778
|
-
-
|
|
778
|
+
- no live select-menu is on screen (Enter would answer the dialog),
|
|
779
779
|
- the identical content has sat there for ``STUCK_BOX_SWEEPS``
|
|
780
780
|
consecutive sweeps (state persisted per-pane next to prompt markers).
|
|
781
781
|
|
|
782
|
+
A mid-generation pane is deliberately NOT skipped (#698): Enter on a
|
|
783
|
+
generating Claude Code pane QUEUES the draft (Esc interrupts, Enter never
|
|
784
|
+
does), while the old ``esc to interrupt`` gate both refused the flush AND
|
|
785
|
+
reset the counter every sweep — so a stuck box on a busy orchestrator was
|
|
786
|
+
never rescued for as long as it kept working (the 2026-07-04 12:40
|
|
787
|
+
incident, where the owner watched the message sit and pressed Enter
|
|
788
|
+
manually). Frames we can't judge (unparseable box, live menu) HOLD the
|
|
789
|
+
counter instead of resetting it, for the same reason.
|
|
790
|
+
|
|
782
791
|
Never pastes — Enter only, so the #621 idempotency dedup keeps holding.
|
|
783
792
|
"""
|
|
784
793
|
path = _stuck_box_path(session, pane_index)
|
|
785
794
|
box = input_box_content(visible)
|
|
786
|
-
if (
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
or is_queued_placeholder(box)
|
|
790
|
-
or "esc to interrupt" in visible.lower()
|
|
791
|
-
):
|
|
795
|
+
if box is None or screen_shows_live_menu(visible):
|
|
796
|
+
return False # can't judge this frame / Enter unsafe — hold the counter
|
|
797
|
+
if not box or not _MACHINE_HEADER_RE.match(box) or is_queued_placeholder(box):
|
|
792
798
|
try:
|
|
793
799
|
path.unlink(missing_ok=True)
|
|
794
800
|
except OSError:
|
|
@@ -14,6 +14,11 @@ from .models import (
|
|
|
14
14
|
_parse_time,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
+
# Minimum sleep when the board has a DUE task that isn't runnable (gate
|
|
18
|
+
# failed). Without it, pick_next_task returns (None, 0.0) and the main loop
|
|
19
|
+
# spins at time.sleep(0) — see #691.
|
|
20
|
+
GATE_RETRY_FLOOR = 30.0
|
|
21
|
+
|
|
17
22
|
|
|
18
23
|
def _dt_to_ts(dt: datetime | None) -> float:
|
|
19
24
|
"""Convert a datetime to a Unix timestamp (0 if None)."""
|
|
@@ -258,9 +263,14 @@ def pick_next_task(board: Board) -> tuple[str | None, float]:
|
|
|
258
263
|
if _sched._check_gate(board, name):
|
|
259
264
|
return name, 0.0
|
|
260
265
|
|
|
261
|
-
# Nothing to run now — calculate sleep until earliest task is due
|
|
266
|
+
# Nothing to run now — calculate sleep until earliest task is due. A task
|
|
267
|
+
# can be DUE yet not runnable (gate failed, above), which makes
|
|
268
|
+
# seconds_until_next_due return 0.0 — without a floor the main loop does
|
|
269
|
+
# time.sleep(0) and spins hard: gate command re-run + portal notify
|
|
270
|
+
# ~12×/sec until the gate ever passes (#691). Floor to GATE_RETRY_FLOOR so
|
|
271
|
+
# a due-but-gated board re-checks at loop cadence instead.
|
|
262
272
|
wait = seconds_until_next_due(board)
|
|
263
|
-
return None, wait
|
|
273
|
+
return None, max(wait, GATE_RETRY_FLOOR)
|
|
264
274
|
|
|
265
275
|
|
|
266
276
|
def seconds_until_next_due(board: Board) -> float:
|
|
@@ -477,11 +477,25 @@ def cmd_new(args) -> int:
|
|
|
477
477
|
)
|
|
478
478
|
save_project_config(project_config, session_path)
|
|
479
479
|
|
|
480
|
+
# Record the creating session as parent for prompt routing. --created-by
|
|
481
|
+
# overrides; empty string opts out; default = the calling tmux session.
|
|
482
|
+
# Resolved before seeding so a failed seed can name its sender.
|
|
483
|
+
created_by = getattr(args, 'created_by', None)
|
|
484
|
+
if created_by is None:
|
|
485
|
+
created_by = pane_manager.get_current_session()
|
|
486
|
+
|
|
480
487
|
# Deliver the first message once the agent is ready (verified paste).
|
|
481
|
-
# Delivery failure doesn't fail the command — the session exists
|
|
488
|
+
# Delivery failure doesn't fail the command — the session exists — but it
|
|
489
|
+
# must be LOUD (#695): clear the partial paste out of the box and fall
|
|
490
|
+
# back to the msg inbox so the prompt still arrives once the box is ready.
|
|
482
491
|
first_message_delivered = None
|
|
492
|
+
first_message_fallback = None
|
|
483
493
|
if first_message and agent_cmd:
|
|
484
|
-
from agentwire.session_ready import
|
|
494
|
+
from agentwire.session_ready import (
|
|
495
|
+
recover_failed_seed,
|
|
496
|
+
send_verified,
|
|
497
|
+
wait_for_session_ready,
|
|
498
|
+
)
|
|
485
499
|
|
|
486
500
|
if not json_mode:
|
|
487
501
|
print("Waiting for agent to deliver first message...")
|
|
@@ -489,14 +503,24 @@ def cmd_new(args) -> int:
|
|
|
489
503
|
wait_for_session_ready(session_name, timeout=60)
|
|
490
504
|
and send_verified(session_name, first_message)
|
|
491
505
|
)
|
|
492
|
-
if not first_message_delivered
|
|
493
|
-
|
|
506
|
+
if not first_message_delivered:
|
|
507
|
+
first_message_fallback = recover_failed_seed(
|
|
508
|
+
session_name, first_message, sender=created_by or "agentwire"
|
|
509
|
+
)
|
|
510
|
+
if not json_mode:
|
|
511
|
+
if first_message_fallback == "inbox":
|
|
512
|
+
print(
|
|
513
|
+
f"WARNING: first message NOT delivered to '{session_name}' — "
|
|
514
|
+
"queued to its msg inbox for delivery once the input box is ready",
|
|
515
|
+
file=sys.stderr,
|
|
516
|
+
)
|
|
517
|
+
else:
|
|
518
|
+
print(
|
|
519
|
+
f"WARNING: first message NOT delivered to '{session_name}' "
|
|
520
|
+
"and could not be queued — paste it manually",
|
|
521
|
+
file=sys.stderr,
|
|
522
|
+
)
|
|
494
523
|
|
|
495
|
-
# Record the creating session as parent for prompt routing. --created-by
|
|
496
|
-
# overrides; empty string opts out; default = the calling tmux session.
|
|
497
|
-
created_by = getattr(args, 'created_by', None)
|
|
498
|
-
if created_by is None:
|
|
499
|
-
created_by = pane_manager.get_current_session()
|
|
500
524
|
_record_session_creator(session_name, created_by, via="new")
|
|
501
525
|
|
|
502
526
|
if json_mode:
|
|
@@ -509,6 +533,10 @@ def cmd_new(args) -> int:
|
|
|
509
533
|
}
|
|
510
534
|
if first_message:
|
|
511
535
|
result["first_message_delivered"] = bool(first_message_delivered)
|
|
536
|
+
if not first_message_delivered:
|
|
537
|
+
# "inbox" (queued for watchdog delivery) or None (fallback
|
|
538
|
+
# failed too — the prompt is gone; caller must redeliver).
|
|
539
|
+
result["first_message_fallback"] = first_message_fallback
|
|
512
540
|
_output_json(result)
|
|
513
541
|
else:
|
|
514
542
|
print(f"Created session '{session_name}' in {session_path}")
|