agentwire-dev 1.71.0__tar.gz → 1.72.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.71.0 → agentwire_dev-1.72.0}/PKG-INFO +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/__init__.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/agents/tmux.py +2 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/auth_expired.py +4 -4
- agentwire_dev-1.72.0/agentwire/background_tasks.py +561 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels_cli.py +7 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/cohort.py +43 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/config.py +49 -6
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/core.py +71 -7
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/doctor_cli.py +260 -39
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/instructions.py +5 -7
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/history.py +17 -11
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/history_migrate.py +9 -9
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +3011 -207
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +3011 -204
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +3047 -217
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +3011 -204
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/containers.yaml +2 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/core.yaml +17 -12
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/git.yaml +10 -5
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/outbound.yaml +2 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +3011 -204
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/idle-handler.sh +70 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks_cli.py +154 -50
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/inbox.py +227 -29
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/limits_cli.py +178 -27
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_core.py +49 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/msg_cli.py +29 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/notify_cli.py +47 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/onboarding.py +1 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/prompt_router.py +70 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/projects.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/sessions_admin.py +3 -3
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/voice.py +10 -1
- agentwire_dev-1.72.0/agentwire/safety/_core.py +7338 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/provenance.py +66 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/rule_baselines.json +7 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety_commands.py +81 -22
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/security.py +96 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/server.py +48 -18
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/services.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/session_cli.py +3 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/session_ready.py +175 -15
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/stt_server.py +2 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/kokoro_server.py +2 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts_cli.py +23 -15
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts_server.py +6 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/paths.py +5 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_status.py +8 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/deployment/remote-machines.md +8 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/damage-control.md +538 -5
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/troubleshooting.md +92 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/fan-out-cohorts.md +6 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/messaging.md +114 -3
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/prompt-routing.md +23 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/usage-limit-recovery.md +31 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice/shim-contract.md +14 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/conftest.py +25 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_30_shell.txt +9 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_agent.txt +7 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_done.txt +12 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_interrupted.txt +8 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_monitor.txt +12 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_quoted_footer.txt +22 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_second_notice.txt +8 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_shell.txt +15 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_shell_and_monitor.txt +5 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/transcript_bash_done.jsonl +2 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/transcript_bash_pending.jsonl +1 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/transcript_monitor_done.jsonl +6 -0
- agentwire_dev-1.72.0/tests/fixtures/background_tasks/transcript_monitor_events.jsonl +5 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/home_guard.py +36 -14
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_send_verified_tmux.py +73 -9
- agentwire_dev-1.72.0/tests/unit/test_allowlist_never_reopens_guarded.py +221 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_audit_outcomes.py +2 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_auth_expired.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_auth_expired_dispatch.py +1 -1
- agentwire_dev-1.72.0/tests/unit/test_background_tasks.py +651 -0
- agentwire_dev-1.72.0/tests/unit/test_background_tasks_review.py +103 -0
- agentwire_dev-1.72.0/tests/unit/test_background_tasks_review2.py +88 -0
- agentwire_dev-1.72.0/tests/unit/test_background_tasks_review3.py +30 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cli_commands.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cohort.py +90 -0
- agentwire_dev-1.72.0/tests/unit/test_compound_command_positions.py +345 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_config.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_control_plane_protection.py +89 -0
- agentwire_dev-1.72.0/tests/unit/test_control_plane_writers.py +1031 -0
- agentwire_dev-1.72.0/tests/unit/test_damage_control_eval_position.py +1098 -0
- agentwire_dev-1.72.0/tests/unit/test_damage_control_flag_order.py +278 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_hooks.py +7 -5
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_payload_anchoring.py +18 -19
- agentwire_dev-1.72.0/tests/unit/test_damage_control_word_spans.py +283 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_orphaned_history.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_handoff_instructions.py +2 -2
- agentwire_dev-1.72.0/tests/unit/test_heredoc_marker_liveness.py +322 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_history_migrate.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_history_migrate_cli.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_home_isolation.py +42 -0
- agentwire_dev-1.72.0/tests/unit/test_hook_fail_closed.py +359 -0
- agentwire_dev-1.72.0/tests/unit/test_hook_link_guard.py +243 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_hooks_install.py +18 -13
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_inbox.py +457 -10
- agentwire_dev-1.72.0/tests/unit/test_mcp_nonblocking.py +172 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_mcp_server.py +58 -12
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_msg_cli.py +2 -0
- agentwire_dev-1.72.0/tests/unit/test_prompt_router_dedup.py +133 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_restart_cli.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_deployment.py +2 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_heal.py +20 -0
- agentwire_dev-1.72.0/tests/unit/test_scan_budget.py +365 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_ready.py +288 -22
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_skill_install.py +4 -6
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_unattended_allow.py +2 -2
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_body_delivery.py +1 -1
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_kind.py +1 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_layer.py +4 -1
- agentwire_dev-1.72.0/tests/unit/test_voice_off_and_shim_bind.py +242 -0
- agentwire_dev-1.72.0/tests/unit/test_watchdog_stages.py +144 -0
- agentwire_dev-1.71.0/agentwire/safety/_core.py +0 -4532
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.agentwire.yml.example +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.claude/commands/handoff.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.claude/skills/wiki/SKILL.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/FUNDING.yml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/workflows/pytest.yml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/workflows/ruff.yml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/workflows/security.yml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/workflows/tts-smoke.yml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.gitignore +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/AGENTS.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/CODE_OF_CONDUCT.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/CONTRIBUTING.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/Dockerfile.local +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/LICENSE +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/README.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/RELEASING.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/SECURITY.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/SPONSORS.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/__main__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/activity_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/agents/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/agents/base.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/alerts_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/beta.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/buddy_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/cached_status.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/base.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/email.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/push.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/quo.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/chrome_tabs.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/completion.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/config_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/inbox.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/minutes.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/state.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/view.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/devices.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/diff_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/doctor_voice.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/ensure_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/fetch.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/fleet_activity.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/fleet_alerts.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/git_state.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/parser.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/renderer.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/schema.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/history_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/agentwire-permission.sh +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/mcp-tools.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/payloads.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/outcome_logger.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/queue-processor.sh +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/listen.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/locking.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/machine_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_channels.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_chrome.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_council.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_desktop.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_handoff.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_history.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_listen.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_lock.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_machine.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_msg.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_notify.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_pane.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_projects.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_scheduler.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_scratchpad.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_server.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_services.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_session.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_status.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_task.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_tunnels.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_voice.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_wiki.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_worktree.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/network.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/palette_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/pane_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/pane_manager.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/portal_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/project_config.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/projects.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/prompts_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/push_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/push_store.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/repo_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/research.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/restart_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/role_prompts.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/agentwire.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/anchor.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/chatbot.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/contributor.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/correspondent.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-brain.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-conscience.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-critic.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-devils-advocate.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-gut.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-historian.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-member.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-orchestrator.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/init.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/notifications.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/orchestrator.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/reviewer-worktree.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/reviewer.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/shared-checkout.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/soul.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/task-runner.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/voice.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/worker-worktree.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/worker.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/artifacts.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/config.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/council.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/desktop.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/history.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/machines.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/notify.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/palette.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/permission.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/push.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/safety.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/scheduler.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/scratchpad.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/sessions.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/audit.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/lint.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety_notify.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/dispatch.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/gates.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/loop.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/models.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/report.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/schedule.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/state.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/zombie.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scratchpad.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/send_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/session_context.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/ssh.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/announcements.json +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/apple-touch-icon.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/css/desktop.css +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/css/mobile.css +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/favicon-32.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/favicon-64.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/bear.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/cat.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/crown.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/deer.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/drone.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/fox.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/horse.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/lion.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/robot.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/img/icon-192.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/img/icon-512.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/.gitkeep +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/announcement-modal.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/api.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/artifact-window.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/card-terminal.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/collage.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/command-palette.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/council-window.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/dead-key-residue.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/desktop-manager.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/desktop.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/help-modal.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/hotkeys.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/icon-manager.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/lineage.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/mobile.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/notification-prefs.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/notifications-panel.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/ptt.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/push-client.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/review-window.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/safety-shared.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/safety-window.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/scratchpad.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/service-classification.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-hud-controller.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-hud-notices.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-hud-spawn.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-hud.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-id.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-window.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/shortcuts.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/config-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/council-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/services-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/spawn-ghost.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/terminal-pane.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/tile-manager.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/toast.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/token-modal.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/topology-render.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/utils/ansi.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/utils/rich-text.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/utils/swipe.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/browser-stt.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/browser-tts.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/jargon.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/prompt.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/workspace-window.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/manifest.webmanifest +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/service-worker.js +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/topology-harness.html +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/base.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/cloud.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/engine.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/local.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/server_backend.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/system_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tabs_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tasks.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tasks_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/base.html +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/council/minutes.html.j2 +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/desktop.html +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/email_notification.html +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/mobile.html +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/pair.html +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/statusline.sh +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/tmux.conf +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templating.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/aws.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/docker.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/gcp.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/gh.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/git.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/gws.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/kubectl.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/npm.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/terraform.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/uv.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/audio.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/base.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/engines/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/engines/chatterbox.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/engines/kokoro.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/engines/zonos.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/local.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/registry.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tunnels.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tunnels_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/usage_limit.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/chunker.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/event_log.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/file_io.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/speech.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/subprocess.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/validation.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/__init__.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/client.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/confirm.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/delivery.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/identity.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/instructions.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/outbox.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/realtime.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/relay.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/server.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/surface.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/tools.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/transcript.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/write_tools.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/wait_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/wiki.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/wiki_audit.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/wiki_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/worktree.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/worktree_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/worktree_registry.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/decisions/obsidian-second-brain.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/design/session-card-fields.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/design/session-card-recommendation.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/logo.png +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/INDEX.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/architecture.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/auth-expired.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/briefing-mode.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/communication/channels.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/communication/hammerspoon.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/communication/handoff.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/concepts.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/council.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/deployment/remote-access.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/glossary.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/parallel-refactor.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/portal.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/session-topology.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/shell-escaping.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/window-collage.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/quickstart.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/security/damage-control-hardening.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/security/pip-audit.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/security/remote-access-hardening.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/security/secrets.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/services.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/conversation-identity.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/heal-line-count-cliff.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/helper-sessions.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/window-sizing.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice/stt-cloud.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice-layer.md +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/pyproject.toml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/scratch-remove-docker-daemons.sh +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/e2e/test_portal_ui.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/fixtures/hotkeys_harness.mjs +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/fixtures/sample_agentwire.yml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/fixtures/sample_config.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/fixtures/sample_scheduler.yaml +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_council_portal.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_scheduler_board.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_server_websockets.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_tmux_name_rewrite.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_worktree_cmd.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/page_slice.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_announcements.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_audit_attribution.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_beta_flag.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_brace_expansion_zero_access.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_buddy_restart.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_build_agent_command.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_channels.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_chrome_tabs.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cli_output.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cli_smoke.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cli_stderr_clean.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_client_wires.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_config_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_core_created_by_rooting.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_inbox.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_minutes.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_state.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_view.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_bypass.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_inert_view.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_operation_pinning.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_sync.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_dangling_worktrees.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_devices.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_diff_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_scheduler_staleness.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_secrets_perms.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_task_migration.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_voice.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_ensure_shared_dir.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_ensure_verified_prompt.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_event_log.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_file_io.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_fleet_activity.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_fleet_alerts.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_guarded_launch_command.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_handoff_git_state.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_handoff_parser.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_handoff_renderer.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_helper_session.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_history.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_history_resume_name.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_hotkeys_js.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_idle_handler.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_idle_nag.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_init_command.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_install_parity.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_launch_line_reentry.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_launch_via_env.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_limits_tick_isolation.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_locking.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_mcp_tool_policy.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_mcp_tools_args.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_notify_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_onboarding_reinit.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_owner_only_writes.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_palette_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_payload_position.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_pending_message_visibility.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_pip_audit_report.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_pip_environment.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_portal_api.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_posture_default.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_project_config.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_projects_registry.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_prompt_router.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_prompt_router_resume.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_prose_operands.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_push.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_rebuild_guard.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_remote_session_record.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_repo_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_rich_text_js.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_rm_recoverable.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_role_prompt_retention.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_role_prompt_sweep_wiring.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_roles.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_routes_snapshot.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_commands.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_coverage_wave.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_disabled_rules.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_engine_is_standalone.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_escape_hatch.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_kill_switch.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_notify.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scheduler.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scheduler_liveness.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scheduler_parsing.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scheduler_zombie.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scratchpad.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_security.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_sed_script_is_data.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_server_async.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_server_pure.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_services.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_services_command.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_context.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_created_by_env.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_metadata_ssot.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_metadata_write.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_shared_dir_guard.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_shim_selfheal.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_speech_tags.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_ssh.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_stt_backend.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_stt_cloud.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_stt_engine.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_task_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_task_max_duration.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tasks.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tasks_cli.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_templating.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_terminal_resize.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tmux_session_cwd.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tmux_template.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tts_engine_resolution.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tts_local.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tunnels_probe.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_unattended_env_isolation.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_unattended_scoped_allow.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_usage_limit.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_validation.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_announcer.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_bridge_host.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_confirm.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_epoch.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_fleet_alerts.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_outbox.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_persona.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_picker.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_relay_full_text.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_status.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_surface.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_ux_1048.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_wiki.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_wiki_audit.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_window_cycling_binding.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_branch_cleanup.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_dot_project.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_git_truth.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_layout.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_registry.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_zero_access_member_access.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tools/nonce_stt_probe.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tools/voice_dc_probe.py +0 -0
- {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tools/voice_heal_probe.py +0 -0
|
@@ -89,7 +89,7 @@ class TmuxAgent(AgentBackend):
|
|
|
89
89
|
Returns:
|
|
90
90
|
CompletedProcess result
|
|
91
91
|
"""
|
|
92
|
-
logger.debug(f"Running local: {' '.join(cmd)}")
|
|
92
|
+
logger.debug(f"Running local: {' '.join(cmd[:2])}") # verb only: later words can carry typed text
|
|
93
93
|
return subprocess.run(
|
|
94
94
|
cmd,
|
|
95
95
|
capture_output=capture,
|
|
@@ -122,7 +122,7 @@ class TmuxAgent(AgentBackend):
|
|
|
122
122
|
ssh_cmd.extend(["-p", str(port)])
|
|
123
123
|
ssh_cmd.extend([ssh_target, cmd])
|
|
124
124
|
|
|
125
|
-
logger.debug(f"Running remote on {ssh_target}: {cmd}")
|
|
125
|
+
logger.debug(f"Running remote on {ssh_target}: {' '.join(cmd.split()[:2])}") # verb only
|
|
126
126
|
return subprocess.run(
|
|
127
127
|
ssh_cmd,
|
|
128
128
|
capture_output=capture,
|
|
@@ -218,7 +218,7 @@ def recorded_transcripts(session: str) -> list[Path]:
|
|
|
218
218
|
still evidence rather than a guess.
|
|
219
219
|
"""
|
|
220
220
|
from .core import load_session_metadata
|
|
221
|
-
from .history import
|
|
221
|
+
from .history import claude_projects_dir, encode_project_path
|
|
222
222
|
|
|
223
223
|
try:
|
|
224
224
|
meta = load_session_metadata(session)
|
|
@@ -228,7 +228,7 @@ def recorded_transcripts(session: str) -> list[Path]:
|
|
|
228
228
|
ids = meta.get("conversation_ids") or []
|
|
229
229
|
if not cwd or not ids:
|
|
230
230
|
return []
|
|
231
|
-
base =
|
|
231
|
+
base = claude_projects_dir() / encode_project_path(str(cwd))
|
|
232
232
|
return [p for p in (base / f"{cid}.jsonl" for cid in ids) if p.exists()]
|
|
233
233
|
|
|
234
234
|
|
|
@@ -245,9 +245,9 @@ def touched_transcripts(project_path, since: float) -> list[Path]:
|
|
|
245
245
|
written during the window the caller is asking about, so a hit is a
|
|
246
246
|
transcript this run actually produced.
|
|
247
247
|
"""
|
|
248
|
-
from .history import
|
|
248
|
+
from .history import claude_projects_dir, encode_project_path
|
|
249
249
|
|
|
250
|
-
base =
|
|
250
|
+
base = claude_projects_dir() / encode_project_path(str(project_path))
|
|
251
251
|
try:
|
|
252
252
|
entries = list(base.glob("*.jsonl"))
|
|
253
253
|
except OSError:
|
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
"""Is a background task still pending when a session goes idle? (#1103)
|
|
2
|
+
|
|
3
|
+
The idle hook fires on "turn ended". A session that started a background
|
|
4
|
+
shell or monitor and ended its turn ("waiting on the suite, then I'll send the
|
|
5
|
+
verdict") is idle but NOT done: the harness wakes it again when the task
|
|
6
|
+
reports. Everything that reads idle as done (the parent's idle notice, the
|
|
7
|
+
worker-pane reap, the scheduled-task summary/``/exit`` pass) was wrong for it.
|
|
8
|
+
|
|
9
|
+
Signals, measured on a real Claude Code 2.1.302 session with a pending
|
|
10
|
+
``sleep 100`` and a pending Monitor:
|
|
11
|
+
|
|
12
|
+
* **Transcript.** A background start is a ``user`` row whose ``toolUseResult``
|
|
13
|
+
carries ``backgroundTaskId`` (Bash) or ``taskId`` (Monitor). The end is a
|
|
14
|
+
``queue-operation`` enqueue whose content is a ``<task-notification>`` with a
|
|
15
|
+
``<status>`` element. A Monitor's per-event notifications have NO
|
|
16
|
+
``<status>`` and are not terminal. Pending = started - terminated.
|
|
17
|
+
* **Pane.** The turn-end line renders ``✻ Worked for 3s · done 7:37 PM · 1 shell
|
|
18
|
+
still running`` and the footer ``⏵⏵ bypass permissions on · 1 shell``. At 30
|
|
19
|
+
columns the footer is truncated (``on ·``) but the turn-end line WRAPS rather
|
|
20
|
+
than truncates, so it is read across lines. Both are read only at their LIVE
|
|
21
|
+
position (directly above / below the last input box), never from scrollback.
|
|
22
|
+
|
|
23
|
+
The pane is authoritative when it is readable, the transcript when it is not.
|
|
24
|
+
The transcript is history: a task started before an ``/exit`` + ``--resume``
|
|
25
|
+
looks pending forever, while the pane shows what the harness believes right
|
|
26
|
+
now. Disagreement is logged.
|
|
27
|
+
|
|
28
|
+
Policy: **defer, bounded, and the bound releases a notice, never a kill.**
|
|
29
|
+
While tasks are pending the idle is swallowed; the harness re-wakes the session
|
|
30
|
+
when the last task reports, that turn ends in a fresh idle with zero pending,
|
|
31
|
+
and the ordinary notice goes out. A stuck task must not suppress forever, so
|
|
32
|
+
after :data:`DEFER_BOUND` one *qualified* parent notice is sent. The worker-pane
|
|
33
|
+
reap and the scheduled-task ``/exit`` are NEVER released by a timer: they stay
|
|
34
|
+
held for as long as a task may be running.
|
|
35
|
+
|
|
36
|
+
Uncertainty rule: *pending* wins every doubt. Unfamiliar task wording next to
|
|
37
|
+
"still running", a truncated footer with no turn-end line, an unparsable line
|
|
38
|
+
all read as **uncertain = hold** — a wrongly held session costs a late notice
|
|
39
|
+
(bounded, reported); a wrongly released one kills live work. Only "nothing
|
|
40
|
+
readable at all" (no agent pane, no transcript) behaves as before the gate.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from __future__ import annotations
|
|
44
|
+
|
|
45
|
+
import json
|
|
46
|
+
import os
|
|
47
|
+
import re
|
|
48
|
+
import time
|
|
49
|
+
import uuid
|
|
50
|
+
from dataclasses import dataclass, field
|
|
51
|
+
from pathlib import Path
|
|
52
|
+
|
|
53
|
+
#: How long an idle may be swallowed before one qualified notice goes out.
|
|
54
|
+
DEFER_BOUND = 30 * 60
|
|
55
|
+
|
|
56
|
+
_RULE = re.compile(r"^[─━\-]{3,}$")
|
|
57
|
+
#: Glyphs that open a transcript row (assistant text, user echo, tool result);
|
|
58
|
+
#: a continuation row of the turn-end line never starts with one.
|
|
59
|
+
_ROW_GLYPHS = ("⏺", "❯", "⎿", "─")
|
|
60
|
+
_TURN_END = re.compile(
|
|
61
|
+
r"✻\s.*?\bdone\s+\d{1,2}:\d{2}\s*(?:[AP]M)?\s*(?:·\s*)?(?P<rest>.*)$", re.IGNORECASE)
|
|
62
|
+
_STILL = re.compile(r"^(?P<frag>.*?)\s*\bstill\s+running\b", re.IGNORECASE)
|
|
63
|
+
_PIECE = re.compile(r"^(?P<n>\d+)\s+[A-Za-z][A-Za-z -]*$")
|
|
64
|
+
#: How many wrapped rows the turn-end line may occupy (20 columns wrap to 4).
|
|
65
|
+
_MAX_TURN_ROWS = 6
|
|
66
|
+
|
|
67
|
+
_TASK_STATUS = re.compile(r"<status>[^<]+</status>")
|
|
68
|
+
_TASK_ID = re.compile(r"<task-id>([^<]+)</task-id>")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class Pending:
|
|
73
|
+
"""What is known about a session's background work.
|
|
74
|
+
|
|
75
|
+
``count`` is ``None`` when unknown. With ``uncertain`` False that means
|
|
76
|
+
nothing was readable and callers behave as before; with ``uncertain`` True
|
|
77
|
+
the pane was readable but the parse was not certain, which holds.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
count: "int | None"
|
|
81
|
+
source: str # pane | transcript | unknown
|
|
82
|
+
transcript_ids: "list[str] | None" = None
|
|
83
|
+
pane_count: "int | None" = None
|
|
84
|
+
notes: list[str] = field(default_factory=list)
|
|
85
|
+
#: The pane shows the shape of background work but the parse is not
|
|
86
|
+
#: certain (new task-kind wording, truncated footer, wrap). Treated as
|
|
87
|
+
#: PENDING by every caller: a hold, never a reap (#1110 review).
|
|
88
|
+
uncertain: bool = False
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _config_dir() -> Path:
|
|
92
|
+
# Through the MODULE so a patched CONFIG_DIR is honored (see auth_expired).
|
|
93
|
+
from . import core
|
|
94
|
+
|
|
95
|
+
return Path(core.CONFIG_DIR)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def state_dir() -> Path:
|
|
99
|
+
return _config_dir() / "idle-deferred"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def events_path() -> Path:
|
|
103
|
+
return _config_dir() / "idle-deferred-events.jsonl"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def log_event(event: str, **fields) -> None:
|
|
107
|
+
"""Best-effort telemetry — never break the idle path."""
|
|
108
|
+
try:
|
|
109
|
+
path = events_path()
|
|
110
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
with open(path, "a") as f:
|
|
112
|
+
f.write(json.dumps({"ts": time.time(), "event": event, **fields}) + "\n")
|
|
113
|
+
except OSError:
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# ---------------------------------------------------------------------------
|
|
118
|
+
# Transcript signal
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def pending_from_transcript(path: Path) -> list[str]:
|
|
123
|
+
"""Background task ids started and not yet terminated, in start order."""
|
|
124
|
+
started: dict[str, None] = {}
|
|
125
|
+
with open(path, errors="replace") as f:
|
|
126
|
+
for line in f:
|
|
127
|
+
# Cheap prefilter: most rows are neither a start nor a notification.
|
|
128
|
+
if "backgroundTaskId" not in line and '"taskId"' not in line \
|
|
129
|
+
and "<task-notification>" not in line:
|
|
130
|
+
continue
|
|
131
|
+
try:
|
|
132
|
+
row = json.loads(line)
|
|
133
|
+
except ValueError:
|
|
134
|
+
continue
|
|
135
|
+
rtype = row.get("type")
|
|
136
|
+
if rtype == "queue-operation" and row.get("operation") == "enqueue":
|
|
137
|
+
content = row.get("content")
|
|
138
|
+
if isinstance(content, str) and "<task-notification>" in content \
|
|
139
|
+
and _TASK_STATUS.search(content):
|
|
140
|
+
m = _TASK_ID.search(content)
|
|
141
|
+
if m:
|
|
142
|
+
started.pop(m.group(1), None)
|
|
143
|
+
elif rtype == "user":
|
|
144
|
+
result = row.get("toolUseResult")
|
|
145
|
+
if isinstance(result, dict):
|
|
146
|
+
tid = result.get("backgroundTaskId") or result.get("taskId")
|
|
147
|
+
if isinstance(tid, str) and tid:
|
|
148
|
+
started[tid] = None
|
|
149
|
+
return list(started)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def find_transcript(session: str, conversation_id: str = "", cwd: str = "") -> "Path | None":
|
|
153
|
+
"""The live conversation's transcript: the id the hook was handed, else the
|
|
154
|
+
newest id recorded for the session (#871)."""
|
|
155
|
+
from .auth_expired import recorded_transcripts
|
|
156
|
+
from .history import locate_conversation
|
|
157
|
+
|
|
158
|
+
if conversation_id and cwd:
|
|
159
|
+
found = locate_conversation(conversation_id, cwd).found_at
|
|
160
|
+
if found:
|
|
161
|
+
return Path(found)
|
|
162
|
+
recorded = recorded_transcripts(session)
|
|
163
|
+
return recorded[-1] if recorded else None
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# ---------------------------------------------------------------------------
|
|
167
|
+
# Pane signal
|
|
168
|
+
# ---------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@dataclass
|
|
172
|
+
class PaneReading:
|
|
173
|
+
"""``status``: ok (``count`` is certain) | uncertain | unreadable."""
|
|
174
|
+
|
|
175
|
+
count: "int | None"
|
|
176
|
+
status: str
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _sum_pieces(frag: str) -> "int | None":
|
|
180
|
+
"""Total of ``N <kind>`` pieces, or ``None`` if any piece is not that shape.
|
|
181
|
+
|
|
182
|
+
The kind word is deliberately free text: new wording ("local agent",
|
|
183
|
+
"bash", "hook") must count, not read as zero.
|
|
184
|
+
"""
|
|
185
|
+
total = 0
|
|
186
|
+
pieces = [p.strip() for p in re.split(r",|\band\b", frag) if p.strip()]
|
|
187
|
+
if not pieces:
|
|
188
|
+
return None
|
|
189
|
+
for piece in pieces:
|
|
190
|
+
m = _PIECE.match(piece)
|
|
191
|
+
if not m:
|
|
192
|
+
return None
|
|
193
|
+
total += int(m.group("n"))
|
|
194
|
+
return total
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
#: Nouns that make a footer ``N <noun>`` segment a background task. The footer
|
|
198
|
+
#: has no "still running" anchor, so a bare count next to an unknown noun
|
|
199
|
+
#: ("2 MCP servers failed", "3 files changed") is NOT a task. That is a
|
|
200
|
+
#: different case from a segment we cannot parse at all (cut after the digit),
|
|
201
|
+
#: which is uncertain: the two are tested separately.
|
|
202
|
+
TASK_NOUNS = frozenset({
|
|
203
|
+
"shell", "monitor", "agent", "subagent", "task", "workflow", "bash", "hook",
|
|
204
|
+
"session", "local", "remote", "background",
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _is_task_piece(piece: str) -> bool:
|
|
209
|
+
words = re.findall(r"[a-z]+", piece.lower())
|
|
210
|
+
return any(w.rstrip("s") in TASK_NOUNS for w in words)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _footer_reading(rows: list[str]) -> PaneReading:
|
|
214
|
+
"""The live mode line (rows BELOW the input box only — a footer quoted in
|
|
215
|
+
scrollback is above it and can never be mistaken for this one).
|
|
216
|
+
|
|
217
|
+
``count`` 0 and ``None`` are different values: a digit-bearing segment we
|
|
218
|
+
cannot parse (``· 1``, ``· 1 shell, 1``) or a line cut off by the width is
|
|
219
|
+
UNCERTAIN, never zero.
|
|
220
|
+
"""
|
|
221
|
+
mode = next((r for r in rows if "⏵⏵" in r), None)
|
|
222
|
+
if mode is None:
|
|
223
|
+
return PaneReading(None, "uncertain")
|
|
224
|
+
if mode.rstrip().endswith(("·", "…")):
|
|
225
|
+
return PaneReading(None, "uncertain") # truncated: a count may be cut off
|
|
226
|
+
total = 0
|
|
227
|
+
for segment in mode.split("·")[1:]:
|
|
228
|
+
if not re.search(r"\d", segment):
|
|
229
|
+
continue # "← for agents" and friends carry no count
|
|
230
|
+
pieces = [p.strip() for p in re.split(r",|\band\b", segment) if p.strip()]
|
|
231
|
+
for piece in pieces:
|
|
232
|
+
m = _PIECE.match(piece)
|
|
233
|
+
if m is None:
|
|
234
|
+
return PaneReading(None, "uncertain")
|
|
235
|
+
if _is_task_piece(piece):
|
|
236
|
+
total += int(m.group("n"))
|
|
237
|
+
return PaneReading(total, "ok")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
#: Text that looks like pending background work when no input box was found
|
|
241
|
+
#: (tall draft, plan/permission/resume dialog over the box): hold, don't proceed.
|
|
242
|
+
_PENDING_LOOKING = re.compile(
|
|
243
|
+
r"still\s+running|✻[^\n]*\bdone\s+\d{1,2}:\d{2}|⏵⏵[^\n]*·\s*\d", re.IGNORECASE)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def parse_pane(text: str) -> PaneReading:
|
|
247
|
+
"""Background tasks the pane says are running.
|
|
248
|
+
|
|
249
|
+
Anchored on the LIVE structure: the last input box (rule / ``❯`` / rule).
|
|
250
|
+
The turn-end line is the ``✻ … done 7:37 PM · 1 shell still running`` block
|
|
251
|
+
directly above it (it wraps over several rows on a narrow pane); anything
|
|
252
|
+
else on screen — an older turn line, a quoted footer — is history and is
|
|
253
|
+
ignored. A turn with no turn-end line (interrupted, non-turn wake) falls
|
|
254
|
+
back to the live footer, which at narrow widths truncates; a truncated
|
|
255
|
+
footer is *uncertain*, never zero.
|
|
256
|
+
"""
|
|
257
|
+
rows = [r.rstrip() for r in text.splitlines() if r.strip()][-60:]
|
|
258
|
+
box = next((i for i in range(len(rows) - 3, -1, -1)
|
|
259
|
+
if _RULE.match(rows[i].strip()) and rows[i + 1].lstrip().startswith("❯")
|
|
260
|
+
and _RULE.match(rows[i + 2].strip())), None)
|
|
261
|
+
if box is None:
|
|
262
|
+
# No box: a bare shell or an exited agent has no signal and stays
|
|
263
|
+
# "unreadable"; any pending-looking text (a dialog or a tall draft over
|
|
264
|
+
# a live task) must HOLD, never proceed to the reap.
|
|
265
|
+
looks = _PENDING_LOOKING.search("\n".join(rows))
|
|
266
|
+
return PaneReading(None, "uncertain" if looks else "unreadable")
|
|
267
|
+
footer = _footer_reading(rows[box + 3:])
|
|
268
|
+
|
|
269
|
+
block = None
|
|
270
|
+
for j in range(box - 1, max(box - 1 - _MAX_TURN_ROWS, -1), -1):
|
|
271
|
+
raw = rows[j]
|
|
272
|
+
if raw.startswith("✻"): # column 0: tool output quoting one is indented
|
|
273
|
+
block = " ".join(r.strip() for r in rows[j:box])
|
|
274
|
+
break
|
|
275
|
+
if not raw[:1].isspace() or raw.lstrip().startswith(_ROW_GLYPHS):
|
|
276
|
+
break # a continuation row is indented and opens with no glyph
|
|
277
|
+
m = _TURN_END.search(block) if block else None
|
|
278
|
+
if m is None:
|
|
279
|
+
return footer
|
|
280
|
+
|
|
281
|
+
still = _STILL.match(m.group("rest"))
|
|
282
|
+
if not still:
|
|
283
|
+
# A complete turn-end line without "still running": nothing pending
|
|
284
|
+
# on the turn line; the footer can only add to that.
|
|
285
|
+
# (A footer we could not parse does not undo a complete turn line.)
|
|
286
|
+
return PaneReading(footer.count if footer.status == "ok" else 0, "ok")
|
|
287
|
+
turn = _sum_pieces(still.group("frag"))
|
|
288
|
+
if turn is None:
|
|
289
|
+
return PaneReading(None, "uncertain")
|
|
290
|
+
return PaneReading(max(turn, footer.count if footer.status == "ok" else 0), "ok")
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def pane_background_count(text: str) -> "int | None":
|
|
294
|
+
"""Certain count, or ``None`` (unreadable or uncertain)."""
|
|
295
|
+
reading = parse_pane(text)
|
|
296
|
+
return reading.count if reading.status == "ok" else None
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _capture(session: str, pane: int) -> "str | None":
|
|
300
|
+
from . import pane_manager
|
|
301
|
+
|
|
302
|
+
try:
|
|
303
|
+
return pane_manager.capture_pane(session, pane, lines=60)
|
|
304
|
+
except Exception: # noqa: BLE001 — an unreadable pane is "unknown", not an error
|
|
305
|
+
return None
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
# ---------------------------------------------------------------------------
|
|
309
|
+
# The predicate
|
|
310
|
+
# ---------------------------------------------------------------------------
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def evaluate(session: str, pane: int = 0, conversation_id: str = "", cwd: str = "") -> Pending:
|
|
314
|
+
"""How many background tasks is *session*.*pane* still running?"""
|
|
315
|
+
notes: list[str] = []
|
|
316
|
+
ids: "list[str] | None" = None
|
|
317
|
+
try:
|
|
318
|
+
transcript = find_transcript(session, conversation_id, cwd)
|
|
319
|
+
if transcript is not None:
|
|
320
|
+
ids = pending_from_transcript(transcript)
|
|
321
|
+
else:
|
|
322
|
+
notes.append("no_transcript")
|
|
323
|
+
except Exception as exc: # noqa: BLE001
|
|
324
|
+
notes.append(f"transcript_error:{exc}")
|
|
325
|
+
|
|
326
|
+
captured = _capture(session, pane)
|
|
327
|
+
reading = parse_pane(captured) if captured is not None else PaneReading(None, "unreadable")
|
|
328
|
+
|
|
329
|
+
if reading.status == "ok":
|
|
330
|
+
if ids and reading.count == 0:
|
|
331
|
+
notes.append("stale_transcript")
|
|
332
|
+
elif ids is not None and not ids and reading.count:
|
|
333
|
+
notes.append("pane_only")
|
|
334
|
+
return Pending(reading.count, "pane", ids, reading.count, notes)
|
|
335
|
+
if reading.status == "uncertain":
|
|
336
|
+
# The pane shows the shape of background work we could not count.
|
|
337
|
+
# A transcript with live ids is still evidence; otherwise HOLD.
|
|
338
|
+
notes.append("pane_uncertain")
|
|
339
|
+
if ids:
|
|
340
|
+
return Pending(len(ids), "transcript", ids, None, notes)
|
|
341
|
+
return Pending(None, "pane", ids, None, notes, uncertain=True)
|
|
342
|
+
notes.append("pane_unreadable")
|
|
343
|
+
if ids is not None:
|
|
344
|
+
return Pending(len(ids), "transcript", ids, None, notes)
|
|
345
|
+
return Pending(None, "unknown", None, None, notes)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
# ---------------------------------------------------------------------------
|
|
349
|
+
# Deferral state + gate
|
|
350
|
+
# ---------------------------------------------------------------------------
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def _marker(session: str, pane: int) -> Path:
|
|
354
|
+
return state_dir() / f"{session}.{pane}.json"
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def read_marker(session: str, pane: int) -> "dict | None":
|
|
358
|
+
try:
|
|
359
|
+
data = json.loads(_marker(session, pane).read_text())
|
|
360
|
+
except (OSError, ValueError):
|
|
361
|
+
return None
|
|
362
|
+
return data if isinstance(data, dict) else None
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _write_marker(session: str, pane: int, data: dict) -> None:
|
|
366
|
+
path = _marker(session, pane)
|
|
367
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
368
|
+
# One tmp name per WRITER: hook-vs-hook and hook-vs-tick race on the same
|
|
369
|
+
# marker, and a shared name made the loser's replace() raise.
|
|
370
|
+
tmp = path.with_name(f"{path.stem}.{os.getpid()}.{uuid.uuid4().hex[:8]}.tmp")
|
|
371
|
+
try:
|
|
372
|
+
tmp.write_text(json.dumps(data))
|
|
373
|
+
tmp.replace(path)
|
|
374
|
+
finally:
|
|
375
|
+
tmp.unlink(missing_ok=True)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def clear_marker(session: str, pane: int) -> None:
|
|
379
|
+
try:
|
|
380
|
+
_marker(session, pane).unlink()
|
|
381
|
+
except OSError:
|
|
382
|
+
pass
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
GATE_FAILURE_WINDOW = 3600
|
|
386
|
+
GATE_FAILURE_THRESHOLD = 3
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def recent_gate_failures(now: "float | None" = None) -> list[dict]:
|
|
390
|
+
"""``gate_failed`` / ``gate_unusable`` events in the last hour, if there are
|
|
391
|
+
enough of them to be a persistent fault rather than a blip.
|
|
392
|
+
|
|
393
|
+
A failing gate HOLDS every path that would kill, so a persistent one keeps
|
|
394
|
+
worker panes alive silently; this is the owner-visible signal.
|
|
395
|
+
"""
|
|
396
|
+
now = time.time() if now is None else now
|
|
397
|
+
try:
|
|
398
|
+
lines = events_path().read_text(errors="replace").splitlines()
|
|
399
|
+
except OSError:
|
|
400
|
+
return []
|
|
401
|
+
found = []
|
|
402
|
+
for line in lines[-500:]:
|
|
403
|
+
try:
|
|
404
|
+
row = json.loads(line)
|
|
405
|
+
except ValueError:
|
|
406
|
+
continue
|
|
407
|
+
if not isinstance(row, dict) or row.get("event") not in ("gate_failed", "gate_unusable"):
|
|
408
|
+
continue
|
|
409
|
+
try:
|
|
410
|
+
age = now - float(row.get("ts", 0))
|
|
411
|
+
except (TypeError, ValueError):
|
|
412
|
+
continue
|
|
413
|
+
# inf / NaN / 1e308 / far-future stamps are not "recent"; an hour of
|
|
414
|
+
# clock skew either way is tolerated
|
|
415
|
+
if -GATE_FAILURE_WINDOW <= age <= GATE_FAILURE_WINDOW:
|
|
416
|
+
found.append(row)
|
|
417
|
+
return found if len(found) >= GATE_FAILURE_THRESHOLD else []
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def qualifier(count: "int | None", waited: float) -> str:
|
|
421
|
+
what = ("background work may still be running" if not count else
|
|
422
|
+
f"{count} background task{'' if count == 1 else 's'} still running")
|
|
423
|
+
return f"is idle, but {what} (waited {int(waited // 60)}m; not necessarily finished)"
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
#: A marker untouched for longer than the bound belongs to a session that is
|
|
427
|
+
#: gone (a same-name session reborn must not inherit its clock). Deliberately
|
|
428
|
+
#: the bound itself, not shorter: a task that wakes the session every 12
|
|
429
|
+
#: minutes must still reach it with no watchdog loaded. Identity is the
|
|
430
|
+
#: conversation id when the hook supplies one, and a call that carries an id is
|
|
431
|
+
#: NEVER restarted by a gap (only by a different id); the gap applies only to a
|
|
432
|
+
#: call with no id.
|
|
433
|
+
MARKER_GRACE = DEFER_BOUND
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def reap_path(session: str, pane: int) -> bool:
|
|
437
|
+
"""Does an idle here lead to a KILL (worker-pane reap, scheduled-task exit)?
|
|
438
|
+
|
|
439
|
+
The bound may release a *notice*; it must never release a kill — a live
|
|
440
|
+
task is not ended by a timer.
|
|
441
|
+
"""
|
|
442
|
+
return pane != 0 or (_config_dir() / "tasks" / f"{session}.json").exists()
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def gate(
|
|
446
|
+
session: str, pane: int = 0, conversation_id: str = "", cwd: str = "",
|
|
447
|
+
now: "float | None" = None, pending: "Pending | None" = None,
|
|
448
|
+
) -> dict:
|
|
449
|
+
"""Decide what an idle event should do. Pure of side effects but the marker.
|
|
450
|
+
|
|
451
|
+
``action``: ``defer`` (swallow — the harness re-wakes the session),
|
|
452
|
+
``proceed`` (behave as before; ONLY when nothing is pending, or nothing at
|
|
453
|
+
all could be read), or ``qualify`` (parent notice only, past the bound).
|
|
454
|
+
A pane whose idle would reap or ``/exit`` is never released by the bound.
|
|
455
|
+
"""
|
|
456
|
+
now = time.time() if now is None else now
|
|
457
|
+
pending = pending or evaluate(session, pane, conversation_id, cwd)
|
|
458
|
+
out = {"action": "proceed", "pending": pending.count, "source": pending.source,
|
|
459
|
+
"uncertain": pending.uncertain, "notes": pending.notes, "text": ""}
|
|
460
|
+
|
|
461
|
+
held = pending.uncertain or bool(pending.count)
|
|
462
|
+
if pending.count is None and not pending.uncertain:
|
|
463
|
+
log_event("unknown", session=session, pane=pane, notes=pending.notes)
|
|
464
|
+
return out
|
|
465
|
+
if not held:
|
|
466
|
+
if read_marker(session, pane):
|
|
467
|
+
clear_marker(session, pane)
|
|
468
|
+
log_event("cleared", session=session, pane=pane)
|
|
469
|
+
if "stale_transcript" in pending.notes:
|
|
470
|
+
log_event("stale_transcript", session=session, pane=pane,
|
|
471
|
+
ids=pending.transcript_ids)
|
|
472
|
+
return out
|
|
473
|
+
|
|
474
|
+
marker = read_marker(session, pane)
|
|
475
|
+
if marker is not None and (
|
|
476
|
+
(not conversation_id
|
|
477
|
+
and now - float(marker.get("last_seen_at", now)) > MARKER_GRACE)
|
|
478
|
+
or (conversation_id and marker.get("conversation_id")
|
|
479
|
+
and marker["conversation_id"] != conversation_id)
|
|
480
|
+
):
|
|
481
|
+
marker = None # a different incarnation of this name: fresh clock
|
|
482
|
+
marker = marker or {"first_deferred_at": now, "qualified": False}
|
|
483
|
+
marker.update(count=pending.count, uncertain=pending.uncertain,
|
|
484
|
+
conversation_id=conversation_id, cwd=cwd, last_seen_at=now)
|
|
485
|
+
waited = now - float(marker.get("first_deferred_at", now))
|
|
486
|
+
if waited >= DEFER_BOUND and not marker.get("qualified") and not reap_path(session, pane):
|
|
487
|
+
marker["qualified"] = True
|
|
488
|
+
out.update(action="qualify", text=qualifier(pending.count, waited))
|
|
489
|
+
log_event("qualified", session=session, pane=pane, count=pending.count,
|
|
490
|
+
waited=int(waited))
|
|
491
|
+
else:
|
|
492
|
+
out["action"] = "defer"
|
|
493
|
+
log_event("deferred", session=session, pane=pane, count=pending.count,
|
|
494
|
+
source=pending.source, uncertain=pending.uncertain)
|
|
495
|
+
_write_marker(session, pane, marker)
|
|
496
|
+
return out
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def tick(now: "float | None" = None) -> dict:
|
|
500
|
+
"""Watchdog stage: the bound must fire even if no further idle event does.
|
|
501
|
+
|
|
502
|
+
A stuck background shell never wakes its session, so the hook alone would
|
|
503
|
+
suppress forever. This sweep re-evaluates each deferred session, keeps the
|
|
504
|
+
marker fresh, and past the bound sends the one qualified notice — for a
|
|
505
|
+
worker pane to its owning pane 0, for a pane-0 session to its parent. The
|
|
506
|
+
``qualified`` flag is set only after the enqueue succeeded; a failed one
|
|
507
|
+
retries next tick. The session itself stays held either way.
|
|
508
|
+
"""
|
|
509
|
+
from . import inbox, prompt_router, services
|
|
510
|
+
from .cohort import session_exists
|
|
511
|
+
|
|
512
|
+
now = time.time() if now is None else now
|
|
513
|
+
result: dict = {"qualified": [], "cleared": []}
|
|
514
|
+
try:
|
|
515
|
+
markers = sorted(state_dir().glob("*.json"))
|
|
516
|
+
except OSError:
|
|
517
|
+
return result
|
|
518
|
+
for path in markers:
|
|
519
|
+
session, _, pane_s = path.stem.rpartition(".")
|
|
520
|
+
if not session or not pane_s.isdigit():
|
|
521
|
+
continue
|
|
522
|
+
pane = int(pane_s)
|
|
523
|
+
marker = read_marker(session, pane)
|
|
524
|
+
if marker is None:
|
|
525
|
+
continue
|
|
526
|
+
if not session_exists(session):
|
|
527
|
+
clear_marker(session, pane)
|
|
528
|
+
result["cleared"].append(session)
|
|
529
|
+
continue
|
|
530
|
+
pending = evaluate(session, pane, marker.get("conversation_id", ""),
|
|
531
|
+
marker.get("cwd", ""))
|
|
532
|
+
if pending.count is None and not pending.uncertain:
|
|
533
|
+
continue # nothing readable this tick: keep the marker, decide next tick
|
|
534
|
+
if not (pending.uncertain or pending.count):
|
|
535
|
+
clear_marker(session, pane)
|
|
536
|
+
result["cleared"].append(session)
|
|
537
|
+
continue
|
|
538
|
+
marker.update(count=pending.count, uncertain=pending.uncertain, last_seen_at=now)
|
|
539
|
+
waited = now - float(marker.get("first_deferred_at", now))
|
|
540
|
+
if waited < DEFER_BOUND or marker.get("qualified") or marker.get("unroutable"):
|
|
541
|
+
_write_marker(session, pane, marker)
|
|
542
|
+
continue
|
|
543
|
+
resolved = prompt_router.resolve_parent(session, pane)
|
|
544
|
+
if not resolved or services.is_service_session(session):
|
|
545
|
+
marker["unroutable"] = True # nobody to tell; stated, not "sent"
|
|
546
|
+
_write_marker(session, pane, marker)
|
|
547
|
+
log_event("unroutable", session=session, pane=pane)
|
|
548
|
+
continue
|
|
549
|
+
try:
|
|
550
|
+
inbox.enqueue(to=resolved[0], text=qualifier(pending.count, waited),
|
|
551
|
+
kind="idle", sender=session)
|
|
552
|
+
except (ValueError, OSError) as exc:
|
|
553
|
+
log_event("qualify_failed", session=session, error=str(exc))
|
|
554
|
+
_write_marker(session, pane, marker)
|
|
555
|
+
continue
|
|
556
|
+
marker["qualified"] = True
|
|
557
|
+
_write_marker(session, pane, marker)
|
|
558
|
+
log_event("qualified", session=session, pane=pane, count=pending.count,
|
|
559
|
+
waited=int(waited), via="tick")
|
|
560
|
+
result["qualified"].append(session)
|
|
561
|
+
return result
|
|
@@ -20,6 +20,7 @@ import urllib.request
|
|
|
20
20
|
from pathlib import Path
|
|
21
21
|
|
|
22
22
|
from . import pane_manager
|
|
23
|
+
from .config import voice_enabled
|
|
23
24
|
from .core import (
|
|
24
25
|
_get_portal_url,
|
|
25
26
|
_output_json,
|
|
@@ -275,6 +276,12 @@ def cmd_say(args) -> int:
|
|
|
275
276
|
|
|
276
277
|
config = load_config()
|
|
277
278
|
tts_config = config.get("tts", {})
|
|
279
|
+
if not voice_enabled(tts_config.get("backend", "default")):
|
|
280
|
+
if json_mode:
|
|
281
|
+
_output_json({"success": True, "sink": None, "disabled": True, "error": None})
|
|
282
|
+
else:
|
|
283
|
+
print("TTS is disabled (tts.backend: none) — nothing spoken.")
|
|
284
|
+
return 0
|
|
278
285
|
# Voice priority: CLI flag > .agentwire.yml > global config default
|
|
279
286
|
voice = args.voice or get_voice_from_config() or tts_config.get("default_voice", "default")
|
|
280
287
|
exaggeration = args.exaggeration if args.exaggeration is not None else tts_config.get("exaggeration", 0.5)
|