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.
Files changed (663) hide show
  1. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/PKG-INFO +1 -1
  2. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/__init__.py +1 -1
  3. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/agents/tmux.py +2 -2
  4. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/auth_expired.py +4 -4
  5. agentwire_dev-1.72.0/agentwire/background_tasks.py +561 -0
  6. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels_cli.py +7 -0
  7. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/cohort.py +43 -0
  8. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/config.py +49 -6
  9. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/core.py +71 -7
  10. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/doctor_cli.py +260 -39
  11. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/instructions.py +5 -7
  12. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/history.py +17 -11
  13. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/history_migrate.py +9 -9
  14. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +3011 -207
  15. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +3011 -204
  16. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +3047 -217
  17. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +3011 -204
  18. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/containers.yaml +2 -1
  19. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/core.yaml +17 -12
  20. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/git.yaml +10 -5
  21. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/outbound.yaml +2 -1
  22. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +3011 -204
  23. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/idle-handler.sh +70 -1
  24. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks_cli.py +154 -50
  25. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/inbox.py +227 -29
  26. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/limits_cli.py +178 -27
  27. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_core.py +49 -1
  28. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/msg_cli.py +29 -0
  29. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/notify_cli.py +47 -0
  30. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/onboarding.py +1 -0
  31. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/prompt_router.py +70 -2
  32. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/projects.py +1 -1
  33. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/sessions_admin.py +3 -3
  34. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/voice.py +10 -1
  35. agentwire_dev-1.72.0/agentwire/safety/_core.py +7338 -0
  36. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/provenance.py +66 -0
  37. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/rule_baselines.json +7 -1
  38. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety_commands.py +81 -22
  39. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/security.py +96 -0
  40. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/server.py +48 -18
  41. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/services.py +1 -1
  42. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/session_cli.py +3 -2
  43. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/session_ready.py +175 -15
  44. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/stt_server.py +2 -2
  45. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/kokoro_server.py +2 -2
  46. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts_cli.py +23 -15
  47. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts_server.py +6 -2
  48. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/paths.py +5 -0
  49. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_status.py +8 -0
  50. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/deployment/remote-machines.md +8 -0
  51. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/damage-control.md +538 -5
  52. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/troubleshooting.md +92 -0
  53. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/fan-out-cohorts.md +6 -0
  54. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/messaging.md +114 -3
  55. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/prompt-routing.md +23 -1
  56. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/usage-limit-recovery.md +31 -0
  57. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice/shim-contract.md +14 -0
  58. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/conftest.py +25 -0
  59. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_30_shell.txt +9 -0
  60. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_agent.txt +7 -0
  61. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_done.txt +12 -0
  62. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_interrupted.txt +8 -0
  63. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_monitor.txt +12 -0
  64. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_quoted_footer.txt +22 -0
  65. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_second_notice.txt +8 -0
  66. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_shell.txt +15 -0
  67. agentwire_dev-1.72.0/tests/fixtures/background_tasks/pane_80_shell_and_monitor.txt +5 -0
  68. agentwire_dev-1.72.0/tests/fixtures/background_tasks/transcript_bash_done.jsonl +2 -0
  69. agentwire_dev-1.72.0/tests/fixtures/background_tasks/transcript_bash_pending.jsonl +1 -0
  70. agentwire_dev-1.72.0/tests/fixtures/background_tasks/transcript_monitor_done.jsonl +6 -0
  71. agentwire_dev-1.72.0/tests/fixtures/background_tasks/transcript_monitor_events.jsonl +5 -0
  72. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/home_guard.py +36 -14
  73. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_send_verified_tmux.py +73 -9
  74. agentwire_dev-1.72.0/tests/unit/test_allowlist_never_reopens_guarded.py +221 -0
  75. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_audit_outcomes.py +2 -2
  76. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_auth_expired.py +1 -1
  77. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_auth_expired_dispatch.py +1 -1
  78. agentwire_dev-1.72.0/tests/unit/test_background_tasks.py +651 -0
  79. agentwire_dev-1.72.0/tests/unit/test_background_tasks_review.py +103 -0
  80. agentwire_dev-1.72.0/tests/unit/test_background_tasks_review2.py +88 -0
  81. agentwire_dev-1.72.0/tests/unit/test_background_tasks_review3.py +30 -0
  82. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cli_commands.py +1 -1
  83. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cohort.py +90 -0
  84. agentwire_dev-1.72.0/tests/unit/test_compound_command_positions.py +345 -0
  85. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_config.py +1 -1
  86. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_control_plane_protection.py +89 -0
  87. agentwire_dev-1.72.0/tests/unit/test_control_plane_writers.py +1031 -0
  88. agentwire_dev-1.72.0/tests/unit/test_damage_control_eval_position.py +1098 -0
  89. agentwire_dev-1.72.0/tests/unit/test_damage_control_flag_order.py +278 -0
  90. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_hooks.py +7 -5
  91. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_payload_anchoring.py +18 -19
  92. agentwire_dev-1.72.0/tests/unit/test_damage_control_word_spans.py +283 -0
  93. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_orphaned_history.py +1 -1
  94. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_handoff_instructions.py +2 -2
  95. agentwire_dev-1.72.0/tests/unit/test_heredoc_marker_liveness.py +322 -0
  96. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_history_migrate.py +1 -1
  97. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_history_migrate_cli.py +1 -1
  98. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_home_isolation.py +42 -0
  99. agentwire_dev-1.72.0/tests/unit/test_hook_fail_closed.py +359 -0
  100. agentwire_dev-1.72.0/tests/unit/test_hook_link_guard.py +243 -0
  101. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_hooks_install.py +18 -13
  102. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_inbox.py +457 -10
  103. agentwire_dev-1.72.0/tests/unit/test_mcp_nonblocking.py +172 -0
  104. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_mcp_server.py +58 -12
  105. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_msg_cli.py +2 -0
  106. agentwire_dev-1.72.0/tests/unit/test_prompt_router_dedup.py +133 -0
  107. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_restart_cli.py +1 -1
  108. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_deployment.py +2 -2
  109. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_heal.py +20 -0
  110. agentwire_dev-1.72.0/tests/unit/test_scan_budget.py +365 -0
  111. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_ready.py +288 -22
  112. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_skill_install.py +4 -6
  113. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_unattended_allow.py +2 -2
  114. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_body_delivery.py +1 -1
  115. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_kind.py +1 -0
  116. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_layer.py +4 -1
  117. agentwire_dev-1.72.0/tests/unit/test_voice_off_and_shim_bind.py +242 -0
  118. agentwire_dev-1.72.0/tests/unit/test_watchdog_stages.py +144 -0
  119. agentwire_dev-1.71.0/agentwire/safety/_core.py +0 -4532
  120. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.agentwire.yml.example +0 -0
  121. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.claude/commands/handoff.md +0 -0
  122. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.claude/skills/wiki/SKILL.md +0 -0
  123. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/FUNDING.yml +0 -0
  124. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  125. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  126. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
  127. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  128. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/workflows/pytest.yml +0 -0
  129. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/workflows/ruff.yml +0 -0
  130. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/workflows/security.yml +0 -0
  131. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.github/workflows/tts-smoke.yml +0 -0
  132. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/.gitignore +0 -0
  133. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/AGENTS.md +0 -0
  134. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/CODE_OF_CONDUCT.md +0 -0
  135. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/CONTRIBUTING.md +0 -0
  136. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/Dockerfile.local +0 -0
  137. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/LICENSE +0 -0
  138. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/README.md +0 -0
  139. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/RELEASING.md +0 -0
  140. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/SECURITY.md +0 -0
  141. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/SPONSORS.md +0 -0
  142. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/__main__.py +0 -0
  143. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/activity_cli.py +0 -0
  144. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/agents/__init__.py +0 -0
  145. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/agents/base.py +0 -0
  146. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/alerts_cli.py +0 -0
  147. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/beta.py +0 -0
  148. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/buddy_cli.py +0 -0
  149. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/cached_status.py +0 -0
  150. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/__init__.py +0 -0
  151. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/base.py +0 -0
  152. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/email.py +0 -0
  153. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/push.py +0 -0
  154. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/channels/quo.py +0 -0
  155. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/chrome_tabs.py +0 -0
  156. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/completion.py +0 -0
  157. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/config_cli.py +0 -0
  158. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/__init__.py +0 -0
  159. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/cli.py +0 -0
  160. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/inbox.py +0 -0
  161. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/minutes.py +0 -0
  162. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/state.py +0 -0
  163. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/council/view.py +0 -0
  164. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/devices.py +0 -0
  165. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/diff_cli.py +0 -0
  166. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/doctor_voice.py +0 -0
  167. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/ensure_cli.py +0 -0
  168. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/fetch.py +0 -0
  169. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/fleet_activity.py +0 -0
  170. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/fleet_alerts.py +0 -0
  171. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/__init__.py +0 -0
  172. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/git_state.py +0 -0
  173. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/parser.py +0 -0
  174. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/renderer.py +0 -0
  175. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff/schema.py +0 -0
  176. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/handoff_cli.py +0 -0
  177. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/history_cli.py +0 -0
  178. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/__init__.py +0 -0
  179. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/agentwire-permission.sh +0 -0
  180. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/__init__.py +0 -0
  181. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
  182. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
  183. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
  184. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
  185. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
  186. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
  187. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
  188. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
  189. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
  190. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
  191. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/mcp-tools.yaml +0 -0
  192. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/payloads.yaml +0 -0
  193. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
  194. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
  195. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/outcome_logger.py +0 -0
  196. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/hooks/queue-processor.sh +0 -0
  197. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/listen.py +0 -0
  198. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/locking.py +0 -0
  199. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/machine_cli.py +0 -0
  200. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_channels.py +0 -0
  201. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_chrome.py +0 -0
  202. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_cli.py +0 -0
  203. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_council.py +0 -0
  204. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_desktop.py +0 -0
  205. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_handoff.py +0 -0
  206. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_history.py +0 -0
  207. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_listen.py +0 -0
  208. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_lock.py +0 -0
  209. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_machine.py +0 -0
  210. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_msg.py +0 -0
  211. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_notify.py +0 -0
  212. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_pane.py +0 -0
  213. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_projects.py +0 -0
  214. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_scheduler.py +0 -0
  215. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_scratchpad.py +0 -0
  216. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_server.py +0 -0
  217. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_services.py +0 -0
  218. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_session.py +0 -0
  219. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_status.py +0 -0
  220. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_task.py +0 -0
  221. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_tunnels.py +0 -0
  222. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_voice.py +0 -0
  223. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_wiki.py +0 -0
  224. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/mcp_worktree.py +0 -0
  225. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/network.py +0 -0
  226. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/palette_cli.py +0 -0
  227. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/pane_cli.py +0 -0
  228. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/pane_manager.py +0 -0
  229. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/portal_cli.py +0 -0
  230. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/project_config.py +0 -0
  231. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/projects.py +0 -0
  232. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/prompts_cli.py +0 -0
  233. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/push_cli.py +0 -0
  234. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/push_store.py +0 -0
  235. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/repo_cli.py +0 -0
  236. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/research.py +0 -0
  237. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/restart_cli.py +0 -0
  238. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/role_prompts.py +0 -0
  239. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/__init__.py +0 -0
  240. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/agentwire.md +0 -0
  241. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/anchor.md +0 -0
  242. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/chatbot.md +0 -0
  243. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/contributor.md +0 -0
  244. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/correspondent.md +0 -0
  245. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-brain.md +0 -0
  246. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-conscience.md +0 -0
  247. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-critic.md +0 -0
  248. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-devils-advocate.md +0 -0
  249. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-gut.md +0 -0
  250. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-historian.md +0 -0
  251. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-member.md +0 -0
  252. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/council-orchestrator.md +0 -0
  253. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/init.md +0 -0
  254. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/notifications.md +0 -0
  255. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/orchestrator.md +0 -0
  256. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/reviewer-worktree.md +0 -0
  257. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/reviewer.md +0 -0
  258. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/shared-checkout.md +0 -0
  259. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/soul.md +0 -0
  260. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/task-runner.md +0 -0
  261. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/voice.md +0 -0
  262. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/worker-worktree.md +0 -0
  263. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles/worker.md +0 -0
  264. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/roles_cli.py +0 -0
  265. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/__init__.py +0 -0
  266. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/artifacts.py +0 -0
  267. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/config.py +0 -0
  268. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/council.py +0 -0
  269. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/desktop.py +0 -0
  270. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/history.py +0 -0
  271. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/machines.py +0 -0
  272. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/notify.py +0 -0
  273. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/palette.py +0 -0
  274. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/permission.py +0 -0
  275. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/push.py +0 -0
  276. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/safety.py +0 -0
  277. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/scheduler.py +0 -0
  278. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/scratchpad.py +0 -0
  279. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/routes/sessions.py +0 -0
  280. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/__init__.py +0 -0
  281. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/audit.py +0 -0
  282. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety/lint.py +0 -0
  283. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety_cli.py +0 -0
  284. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/safety_notify.py +0 -0
  285. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/__init__.py +0 -0
  286. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/dispatch.py +0 -0
  287. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/gates.py +0 -0
  288. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/loop.py +0 -0
  289. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/models.py +0 -0
  290. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/report.py +0 -0
  291. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/schedule.py +0 -0
  292. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/state.py +0 -0
  293. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler/zombie.py +0 -0
  294. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scheduler_cli.py +0 -0
  295. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/scratchpad.py +0 -0
  296. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/send_cli.py +0 -0
  297. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/session_context.py +0 -0
  298. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/ssh.py +0 -0
  299. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
  300. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
  301. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
  302. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
  303. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
  304. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/announcements.json +0 -0
  305. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/apple-touch-icon.png +0 -0
  306. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/css/desktop.css +0 -0
  307. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/css/mobile.css +0 -0
  308. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/favicon-32.png +0 -0
  309. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/favicon-64.png +0 -0
  310. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/bear.webp +0 -0
  311. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/cat.webp +0 -0
  312. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/crown.webp +0 -0
  313. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
  314. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
  315. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
  316. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/deer.webp +0 -0
  317. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/drone.webp +0 -0
  318. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
  319. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/fox.webp +0 -0
  320. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
  321. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/horse.webp +0 -0
  322. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/lion.webp +0 -0
  323. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
  324. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/robot.webp +0 -0
  325. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
  326. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
  327. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/img/icon-192.png +0 -0
  328. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/img/icon-512.png +0 -0
  329. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/.gitkeep +0 -0
  330. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/announcement-modal.js +0 -0
  331. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/api.js +0 -0
  332. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/artifact-window.js +0 -0
  333. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/card-terminal.js +0 -0
  334. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/collage.js +0 -0
  335. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/command-palette.js +0 -0
  336. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/council-window.js +0 -0
  337. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/dead-key-residue.js +0 -0
  338. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/desktop-manager.js +0 -0
  339. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/desktop.js +0 -0
  340. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/help-modal.js +0 -0
  341. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/hotkeys.js +0 -0
  342. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/icon-manager.js +0 -0
  343. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/lineage.js +0 -0
  344. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/mobile.js +0 -0
  345. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/notification-prefs.js +0 -0
  346. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/notifications-panel.js +0 -0
  347. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/ptt.js +0 -0
  348. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/push-client.js +0 -0
  349. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/review-window.js +0 -0
  350. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/safety-shared.js +0 -0
  351. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/safety-window.js +0 -0
  352. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/scratchpad.js +0 -0
  353. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/service-classification.js +0 -0
  354. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-hud-controller.js +0 -0
  355. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-hud-notices.js +0 -0
  356. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-hud-spawn.js +0 -0
  357. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-hud.js +0 -0
  358. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-id.js +0 -0
  359. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/session-window.js +0 -0
  360. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/shortcuts.js +0 -0
  361. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
  362. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/config-section.js +0 -0
  363. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/council-section.js +0 -0
  364. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
  365. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
  366. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
  367. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
  368. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/services-section.js +0 -0
  369. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
  370. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/sidebar.js +0 -0
  371. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/spawn-ghost.js +0 -0
  372. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
  373. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/terminal-pane.js +0 -0
  374. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/tile-manager.js +0 -0
  375. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/toast.js +0 -0
  376. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/token-modal.js +0 -0
  377. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/topology-render.js +0 -0
  378. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/utils/ansi.js +0 -0
  379. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/utils/rich-text.js +0 -0
  380. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/utils/swipe.js +0 -0
  381. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
  382. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/browser-stt.js +0 -0
  383. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/browser-tts.js +0 -0
  384. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/jargon.js +0 -0
  385. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/voice/prompt.js +0 -0
  386. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
  387. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/js/workspace-window.js +0 -0
  388. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/manifest.webmanifest +0 -0
  389. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/service-worker.js +0 -0
  390. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/static/topology-harness.html +0 -0
  391. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/__init__.py +0 -0
  392. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/base.py +0 -0
  393. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/cloud.py +0 -0
  394. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/engine.py +0 -0
  395. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/local.py +0 -0
  396. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/stt/server_backend.py +0 -0
  397. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/system_cli.py +0 -0
  398. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tabs_cli.py +0 -0
  399. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tasks.py +0 -0
  400. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tasks_cli.py +0 -0
  401. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/__init__.py +0 -0
  402. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/base.html +0 -0
  403. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/council/minutes.html.j2 +0 -0
  404. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/desktop.html +0 -0
  405. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/email_notification.html +0 -0
  406. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
  407. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
  408. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/mobile.html +0 -0
  409. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/pair.html +0 -0
  410. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/statusline.sh +0 -0
  411. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templates/tmux.conf +0 -0
  412. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/templating.py +0 -0
  413. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/aws.yaml +0 -0
  414. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/docker.yaml +0 -0
  415. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/gcp.yaml +0 -0
  416. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/gh.yaml +0 -0
  417. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/git.yaml +0 -0
  418. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/gws.yaml +0 -0
  419. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/kubectl.yaml +0 -0
  420. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/npm.yaml +0 -0
  421. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/terraform.yaml +0 -0
  422. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tooldefs/uv.yaml +0 -0
  423. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/__init__.py +0 -0
  424. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/audio.py +0 -0
  425. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/base.py +0 -0
  426. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/engines/__init__.py +0 -0
  427. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/engines/chatterbox.py +0 -0
  428. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/engines/kokoro.py +0 -0
  429. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/engines/zonos.py +0 -0
  430. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/local.py +0 -0
  431. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tts/registry.py +0 -0
  432. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tunnels.py +0 -0
  433. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/tunnels_cli.py +0 -0
  434. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/usage_limit.py +0 -0
  435. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/__init__.py +0 -0
  436. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/chunker.py +0 -0
  437. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/event_log.py +0 -0
  438. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/file_io.py +0 -0
  439. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/speech.py +0 -0
  440. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/utils/subprocess.py +0 -0
  441. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/validation.py +0 -0
  442. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/__init__.py +0 -0
  443. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/client.py +0 -0
  444. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/confirm.py +0 -0
  445. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/delivery.py +0 -0
  446. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/identity.py +0 -0
  447. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/instructions.py +0 -0
  448. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/outbox.py +0 -0
  449. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/realtime.py +0 -0
  450. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/relay.py +0 -0
  451. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/server.py +0 -0
  452. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/surface.py +0 -0
  453. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/tools.py +0 -0
  454. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/transcript.py +0 -0
  455. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/voice_layer/write_tools.py +0 -0
  456. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/wait_cli.py +0 -0
  457. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/wiki.py +0 -0
  458. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/wiki_audit.py +0 -0
  459. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/wiki_cli.py +0 -0
  460. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/worktree.py +0 -0
  461. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/worktree_cli.py +0 -0
  462. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/agentwire/worktree_registry.py +0 -0
  463. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/decisions/obsidian-second-brain.md +0 -0
  464. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/design/session-card-fields.md +0 -0
  465. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/design/session-card-recommendation.md +0 -0
  466. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/logo.png +0 -0
  467. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/INDEX.md +0 -0
  468. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/architecture.md +0 -0
  469. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/auth-expired.md +0 -0
  470. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/briefing-mode.md +0 -0
  471. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/communication/channels.md +0 -0
  472. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/communication/hammerspoon.md +0 -0
  473. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/communication/handoff.md +0 -0
  474. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/concepts.md +0 -0
  475. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/council.md +0 -0
  476. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/deployment/remote-access.md +0 -0
  477. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/glossary.md +0 -0
  478. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
  479. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/parallel-refactor.md +0 -0
  480. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/portal.md +0 -0
  481. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/session-topology.md +0 -0
  482. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/shell-escaping.md +0 -0
  483. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/internals/window-collage.md +0 -0
  484. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/quickstart.md +0 -0
  485. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
  486. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
  487. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
  488. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/security/damage-control-hardening.md +0 -0
  489. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/security/pip-audit.md +0 -0
  490. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/security/remote-access-hardening.md +0 -0
  491. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/security/secrets.md +0 -0
  492. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/services.md +0 -0
  493. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
  494. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/conversation-identity.md +0 -0
  495. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/heal-line-count-cliff.md +0 -0
  496. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/helper-sessions.md +0 -0
  497. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/window-sizing.md +0 -0
  498. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
  499. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice/stt-cloud.md +0 -0
  500. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
  501. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
  502. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/docs/wiki/voice-layer.md +0 -0
  503. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/pyproject.toml +0 -0
  504. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/scratch-remove-docker-daemons.sh +0 -0
  505. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/e2e/test_portal_ui.py +0 -0
  506. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/fixtures/hotkeys_harness.mjs +0 -0
  507. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/fixtures/sample_agentwire.yml +0 -0
  508. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/fixtures/sample_config.yaml +0 -0
  509. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/fixtures/sample_scheduler.yaml +0 -0
  510. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_council_portal.py +0 -0
  511. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_scheduler_board.py +0 -0
  512. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_server_websockets.py +0 -0
  513. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_tmux_name_rewrite.py +0 -0
  514. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/integration/test_worktree_cmd.py +0 -0
  515. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/page_slice.py +0 -0
  516. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_announcements.py +0 -0
  517. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_audit_attribution.py +0 -0
  518. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_beta_flag.py +0 -0
  519. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_brace_expansion_zero_access.py +0 -0
  520. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_buddy_restart.py +0 -0
  521. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_build_agent_command.py +0 -0
  522. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_channels.py +0 -0
  523. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_chrome_tabs.py +0 -0
  524. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cli_output.py +0 -0
  525. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cli_smoke.py +0 -0
  526. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_cli_stderr_clean.py +0 -0
  527. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_client_wires.py +0 -0
  528. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_config_cli.py +0 -0
  529. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_core_created_by_rooting.py +0 -0
  530. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_cli.py +0 -0
  531. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_inbox.py +0 -0
  532. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_minutes.py +0 -0
  533. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_state.py +0 -0
  534. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_council_view.py +0 -0
  535. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_bypass.py +0 -0
  536. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_inert_view.py +0 -0
  537. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_operation_pinning.py +0 -0
  538. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_damage_control_sync.py +0 -0
  539. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_dangling_worktrees.py +0 -0
  540. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_devices.py +0 -0
  541. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_diff_cli.py +0 -0
  542. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_scheduler_staleness.py +0 -0
  543. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_secrets_perms.py +0 -0
  544. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_task_migration.py +0 -0
  545. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_doctor_voice.py +0 -0
  546. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_ensure_shared_dir.py +0 -0
  547. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_ensure_verified_prompt.py +0 -0
  548. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_event_log.py +0 -0
  549. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_file_io.py +0 -0
  550. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_fleet_activity.py +0 -0
  551. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_fleet_alerts.py +0 -0
  552. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_guarded_launch_command.py +0 -0
  553. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_handoff_git_state.py +0 -0
  554. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_handoff_parser.py +0 -0
  555. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_handoff_renderer.py +0 -0
  556. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_helper_session.py +0 -0
  557. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_history.py +0 -0
  558. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_history_resume_name.py +0 -0
  559. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_hotkeys_js.py +0 -0
  560. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_idle_handler.py +0 -0
  561. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_idle_nag.py +0 -0
  562. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_init_command.py +0 -0
  563. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_install_parity.py +0 -0
  564. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_launch_line_reentry.py +0 -0
  565. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_launch_via_env.py +0 -0
  566. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_limits_tick_isolation.py +0 -0
  567. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_locking.py +0 -0
  568. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_mcp_tool_policy.py +0 -0
  569. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_mcp_tools_args.py +0 -0
  570. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_notify_cli.py +0 -0
  571. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_onboarding_reinit.py +0 -0
  572. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_owner_only_writes.py +0 -0
  573. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_palette_cli.py +0 -0
  574. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_payload_position.py +0 -0
  575. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_pending_message_visibility.py +0 -0
  576. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_pip_audit_report.py +0 -0
  577. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_pip_environment.py +0 -0
  578. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_portal_api.py +0 -0
  579. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_posture_default.py +0 -0
  580. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_project_config.py +0 -0
  581. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_projects_registry.py +0 -0
  582. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_prompt_router.py +0 -0
  583. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_prompt_router_resume.py +0 -0
  584. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_prose_operands.py +0 -0
  585. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_push.py +0 -0
  586. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_rebuild_guard.py +0 -0
  587. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_remote_session_record.py +0 -0
  588. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_repo_cli.py +0 -0
  589. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_rich_text_js.py +0 -0
  590. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_rm_recoverable.py +0 -0
  591. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_role_prompt_retention.py +0 -0
  592. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_role_prompt_sweep_wiring.py +0 -0
  593. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_roles.py +0 -0
  594. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_routes_snapshot.py +0 -0
  595. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_commands.py +0 -0
  596. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_coverage_wave.py +0 -0
  597. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_disabled_rules.py +0 -0
  598. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_engine_is_standalone.py +0 -0
  599. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_escape_hatch.py +0 -0
  600. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_kill_switch.py +0 -0
  601. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_safety_notify.py +0 -0
  602. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scheduler.py +0 -0
  603. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scheduler_liveness.py +0 -0
  604. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scheduler_parsing.py +0 -0
  605. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scheduler_zombie.py +0 -0
  606. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_scratchpad.py +0 -0
  607. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_security.py +0 -0
  608. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_sed_script_is_data.py +0 -0
  609. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_server_async.py +0 -0
  610. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_server_pure.py +0 -0
  611. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_services.py +0 -0
  612. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_services_command.py +0 -0
  613. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_context.py +0 -0
  614. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_created_by_env.py +0 -0
  615. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_metadata_ssot.py +0 -0
  616. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_session_metadata_write.py +0 -0
  617. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_shared_dir_guard.py +0 -0
  618. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_shim_selfheal.py +0 -0
  619. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_speech_tags.py +0 -0
  620. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_ssh.py +0 -0
  621. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_stt_backend.py +0 -0
  622. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_stt_cloud.py +0 -0
  623. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_stt_engine.py +0 -0
  624. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_task_cli.py +0 -0
  625. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_task_max_duration.py +0 -0
  626. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tasks.py +0 -0
  627. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tasks_cli.py +0 -0
  628. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_templating.py +0 -0
  629. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_terminal_resize.py +0 -0
  630. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tmux_session_cwd.py +0 -0
  631. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tmux_template.py +0 -0
  632. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tts_engine_resolution.py +0 -0
  633. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tts_local.py +0 -0
  634. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_tunnels_probe.py +0 -0
  635. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_unattended_env_isolation.py +0 -0
  636. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_unattended_scoped_allow.py +0 -0
  637. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_usage_limit.py +0 -0
  638. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_validation.py +0 -0
  639. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_announcer.py +0 -0
  640. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_bridge_host.py +0 -0
  641. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_confirm.py +0 -0
  642. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_epoch.py +0 -0
  643. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_fleet_alerts.py +0 -0
  644. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_outbox.py +0 -0
  645. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_persona.py +0 -0
  646. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_picker.py +0 -0
  647. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_relay_full_text.py +0 -0
  648. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_status.py +0 -0
  649. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_surface.py +0 -0
  650. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_voice_ux_1048.py +0 -0
  651. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_wiki.py +0 -0
  652. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_wiki_audit.py +0 -0
  653. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_window_cycling_binding.py +0 -0
  654. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree.py +0 -0
  655. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_branch_cleanup.py +0 -0
  656. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_dot_project.py +0 -0
  657. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_git_truth.py +0 -0
  658. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_layout.py +0 -0
  659. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_worktree_registry.py +0 -0
  660. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tests/unit/test_zero_access_member_access.py +0 -0
  661. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tools/nonce_stt_probe.py +0 -0
  662. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tools/voice_dc_probe.py +0 -0
  663. {agentwire_dev-1.71.0 → agentwire_dev-1.72.0}/tools/voice_heal_probe.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentwire-dev
3
- Version: 1.71.0
3
+ Version: 1.72.0
4
4
  Summary: Multi-session voice web interface for AI coding agents
5
5
  Project-URL: Homepage, https://agentwire.dev
6
6
  Project-URL: Repository, https://github.com/dotdevdotdev/agentwire-dev
@@ -1,3 +1,3 @@
1
1
  """AgentWire - Multi-session voice web interface for AI coding agents."""
2
2
 
3
- __version__ = "1.71.0"
3
+ __version__ = "1.72.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 PROJECTS_DIR, encode_project_path
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 = Path(PROJECTS_DIR) / encode_project_path(str(cwd))
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 PROJECTS_DIR, encode_project_path
248
+ from .history import claude_projects_dir, encode_project_path
249
249
 
250
- base = Path(PROJECTS_DIR) / encode_project_path(str(project_path))
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)