agentwire-dev 1.66.0__tar.gz → 1.68.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 (574) hide show
  1. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/workflows/security.yml +73 -1
  2. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/PKG-INFO +2 -2
  3. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/__init__.py +1 -1
  4. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/__main__.py +3 -2
  5. agentwire_dev-1.68.0/agentwire/auth_expired.py +447 -0
  6. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/completion.py +76 -5
  7. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/core.py +592 -64
  8. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/doctor_cli.py +701 -30
  9. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/ensure_cli.py +157 -8
  10. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/history.py +220 -12
  11. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/history_cli.py +155 -1
  12. agentwire_dev-1.68.0/agentwire/history_migrate.py +463 -0
  13. agentwire_dev-1.68.0/agentwire/hooks/damage-control/bash-tool-damage-control.py +3009 -0
  14. agentwire_dev-1.68.0/agentwire/hooks/damage-control/edit-tool-damage-control.py +2910 -0
  15. agentwire_dev-1.68.0/agentwire/hooks/damage-control/mcp-tool-damage-control.py +3045 -0
  16. agentwire_dev-1.68.0/agentwire/hooks/damage-control/read-tool-damage-control.py +2925 -0
  17. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +7 -0
  18. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/aws.yaml +13 -0
  19. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +27 -0
  20. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/containers.yaml +10 -3
  21. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/core.yaml +19 -7
  22. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/databases.yaml +27 -55
  23. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/firebase.yaml +5 -0
  24. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/gcp.yaml +9 -0
  25. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/gws.yaml +7 -0
  26. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +10 -0
  27. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/outbound.yaml +7 -0
  28. agentwire_dev-1.68.0/agentwire/hooks/damage-control/rules/payloads.yaml +118 -0
  29. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/publish.yaml +6 -0
  30. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/remote.yaml +30 -0
  31. agentwire_dev-1.68.0/agentwire/hooks/damage-control/write-tool-damage-control.py +2909 -0
  32. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/queue-processor.sh +0 -0
  33. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks_cli.py +60 -7
  34. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/inbox.py +80 -11
  35. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/limits_cli.py +18 -1
  36. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/machine_cli.py +8 -8
  37. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_task.py +5 -0
  38. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/onboarding.py +8 -1
  39. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/pane_cli.py +24 -9
  40. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/prompt_router.py +382 -61
  41. agentwire_dev-1.68.0/agentwire/restart_cli.py +276 -0
  42. agentwire_dev-1.68.0/agentwire/role_prompts.py +301 -0
  43. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/scheduler.py +34 -20
  44. agentwire_dev-1.68.0/agentwire/safety/_core.py +2821 -0
  45. agentwire_dev-1.68.0/agentwire/safety/lint.py +252 -0
  46. agentwire_dev-1.68.0/agentwire/safety/provenance.py +205 -0
  47. agentwire_dev-1.68.0/agentwire/safety/rule_baselines.json +116 -0
  48. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/safety_cli.py +18 -2
  49. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/safety_commands.py +395 -54
  50. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/__init__.py +1 -0
  51. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/dispatch.py +59 -2
  52. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/models.py +3 -1
  53. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/report.py +83 -1
  54. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/zombie.py +1 -1
  55. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler_cli.py +62 -6
  56. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/security.py +8 -22
  57. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/session_cli.py +64 -23
  58. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/system_cli.py +25 -0
  59. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tasks.py +58 -5
  60. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tasks_cli.py +55 -0
  61. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/tmux.conf +12 -3
  62. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/worktree.py +22 -6
  63. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/INDEX.md +3 -0
  64. agentwire_dev-1.68.0/docs/wiki/auth-expired.md +210 -0
  65. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/damage-control.md +424 -10
  66. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/scheduling/scheduled-workloads.md +145 -1
  67. agentwire_dev-1.68.0/docs/wiki/security/pip-audit.md +158 -0
  68. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/security/secrets.md +36 -0
  69. agentwire_dev-1.68.0/docs/wiki/sessions/conversation-identity.md +532 -0
  70. agentwire_dev-1.68.0/docs/wiki/sessions/heal-line-count-cliff.md +166 -0
  71. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/messaging.md +37 -10
  72. agentwire_dev-1.68.0/docs/wiki/sessions/prompt-routing.md +290 -0
  73. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/pyproject.toml +9 -1
  74. agentwire_dev-1.68.0/tests/conftest.py +371 -0
  75. agentwire_dev-1.68.0/tests/home_guard.py +133 -0
  76. agentwire_dev-1.68.0/tests/integration/test_tmux_name_rewrite.py +174 -0
  77. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_worktree_cmd.py +122 -12
  78. agentwire_dev-1.68.0/tests/unit/test_auth_expired.py +417 -0
  79. agentwire_dev-1.68.0/tests/unit/test_auth_expired_dispatch.py +310 -0
  80. agentwire_dev-1.68.0/tests/unit/test_build_agent_command.py +380 -0
  81. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_cli_commands.py +7 -9
  82. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_control_plane_protection.py +8 -0
  83. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_damage_control_bypass.py +10 -0
  84. agentwire_dev-1.68.0/tests/unit/test_damage_control_hooks.py +1867 -0
  85. agentwire_dev-1.68.0/tests/unit/test_damage_control_payload_anchoring.py +1354 -0
  86. agentwire_dev-1.68.0/tests/unit/test_doctor_orphaned_history.py +168 -0
  87. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_doctor_scheduler_staleness.py +58 -15
  88. agentwire_dev-1.68.0/tests/unit/test_doctor_secrets_perms.py +128 -0
  89. agentwire_dev-1.68.0/tests/unit/test_ensure_verified_prompt.py +155 -0
  90. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_guarded_launch_command.py +12 -2
  91. agentwire_dev-1.68.0/tests/unit/test_history.py +179 -0
  92. agentwire_dev-1.68.0/tests/unit/test_history_migrate.py +476 -0
  93. agentwire_dev-1.68.0/tests/unit/test_history_migrate_cli.py +134 -0
  94. agentwire_dev-1.68.0/tests/unit/test_history_resume_name.py +126 -0
  95. agentwire_dev-1.68.0/tests/unit/test_home_isolation.py +364 -0
  96. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_hooks_install.py +10 -0
  97. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_inbox.py +101 -4
  98. agentwire_dev-1.68.0/tests/unit/test_launch_line_reentry.py +355 -0
  99. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_locking.py +4 -4
  100. agentwire_dev-1.68.0/tests/unit/test_owner_only_writes.py +102 -0
  101. agentwire_dev-1.68.0/tests/unit/test_pending_message_visibility.py +149 -0
  102. agentwire_dev-1.68.0/tests/unit/test_pip_audit_report.py +580 -0
  103. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_prompt_router.py +30 -7
  104. agentwire_dev-1.68.0/tests/unit/test_prompt_router_resume.py +701 -0
  105. agentwire_dev-1.68.0/tests/unit/test_remote_session_record.py +97 -0
  106. agentwire_dev-1.68.0/tests/unit/test_restart_cli.py +373 -0
  107. agentwire_dev-1.68.0/tests/unit/test_role_prompt_retention.py +286 -0
  108. agentwire_dev-1.68.0/tests/unit/test_role_prompt_sweep_wiring.py +198 -0
  109. agentwire_dev-1.68.0/tests/unit/test_safety_deployment.py +842 -0
  110. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_heal.py +9 -0
  111. agentwire_dev-1.68.0/tests/unit/test_scheduler_liveness.py +351 -0
  112. agentwire_dev-1.68.0/tests/unit/test_session_metadata_ssot.py +190 -0
  113. agentwire_dev-1.68.0/tests/unit/test_session_metadata_write.py +157 -0
  114. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_skill_install.py +12 -2
  115. agentwire_dev-1.68.0/tests/unit/test_task_max_duration.py +171 -0
  116. agentwire_dev-1.68.0/tests/unit/test_tmux_session_cwd.py +126 -0
  117. agentwire_dev-1.68.0/tests/unit/test_unattended_scoped_allow.py +732 -0
  118. agentwire_dev-1.68.0/tests/unit/test_worktree_dot_project.py +146 -0
  119. agentwire_dev-1.66.0/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -1605
  120. agentwire_dev-1.66.0/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -1515
  121. agentwire_dev-1.66.0/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -1642
  122. agentwire_dev-1.66.0/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -1530
  123. agentwire_dev-1.66.0/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -1514
  124. agentwire_dev-1.66.0/agentwire/safety/_core.py +0 -1429
  125. agentwire_dev-1.66.0/docs/wiki/security/pip-audit.md +0 -60
  126. agentwire_dev-1.66.0/docs/wiki/sessions/prompt-routing.md +0 -156
  127. agentwire_dev-1.66.0/tests/conftest.py +0 -149
  128. agentwire_dev-1.66.0/tests/unit/test_build_agent_command.py +0 -163
  129. agentwire_dev-1.66.0/tests/unit/test_damage_control_hooks.py +0 -806
  130. agentwire_dev-1.66.0/tests/unit/test_history.py +0 -34
  131. agentwire_dev-1.66.0/tests/unit/test_worktree_dot_project.py +0 -84
  132. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.agentwire.yml.example +0 -0
  133. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.claude/commands/handoff.md +0 -0
  134. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.claude/skills/wiki/SKILL.md +0 -0
  135. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/FUNDING.yml +0 -0
  136. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  137. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  138. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
  139. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  140. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/workflows/pytest.yml +0 -0
  141. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/workflows/ruff.yml +0 -0
  142. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.github/workflows/tts-smoke.yml +0 -0
  143. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/.gitignore +0 -0
  144. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/AGENTS.md +0 -0
  145. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/CODE_OF_CONDUCT.md +0 -0
  146. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/CONTRIBUTING.md +0 -0
  147. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/Dockerfile.local +0 -0
  148. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/LICENSE +0 -0
  149. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/README.md +0 -0
  150. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/RELEASING.md +0 -0
  151. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/SECURITY.md +0 -0
  152. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/SPONSORS.md +0 -0
  153. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/agents/__init__.py +0 -0
  154. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/agents/base.py +0 -0
  155. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/agents/tmux.py +0 -0
  156. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/cached_status.py +0 -0
  157. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/__init__.py +0 -0
  158. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/base.py +0 -0
  159. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/email.py +0 -0
  160. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/push.py +0 -0
  161. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels/quo.py +0 -0
  162. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/channels_cli.py +0 -0
  163. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/chrome_tabs.py +0 -0
  164. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/cohort.py +0 -0
  165. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/config.py +0 -0
  166. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/config_cli.py +0 -0
  167. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/__init__.py +0 -0
  168. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/cli.py +0 -0
  169. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/inbox.py +0 -0
  170. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/minutes.py +0 -0
  171. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/state.py +0 -0
  172. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/council/view.py +0 -0
  173. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/devices.py +0 -0
  174. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/diff_cli.py +0 -0
  175. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/doctor_voice.py +0 -0
  176. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/fetch.py +0 -0
  177. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/__init__.py +0 -0
  178. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/git_state.py +0 -0
  179. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/instructions.py +0 -0
  180. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/parser.py +0 -0
  181. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/renderer.py +0 -0
  182. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff/schema.py +0 -0
  183. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/handoff_cli.py +0 -0
  184. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/__init__.py +0 -0
  185. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/agentwire-permission.sh +0 -0
  186. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/__init__.py +0 -0
  187. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
  188. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
  189. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
  190. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/hooks/idle-handler.sh +0 -0
  191. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/listen.py +0 -0
  192. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/locking.py +0 -0
  193. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_channels.py +0 -0
  194. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_chrome.py +0 -0
  195. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_cli.py +0 -0
  196. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_core.py +0 -0
  197. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_council.py +0 -0
  198. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_desktop.py +0 -0
  199. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_handoff.py +0 -0
  200. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_history.py +0 -0
  201. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_listen.py +0 -0
  202. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_lock.py +0 -0
  203. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_machine.py +0 -0
  204. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_msg.py +0 -0
  205. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_notify.py +0 -0
  206. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_pane.py +0 -0
  207. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_projects.py +0 -0
  208. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_scheduler.py +0 -0
  209. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_scratchpad.py +0 -0
  210. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_server.py +0 -0
  211. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_services.py +0 -0
  212. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_session.py +0 -0
  213. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_status.py +0 -0
  214. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_tunnels.py +0 -0
  215. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_voice.py +0 -0
  216. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_wiki.py +0 -0
  217. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/mcp_worktree.py +0 -0
  218. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/msg_cli.py +0 -0
  219. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/network.py +0 -0
  220. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/notify_cli.py +0 -0
  221. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/palette_cli.py +0 -0
  222. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/pane_manager.py +0 -0
  223. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/portal_cli.py +0 -0
  224. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/project_config.py +0 -0
  225. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/projects.py +0 -0
  226. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/prompts_cli.py +0 -0
  227. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/push_cli.py +0 -0
  228. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/push_store.py +0 -0
  229. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/repo_cli.py +0 -0
  230. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/research.py +0 -0
  231. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/__init__.py +0 -0
  232. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/agentwire.md +0 -0
  233. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/anchor.md +0 -0
  234. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/chatbot.md +0 -0
  235. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/contributor.md +0 -0
  236. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/correspondent.md +0 -0
  237. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-brain.md +0 -0
  238. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-conscience.md +0 -0
  239. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-critic.md +0 -0
  240. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-devils-advocate.md +0 -0
  241. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-gut.md +0 -0
  242. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-historian.md +0 -0
  243. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-member.md +0 -0
  244. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/council-orchestrator.md +0 -0
  245. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/init.md +0 -0
  246. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/notifications.md +0 -0
  247. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/orchestrator.md +0 -0
  248. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/reviewer-worktree.md +0 -0
  249. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/reviewer.md +0 -0
  250. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/shared-checkout.md +0 -0
  251. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/soul.md +0 -0
  252. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/task-runner.md +0 -0
  253. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/voice.md +0 -0
  254. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/worker-worktree.md +0 -0
  255. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles/worker.md +0 -0
  256. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/roles_cli.py +0 -0
  257. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/__init__.py +0 -0
  258. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/artifacts.py +0 -0
  259. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/config.py +0 -0
  260. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/council.py +0 -0
  261. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/desktop.py +0 -0
  262. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/history.py +0 -0
  263. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/machines.py +0 -0
  264. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/notify.py +0 -0
  265. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/palette.py +0 -0
  266. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/permission.py +0 -0
  267. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/projects.py +0 -0
  268. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/push.py +0 -0
  269. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/safety.py +0 -0
  270. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/scratchpad.py +0 -0
  271. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/sessions.py +0 -0
  272. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/sessions_admin.py +0 -0
  273. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/routes/voice.py +0 -0
  274. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/safety/__init__.py +0 -0
  275. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/gates.py +0 -0
  276. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/loop.py +0 -0
  277. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/schedule.py +0 -0
  278. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scheduler/state.py +0 -0
  279. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/scratchpad.py +0 -0
  280. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/send_cli.py +0 -0
  281. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/server.py +0 -0
  282. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/services.py +0 -0
  283. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/session_context.py +0 -0
  284. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/session_ready.py +0 -0
  285. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/ssh.py +0 -0
  286. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
  287. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
  288. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
  289. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
  290. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
  291. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/announcements.json +0 -0
  292. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/apple-touch-icon.png +0 -0
  293. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/css/desktop.css +0 -0
  294. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/css/mobile.css +0 -0
  295. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/favicon-32.png +0 -0
  296. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/favicon-64.png +0 -0
  297. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/bear.webp +0 -0
  298. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/cat.webp +0 -0
  299. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/crown.webp +0 -0
  300. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
  301. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
  302. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
  303. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/deer.webp +0 -0
  304. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/drone.webp +0 -0
  305. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
  306. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/fox.webp +0 -0
  307. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
  308. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/horse.webp +0 -0
  309. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/lion.webp +0 -0
  310. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
  311. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/robot.webp +0 -0
  312. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
  313. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
  314. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/img/icon-192.png +0 -0
  315. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/img/icon-512.png +0 -0
  316. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/.gitkeep +0 -0
  317. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/announcement-modal.js +0 -0
  318. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/api.js +0 -0
  319. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/artifact-window.js +0 -0
  320. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/card-terminal.js +0 -0
  321. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/collage.js +0 -0
  322. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/command-palette.js +0 -0
  323. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/council-window.js +0 -0
  324. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
  325. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/desktop-manager.js +0 -0
  326. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/desktop.js +0 -0
  327. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/help-modal.js +0 -0
  328. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/icon-manager.js +0 -0
  329. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/lineage.js +0 -0
  330. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/mobile.js +0 -0
  331. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/notification-prefs.js +0 -0
  332. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/notifications-panel.js +0 -0
  333. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/ptt.js +0 -0
  334. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/push-client.js +0 -0
  335. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/review-window.js +0 -0
  336. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/safety-shared.js +0 -0
  337. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/safety-window.js +0 -0
  338. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/scratchpad.js +0 -0
  339. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/service-classification.js +0 -0
  340. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-hud-controller.js +0 -0
  341. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-hud-notices.js +0 -0
  342. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-hud-spawn.js +0 -0
  343. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-hud.js +0 -0
  344. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-id.js +0 -0
  345. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/session-window.js +0 -0
  346. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/shortcuts.js +0 -0
  347. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
  348. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/config-section.js +0 -0
  349. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/council-section.js +0 -0
  350. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
  351. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
  352. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
  353. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
  354. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/services-section.js +0 -0
  355. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
  356. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/sidebar.js +0 -0
  357. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/spawn-ghost.js +0 -0
  358. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
  359. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/terminal-pane.js +0 -0
  360. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/tile-manager.js +0 -0
  361. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/toast.js +0 -0
  362. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/token-modal.js +0 -0
  363. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/topology-render.js +0 -0
  364. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/utils/ansi.js +0 -0
  365. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/utils/rich-text.js +0 -0
  366. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/utils/swipe.js +0 -0
  367. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
  368. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/browser-stt.js +0 -0
  369. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/browser-tts.js +0 -0
  370. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/jargon.js +0 -0
  371. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/voice/prompt.js +0 -0
  372. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
  373. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/js/workspace-window.js +0 -0
  374. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/manifest.webmanifest +0 -0
  375. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/service-worker.js +0 -0
  376. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/static/topology-harness.html +0 -0
  377. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/__init__.py +0 -0
  378. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/base.py +0 -0
  379. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/cloud.py +0 -0
  380. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/engine.py +0 -0
  381. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/local.py +0 -0
  382. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/server_backend.py +0 -0
  383. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/stt/stt_server.py +0 -0
  384. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tabs_cli.py +0 -0
  385. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/__init__.py +0 -0
  386. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/base.html +0 -0
  387. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/council/minutes.html.j2 +0 -0
  388. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/desktop.html +0 -0
  389. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/email_notification.html +0 -0
  390. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
  391. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
  392. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/mobile.html +0 -0
  393. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/pair.html +0 -0
  394. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templates/statusline.sh +0 -0
  395. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/templating.py +0 -0
  396. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/aws.yaml +0 -0
  397. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/docker.yaml +0 -0
  398. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/gcp.yaml +0 -0
  399. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/gh.yaml +0 -0
  400. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/git.yaml +0 -0
  401. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/gws.yaml +0 -0
  402. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/kubectl.yaml +0 -0
  403. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/npm.yaml +0 -0
  404. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/terraform.yaml +0 -0
  405. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tooldefs/uv.yaml +0 -0
  406. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/__init__.py +0 -0
  407. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/audio.py +0 -0
  408. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/base.py +0 -0
  409. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/engines/__init__.py +0 -0
  410. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/engines/chatterbox.py +0 -0
  411. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/engines/kokoro.py +0 -0
  412. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/engines/zonos.py +0 -0
  413. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/kokoro_server.py +0 -0
  414. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/local.py +0 -0
  415. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts/registry.py +0 -0
  416. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts_cli.py +0 -0
  417. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tts_server.py +0 -0
  418. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tunnels.py +0 -0
  419. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/tunnels_cli.py +0 -0
  420. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/usage_limit.py +0 -0
  421. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/__init__.py +0 -0
  422. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/chunker.py +0 -0
  423. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/event_log.py +0 -0
  424. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/file_io.py +0 -0
  425. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/paths.py +0 -0
  426. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/speech.py +0 -0
  427. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/utils/subprocess.py +0 -0
  428. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/validation.py +0 -0
  429. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/voice_status.py +0 -0
  430. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/wait_cli.py +0 -0
  431. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/wiki.py +0 -0
  432. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/wiki_audit.py +0 -0
  433. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/wiki_cli.py +0 -0
  434. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/worktree_cli.py +0 -0
  435. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/agentwire/worktree_registry.py +0 -0
  436. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/decisions/obsidian-second-brain.md +0 -0
  437. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/design/session-card-fields.md +0 -0
  438. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/design/session-card-recommendation.md +0 -0
  439. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/logo.png +0 -0
  440. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/architecture.md +0 -0
  441. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/briefing-mode.md +0 -0
  442. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/communication/channels.md +0 -0
  443. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/communication/hammerspoon.md +0 -0
  444. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/communication/handoff.md +0 -0
  445. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/concepts.md +0 -0
  446. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/council.md +0 -0
  447. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/deployment/remote-access.md +0 -0
  448. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/deployment/remote-machines.md +0 -0
  449. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/glossary.md +0 -0
  450. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
  451. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/parallel-refactor.md +0 -0
  452. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/portal.md +0 -0
  453. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/session-topology.md +0 -0
  454. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/shell-escaping.md +0 -0
  455. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/troubleshooting.md +0 -0
  456. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/internals/window-collage.md +0 -0
  457. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/quickstart.md +0 -0
  458. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
  459. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
  460. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/security/damage-control-hardening.md +0 -0
  461. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/security/remote-access-hardening.md +0 -0
  462. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/services.md +0 -0
  463. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
  464. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/fan-out-cohorts.md +0 -0
  465. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/helper-sessions.md +0 -0
  466. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/window-sizing.md +0 -0
  467. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
  468. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/usage-limit-recovery.md +0 -0
  469. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/voice/shim-contract.md +0 -0
  470. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/voice/stt-cloud.md +0 -0
  471. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
  472. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
  473. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/e2e/test_portal_ui.py +0 -0
  474. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/fixtures/sample_agentwire.yml +0 -0
  475. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/fixtures/sample_config.yaml +0 -0
  476. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/fixtures/sample_scheduler.yaml +0 -0
  477. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_council_portal.py +0 -0
  478. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_scheduler_board.py +0 -0
  479. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_send_verified_tmux.py +0 -0
  480. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/integration/test_server_websockets.py +0 -0
  481. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_announcements.py +0 -0
  482. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_channels.py +0 -0
  483. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_chrome_tabs.py +0 -0
  484. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_cli_output.py +0 -0
  485. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_cli_smoke.py +0 -0
  486. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_cohort.py +0 -0
  487. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_config.py +0 -0
  488. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_config_cli.py +0 -0
  489. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_core_created_by_rooting.py +0 -0
  490. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_cli.py +0 -0
  491. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_inbox.py +0 -0
  492. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_minutes.py +0 -0
  493. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_state.py +0 -0
  494. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_council_view.py +0 -0
  495. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_damage_control_sync.py +0 -0
  496. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_dangling_worktrees.py +0 -0
  497. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_devices.py +0 -0
  498. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_diff_cli.py +0 -0
  499. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_doctor_task_migration.py +0 -0
  500. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_doctor_voice.py +0 -0
  501. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_ensure_shared_dir.py +0 -0
  502. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_event_log.py +0 -0
  503. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_file_io.py +0 -0
  504. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_handoff_git_state.py +0 -0
  505. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_handoff_instructions.py +0 -0
  506. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_handoff_parser.py +0 -0
  507. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_handoff_renderer.py +0 -0
  508. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_helper_session.py +0 -0
  509. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_idle_handler.py +0 -0
  510. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_idle_nag.py +0 -0
  511. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_init_command.py +0 -0
  512. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_install_parity.py +0 -0
  513. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_launch_via_env.py +0 -0
  514. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_limits_tick_isolation.py +0 -0
  515. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_mcp_server.py +0 -0
  516. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_mcp_tools_args.py +0 -0
  517. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_msg_cli.py +0 -0
  518. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_notify_cli.py +0 -0
  519. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_onboarding_reinit.py +0 -0
  520. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_palette_cli.py +0 -0
  521. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_pip_environment.py +0 -0
  522. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_portal_api.py +0 -0
  523. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_posture_default.py +0 -0
  524. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_project_config.py +0 -0
  525. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_projects_registry.py +0 -0
  526. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_push.py +0 -0
  527. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_rebuild_guard.py +0 -0
  528. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_repo_cli.py +0 -0
  529. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_rich_text_js.py +0 -0
  530. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_roles.py +0 -0
  531. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_routes_snapshot.py +0 -0
  532. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_commands.py +0 -0
  533. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_disabled_rules.py +0 -0
  534. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_escape_hatch.py +0 -0
  535. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_safety_kill_switch.py +0 -0
  536. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_scheduler.py +0 -0
  537. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_scheduler_parsing.py +0 -0
  538. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_scheduler_zombie.py +0 -0
  539. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_scratchpad.py +0 -0
  540. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_security.py +0 -0
  541. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_server_async.py +0 -0
  542. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_server_pure.py +0 -0
  543. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_services.py +0 -0
  544. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_session_context.py +0 -0
  545. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_session_created_by_env.py +0 -0
  546. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_session_ready.py +0 -0
  547. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_shared_dir_guard.py +0 -0
  548. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_shim_selfheal.py +0 -0
  549. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_speech_tags.py +0 -0
  550. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_ssh.py +0 -0
  551. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_stt_backend.py +0 -0
  552. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_stt_cloud.py +0 -0
  553. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_stt_engine.py +0 -0
  554. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_task_cli.py +0 -0
  555. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tasks.py +0 -0
  556. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tasks_cli.py +0 -0
  557. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_templating.py +0 -0
  558. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_terminal_resize.py +0 -0
  559. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tmux_template.py +0 -0
  560. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tts_engine_resolution.py +0 -0
  561. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tts_local.py +0 -0
  562. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_tunnels_probe.py +0 -0
  563. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_unattended_env_isolation.py +0 -0
  564. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_usage_limit.py +0 -0
  565. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_validation.py +0 -0
  566. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_voice_status.py +0 -0
  567. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_wiki.py +0 -0
  568. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_wiki_audit.py +0 -0
  569. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_window_cycling_binding.py +0 -0
  570. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree.py +0 -0
  571. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree_branch_cleanup.py +0 -0
  572. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree_git_truth.py +0 -0
  573. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree_layout.py +0 -0
  574. {agentwire_dev-1.66.0 → agentwire_dev-1.68.0}/tests/unit/test_worktree_registry.py +0 -0
@@ -66,6 +66,16 @@ jobs:
66
66
  # deps are bumped explicitly in pyproject; transitive fixes land via lock
67
67
  # bumps. See docs/wiki/security/pip-audit.md for the residual-CVE rationale.
68
68
  continue-on-error: true
69
+ # The weekly cron opens/updates the tracking issue, which the DEFAULT token
70
+ # does not necessarily allow — a repo set to read-only default permissions
71
+ # would fail the `gh issue` call. Declared explicitly so the durable half of
72
+ # the visibility fix can't silently no-op. (No `pull-requests: write`: this
73
+ # deliberately does not comment on PRs — a fork PR gets a read-only token,
74
+ # so that flow would silently fail for exactly the external contributors it
75
+ # would exist to serve.)
76
+ permissions:
77
+ contents: read
78
+ issues: write
69
79
  steps:
70
80
  - uses: actions/checkout@v4
71
81
  - name: Install uv
@@ -85,14 +95,42 @@ jobs:
85
95
  # HTTP request-handling CVEs are not on a reachable path. Documented +
86
96
  # ignored here so the advisory signal stays meaningful; revisit when mcp /
87
97
  # chatterbox-tts relax the ceiling. See docs/wiki/security/pip-audit.md.
98
+ # PYSEC-2026-3483 is the deprecated WebSocket SERVER transport
99
+ # (mcp.server.websocket) missing Host/Origin validation. agentwire runs
100
+ # its MCP server on stdio (mcp_server.py: mcp.run(transport="stdio")) and
101
+ # never imports that module, so it is not on a reachable path. Its fix
102
+ # needs mcp>=1.28.1, which pulls pydantic 2.13 and cascades the tts
103
+ # extra's whole chain (torch 2.6 -> 2.13 plus the CUDA stack, 32 packages)
104
+ # — a bad trade against an unreachable advisory. 1.27.2 clears the other
105
+ # two mcp advisories at a one-package diff. Revisit when the torch bump is
106
+ # wanted on its own merits. See docs/wiki/security/pip-audit.md.
88
107
  - name: Audit runtime dependencies
108
+ id: audit
109
+ continue-on-error: true
89
110
  run: >
90
111
  uvx pip-audit==2.10.1 -r requirements.txt
112
+ --format json --output audit-runtime.json
91
113
  --ignore-vuln PYSEC-2026-161
92
114
  --ignore-vuln CVE-2026-48818
93
115
  --ignore-vuln CVE-2026-48817
94
116
  --ignore-vuln CVE-2026-54283
95
117
  --ignore-vuln CVE-2026-54282
118
+ --ignore-vuln PYSEC-2026-3483
119
+ # The job stays advisory (continue-on-error above), but its RESULT is no
120
+ # longer invisible: this prints ::warning:: annotations, which GitHub
121
+ # renders on the run and PR checks views without anyone opening the job
122
+ # log, and writes a table to the step summary. `if: always()` so a
123
+ # crashed audit reports "UNKNOWN, which is not clean" rather than nothing
124
+ # — the exact shape of #900, where a red audit rendered as green.
125
+ # --min-packages is a coverage floor, not a version assertion: zero
126
+ # advisories over zero packages is not a clean bill of health. The
127
+ # runtime export is ~124 packages, so anything under 50 means the export
128
+ # produced nothing to audit and the run is reported UNKNOWN, not clean.
129
+ - name: Report advisories (never blocks)
130
+ if: always()
131
+ run: >
132
+ uv run --no-project python scripts/pip_audit_report.py
133
+ audit-runtime.json --scope runtime --min-packages 50
96
134
  # Full audit including optional extras (tts/stt: torch, onnxruntime,
97
135
  # gradio, ...). Weekly only and never ignore-filtered — surfaces the full
98
136
  # backlog for review without blocking or spamming every PR.
@@ -101,4 +139,38 @@ jobs:
101
139
  run: uv export --no-emit-project --all-extras --format requirements-txt -o requirements-all.txt
102
140
  - name: Full audit (weekly cron, optional extras)
103
141
  if: github.event_name == 'schedule'
104
- run: uvx pip-audit==2.10.1 -r requirements-all.txt
142
+ continue-on-error: true
143
+ run: >
144
+ uvx pip-audit==2.10.1 -r requirements-all.txt
145
+ --format json --output audit-all.json
146
+ - name: Report full audit + open/update the tracking issue
147
+ if: always() && github.event_name == 'schedule'
148
+ env:
149
+ GH_TOKEN: ${{ github.token }}
150
+ AUDIT_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
151
+ run: |
152
+ uv run --no-project python scripts/pip_audit_report.py audit-all.json \
153
+ --scope "all extras" --min-packages 100 --issue-body issue-body.md
154
+ # ONE issue, reused. Annotations and summaries belong to a run nobody
155
+ # revisits; an issue is what actually stops advisories accumulating
156
+ # unseen — which is how #900 reached eight.
157
+ title='pip-audit: unresolved advisories in the dependency lock'
158
+ # --state all, NOT --state open: an open-only search cannot see the
159
+ # issue this workflow closed last week, so a recurrence would file a
160
+ # SECOND issue and the "one issue, reused" promise would quietly
161
+ # become "one per close/recur cycle".
162
+ existing=$(gh issue list --state all --search "$title in:title" \
163
+ --json number,state --jq '.[0] | "\(.number) \(.state)"' || true)
164
+ number=${existing%% *}
165
+ state=${existing##* }
166
+ if grep -q ': clean' issue-body.md; then
167
+ if [ -n "$number" ] && [ "$state" = "OPEN" ]; then
168
+ gh issue comment "$number" --body-file issue-body.md
169
+ gh issue close "$number" --comment "pip-audit is clean; closing. This issue is reopened automatically if findings return."
170
+ fi
171
+ elif [ -z "$number" ]; then
172
+ gh issue create --title "$title" --label "area:security" --body-file issue-body.md
173
+ else
174
+ [ "$state" = "CLOSED" ] && gh issue reopen "$number"
175
+ gh issue comment "$number" --body-file issue-body.md
176
+ fi
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentwire-dev
3
- Version: 1.66.0
3
+ Version: 1.68.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
@@ -231,7 +231,7 @@ Requires-Dist: fastapi>=0.104.0
231
231
  Requires-Dist: jinja2>=3.1.0
232
232
  Requires-Dist: kokoro-onnx>=0.4.9; python_version < '3.14'
233
233
  Requires-Dist: markdown>=3.5
234
- Requires-Dist: mcp>=1.2.0
234
+ Requires-Dist: mcp<2,>=1.2.0
235
235
  Requires-Dist: pydantic>=2.0.0
236
236
  Requires-Dist: python-dotenv>=1.2.2
237
237
  Requires-Dist: python-multipart>=0.0.6
@@ -1,3 +1,3 @@
1
1
  """AgentWire - Multi-session voice web interface for AI coding agents."""
2
2
 
3
- __version__ = "1.66.0"
3
+ __version__ = "1.68.0"
@@ -37,7 +37,6 @@ from .core import ( # noqa: E402,F401 # E402: must follow load_dotenv(); F401:
37
37
  _parse_session_target,
38
38
  _portal_auth_headers,
39
39
  _post_desktop_notification,
40
- _record_session_creator,
41
40
  _resolve_posture_from_args,
42
41
  _run_remote,
43
42
  _set_session_name_env,
@@ -58,6 +57,7 @@ from .core import ( # noqa: E402,F401 # E402: must follow load_dotenv(); F401:
58
57
  load_config,
59
58
  load_session_metadata,
60
59
  parse_env_args,
60
+ record_session_launch,
61
61
  store_session_metadata,
62
62
  tmux_session_exists,
63
63
  tmux_session_has_agent,
@@ -190,7 +190,7 @@ Command Categories:
190
190
  from . import doctor_cli, history_cli, machine_cli, safety_cli
191
191
  from . import handoff_cli, hooks_cli, mcp_cli, roles_cli, tunnels_cli
192
192
  from . import notify_cli, palette_cli, push_cli, repo_cli, system_cli, wiki_cli
193
- from . import tabs_cli, wait_cli, worktree_cli
193
+ from . import restart_cli, tabs_cli, wait_cli, worktree_cli
194
194
  from .council import cli as council_cli
195
195
 
196
196
  _REGISTRARS = [ # noqa: N806 # registry constant; Phase 1 of #495 appends here
@@ -201,6 +201,7 @@ Command Categories:
201
201
  pane_cli.register_pane_parser,
202
202
  send_cli.register_send_parser,
203
203
  session_cli.register_session_parser,
204
+ restart_cli.register_restart_parser,
204
205
  portal_cli.register_portal_parser,
205
206
  tts_cli.register_tts_parser,
206
207
  channels_cli.register_channels_parser,
@@ -0,0 +1,447 @@
1
+ """Detect an expired Claude login and stop dispatching into it (#906).
2
+
3
+ The failure this exists for, measured on 2026-08-04 (#867): a scheduled
4
+ dispatch did everything right — session created, agent launched, a 20,433-byte
5
+ prompt submitted at ``08:00:20.785Z`` — and the turn was rejected 15 ms later:
6
+
7
+ .. code-block:: json
8
+
9
+ {"model": "<synthetic>",
10
+ "content": [{"type": "text", "text": "Login expired · Please run /login"}],
11
+ "usage": {"input_tokens": 0, "output_tokens": 0},
12
+ "error": "authentication_failed", "isApiErrorMessage": true}
13
+
14
+ Zero tokens, no model call, ``turn_duration: 16ms``, transcript ends. Nothing
15
+ noticed. ``memory-manager`` then sat until its ceiling and reported
16
+ ``incomplete — Timeout waiting for task completion``, which describes the
17
+ symptom and actively misleads about the cause; ``ai-morning-briefing`` hit the
18
+ same outage four hours later and burned the scheduler's full 14400s. Six hours
19
+ of dispatch time, and three investigation passes chasing a guardrail, a
20
+ dispatcher, a timeout and a paste race.
21
+
22
+ **The transcript is the detector, and the pane deliberately is not.** Claude
23
+ Code renders the phrase inline as an ordinary assistant message, so it also
24
+ appears in any pane that merely *quotes* or reviews the incident — the pane
25
+ investigating #867 had "Login expired · Please run /login" on screen all day.
26
+ A pane-text rule would buy that false-positive class, and a false positive
27
+ here **halts scheduling**, which is strictly worse than the hang it replaces.
28
+ The transcript's ``error`` field is a structured fact about a turn that
29
+ actually happened, so that is what is keyed on. This is the opposite trade
30
+ from :mod:`usage_limit`, and for a concrete reason: the usage-limit signal is
31
+ a *live select-menu* that can be proven live (nothing renders after it), and
32
+ this one cannot.
33
+
34
+ Recovery is a property of the same signal, not a separate mechanism: only the
35
+ **last** assistant turn in a transcript decides, so a session that auth-failed
36
+ and then took a real turn reads as healthy with nothing to reset.
37
+
38
+ The machine-wide part matters as much as the detection. An expired login is
39
+ not per-task — every subsequent dispatch hits it — so one detection records a
40
+ single outage state, emails the owner ONCE (throttled, following the
41
+ dead-letter and #905 no-parent escalation precedents rather than inventing a
42
+ third channel), and later dispatches fail fast instead of each burning its own
43
+ timeout. The state carries :data:`OUTAGE_TTL` so it cannot wedge the scheduler
44
+ indefinitely: after it, one dispatch is let through as a probe, which now
45
+ fails in seconds rather than hours.
46
+
47
+ On a pre-flight credential check (#906 item 3): there is no cheap, reliable
48
+ local signal to gate on. Claude Code keeps credentials in the macOS Keychain,
49
+ where reading them needs ``security find-generic-password -w`` — an
50
+ interactive authorization prompt, which unattended is a worse hang than the
51
+ bug. Where a plaintext ``~/.claude/.credentials.json`` does exist, its
52
+ ``expiresAt`` is the *access* token's, which lapses routinely and is refreshed
53
+ silently; gating dispatch on it would false-alarm constantly. The outage state
54
+ below IS the cheap pre-flight — a single local file read, no network — it just
55
+ costs one detection to arm.
56
+ """
57
+
58
+ from __future__ import annotations
59
+
60
+ import json
61
+ import os
62
+ import socket
63
+ from datetime import datetime, timedelta, timezone
64
+ from pathlib import Path
65
+
66
+ # The transcript's structured error value for an expired/refused login. Keyed
67
+ # on exactly this — never widened to "any api error", because a rate-limit or
68
+ # an overloaded upstream is transient and retryable, while this one provably
69
+ # cannot succeed until a human runs `/login`.
70
+ AUTH_ERROR = "authentication_failed"
71
+
72
+ # What Claude Code renders for it. Used only to quote the operator a
73
+ # recognizable line in the email/summary — never as a detection signal (see
74
+ # the module docstring).
75
+ RENDERED = "Login expired · Please run /login"
76
+
77
+ # How far back into a transcript to read. A hung run's file is a few KB; a
78
+ # long interactive one is megabytes, and only its tail can be the last turn.
79
+ TAIL_BYTES = 256 * 1024
80
+
81
+ # How long a recorded outage keeps gating dispatch before one probe is allowed
82
+ # through. Bounded on purpose: a stale flag that never cleared would halt every
83
+ # scheduled task on the machine, which is a worse failure than the hang. Each
84
+ # fresh detection refreshes it, so a real outage keeps gating; a resolved one
85
+ # costs at most one fast failure to notice.
86
+ OUTAGE_TTL = timedelta(minutes=30)
87
+
88
+ # Owner-escalation throttle. Follows prompt_router's no-parent escalation
89
+ # (#905) and the dead-letter digest: an out-of-band email, sent on the first
90
+ # sighting and then at most once an hour while the outage persists. Unthrottled
91
+ # this would be one email per dispatch per outage.
92
+ ESCALATE_TTL = timedelta(hours=1)
93
+
94
+
95
+ def _config_dir() -> Path:
96
+ """Read through the MODULE, not a from-import (#902).
97
+
98
+ ``from .core import CONFIG_DIR`` binds the value at import time, so a test
99
+ (or anything else) that patches ``core.CONFIG_DIR`` is silently ignored and
100
+ the code writes to the real ``~/.agentwire``. That is the same trap
101
+ ``core.role_prompts_dir()`` exists to avoid, and here it would mean a test
102
+ suite scribbling a real outage gate onto the operator's machine.
103
+ """
104
+ from . import core
105
+
106
+ return Path(core.CONFIG_DIR)
107
+
108
+
109
+ def state_path() -> Path:
110
+ """The ONE outage record. Machine-wide, not per-session or per-task."""
111
+ return _config_dir() / "auth-expired" / "state.json"
112
+
113
+
114
+ def events_path() -> Path:
115
+ return _config_dir() / "auth-expired-events.jsonl"
116
+
117
+
118
+ def _now() -> datetime:
119
+ return datetime.now(timezone.utc)
120
+
121
+
122
+ def log_event(event: str, **fields) -> None:
123
+ """Append an event. Best-effort — telemetry must never break a dispatch."""
124
+ try:
125
+ path = events_path()
126
+ path.parent.mkdir(parents=True, exist_ok=True)
127
+ with open(path, "a") as f:
128
+ f.write(json.dumps({"ts": _now().isoformat(), "event": event, **fields}) + "\n")
129
+ except OSError:
130
+ pass
131
+
132
+
133
+ # ---------------------------------------------------------------------------
134
+ # Detection — the transcript
135
+ # ---------------------------------------------------------------------------
136
+
137
+
138
+ def _tail_lines(path: Path, limit: int = TAIL_BYTES) -> list[str]:
139
+ """The last complete lines of *path*, bounded by *limit* bytes.
140
+
141
+ The first line of a mid-file read is almost always a fragment, so it is
142
+ dropped rather than fed to ``json.loads`` — a partial row must read as
143
+ "nothing to see", never as a parse error that aborts the scan.
144
+ """
145
+ try:
146
+ size = path.stat().st_size
147
+ with open(path, "rb") as f:
148
+ if size > limit:
149
+ f.seek(size - limit)
150
+ chunk = f.read()
151
+ chunk = chunk.split(b"\n", 1)[1] if b"\n" in chunk else b""
152
+ else:
153
+ chunk = f.read()
154
+ except OSError:
155
+ return []
156
+ return [ln for ln in chunk.decode("utf-8", "replace").split("\n") if ln.strip()]
157
+
158
+
159
+ def last_assistant_turn(path: Path) -> dict | None:
160
+ """The last ``assistant`` row in *path*, or None.
161
+
162
+ "Last" is the whole point. A transcript that auth-failed at 08:00 and took
163
+ a real turn at 09:00 has recovered, and reporting it as expired would gate
164
+ the scheduler on a resolved outage. Reading only the final assistant row
165
+ makes recovery fall out of detection instead of needing a reset.
166
+ """
167
+ found = None
168
+ for line in _tail_lines(path):
169
+ try:
170
+ row = json.loads(line)
171
+ except (json.JSONDecodeError, ValueError):
172
+ continue
173
+ if isinstance(row, dict) and row.get("type") == "assistant":
174
+ found = row
175
+ return found
176
+
177
+
178
+ def row_is_auth_failure(row: dict | None) -> bool:
179
+ """Does *row* carry the expired-login rejection?
180
+
181
+ Keyed on the structured ``error`` field, not on the rendered text, so a
182
+ reworded message keeps working and an assistant turn that merely *says*
183
+ the phrase (an agent reporting on this very incident) never matches.
184
+
185
+ Rewording is proven, not assumed: the two real outages on disk render
186
+ DIFFERENTLY — "Login expired · Please run /login" (2026-08-04, Claude Code
187
+ 2.1.221) and "Not logged in · Please run /login" (2026-07-07, 2.1.201) —
188
+ and share this one field. Both are fixtured.
189
+
190
+ The residual risk is RESTRUCTURING, not rewording: if a future version
191
+ nests the error (say under ``message.error`` or an ``error.type``), this
192
+ returns False and the detector goes quiet rather than loud. Nothing here
193
+ can catch that on its own — the check to run when a Claude Code upgrade
194
+ lands is that ``error`` is still a top-level string on an api-error row.
195
+ """
196
+ if not isinstance(row, dict):
197
+ return False
198
+ return row.get("error") == AUTH_ERROR
199
+
200
+
201
+ def transcript_auth_failure(path: Path) -> bool:
202
+ """True iff *path*'s most recent assistant turn was refused for auth."""
203
+ return row_is_auth_failure(last_assistant_turn(path))
204
+
205
+
206
+ # ---------------------------------------------------------------------------
207
+ # Detection — locating the transcripts to read
208
+ # ---------------------------------------------------------------------------
209
+
210
+
211
+ def recorded_transcripts(session: str) -> list[Path]:
212
+ """Transcripts named by the session's own launch record (#871).
213
+
214
+ The strong path: agentwire MINTS the conversation id and records it with
215
+ the launch cwd, so this addresses the exact file rather than guessing.
216
+ Returns [] when the record predates #871 (or the session was never
217
+ recorded) — the caller falls back to :func:`touched_transcripts`, which is
218
+ still evidence rather than a guess.
219
+ """
220
+ from .core import load_session_metadata
221
+ from .history import PROJECTS_DIR, encode_project_path
222
+
223
+ try:
224
+ meta = load_session_metadata(session)
225
+ except Exception:
226
+ return []
227
+ cwd = meta.get("cwd_at_launch")
228
+ ids = meta.get("conversation_ids") or []
229
+ if not cwd or not ids:
230
+ return []
231
+ base = Path(PROJECTS_DIR) / encode_project_path(str(cwd))
232
+ return [p for p in (base / f"{cid}.jsonl" for cid in ids) if p.exists()]
233
+
234
+
235
+ def touched_transcripts(project_path, since: float) -> list[Path]:
236
+ """Transcripts in *project_path*'s history dir written since *since*.
237
+
238
+ The fallback for a session whose launch record predates #871 — which is
239
+ exactly ``memory-manager``'s shape on 2026-08-04, so a detector that only
240
+ handled the recorded path could not have seen the incident it was written
241
+ for.
242
+
243
+ Deliberately NOT "the newest ``.jsonl`` in the directory", the guess
244
+ CLAUDE.md warns against: this is scoped to one project dir AND to files
245
+ written during the window the caller is asking about, so a hit is a
246
+ transcript this run actually produced.
247
+ """
248
+ from .history import PROJECTS_DIR, encode_project_path
249
+
250
+ base = Path(PROJECTS_DIR) / encode_project_path(str(project_path))
251
+ try:
252
+ entries = list(base.glob("*.jsonl"))
253
+ except OSError:
254
+ return []
255
+ out = []
256
+ for p in entries:
257
+ try:
258
+ if p.stat().st_mtime >= since:
259
+ out.append(p)
260
+ except OSError:
261
+ continue
262
+ return sorted(out)
263
+
264
+
265
+ def detect(session: str, project_path=None, since: float | None = None) -> dict | None:
266
+ """Is *session*'s last turn an expired-login rejection?
267
+
268
+ Returns a detail dict (never a bare bool — the caller has to be able to
269
+ say WHICH transcript proved it) or None. Recorded transcripts first; the
270
+ touched-since fallback only when the record can't name one.
271
+ """
272
+ for path in recorded_transcripts(session):
273
+ if transcript_auth_failure(path):
274
+ return {"session": session, "transcript": str(path), "source": "recorded"}
275
+ if project_path is not None and since is not None:
276
+ for path in touched_transcripts(project_path, since):
277
+ if transcript_auth_failure(path):
278
+ return {"session": session, "transcript": str(path), "source": "touched"}
279
+ return None
280
+
281
+
282
+ # ---------------------------------------------------------------------------
283
+ # Machine-wide outage state
284
+ # ---------------------------------------------------------------------------
285
+
286
+
287
+ def read_state() -> dict | None:
288
+ try:
289
+ return json.loads(state_path().read_text())
290
+ except (OSError, json.JSONDecodeError):
291
+ return None
292
+
293
+
294
+ def write_state(state: dict) -> None:
295
+ """Atomic — a torn write must not leave an unparseable gate behind."""
296
+ path = state_path()
297
+ path.parent.mkdir(parents=True, exist_ok=True)
298
+ tmp = path.with_suffix(".tmp")
299
+ tmp.write_text(json.dumps(state, indent=2))
300
+ os.replace(tmp, path)
301
+
302
+
303
+ def clear_state() -> bool:
304
+ """Drop the outage record. True iff one was there.
305
+
306
+ Called from ``completion.wait_for_completion_signal``'s success path: a
307
+ written task summary is proof a turn ran, which is proof the login works.
308
+ That is what makes the operator-facing "reopens on the first successful
309
+ turn" a fact rather than a description of behavior nothing implements —
310
+ the mismatch #906 itself is about, at a smaller scale. ``OUTAGE_TTL``
311
+ remains the backstop for a fleet that isn't completing anything.
312
+ """
313
+ try:
314
+ state_path().unlink()
315
+ log_event("outage_cleared")
316
+ return True
317
+ except OSError:
318
+ return False
319
+
320
+
321
+ def outage_active(now: datetime | None = None) -> dict | None:
322
+ """The current outage, or None if there isn't a fresh one.
323
+
324
+ Freshness is the safety property: a recorded outage gates dispatch only
325
+ while it has been seen within :data:`OUTAGE_TTL`. Past that the gate opens
326
+ and the next dispatch acts as the probe — which, with detection in place,
327
+ fails in seconds instead of hours. A flag that gated forever would take the
328
+ whole scheduler down on a stale file.
329
+ """
330
+ state = read_state()
331
+ if not state:
332
+ return None
333
+ try:
334
+ seen = datetime.fromisoformat(state["last_seen"])
335
+ except (KeyError, TypeError, ValueError):
336
+ return None
337
+ if (now or _now()) - seen > OUTAGE_TTL:
338
+ return None
339
+ return state
340
+
341
+
342
+ def record_outage(detail: dict, source: str = "ensure") -> dict:
343
+ """Record (or refresh) the machine-wide outage and escalate once.
344
+
345
+ ``detected_at`` is carried forward across refreshes so the operator can see
346
+ how long the outage has run; refreshing it each sighting would make a
347
+ four-hour outage read as seconds old — the same defect #905 fixed on
348
+ ``detected_at`` in the prompt sweep.
349
+ """
350
+ prior = read_state() or {}
351
+ now = _now()
352
+ sessions = list(prior.get("sessions") or [])
353
+ if detail.get("session") and detail["session"] not in sessions:
354
+ sessions.append(detail["session"])
355
+ state = {
356
+ "detected_at": prior.get("detected_at") or now.isoformat(),
357
+ "last_seen": now.isoformat(),
358
+ "sessions": sessions,
359
+ "transcript": detail.get("transcript"),
360
+ "source": source,
361
+ "host": socket.gethostname(),
362
+ "escalated_at": prior.get("escalated_at"),
363
+ }
364
+ state["escalated_at"] = _escalate(state, prior)
365
+ write_state(state)
366
+ log_event("outage_detected", session=detail.get("session"),
367
+ transcript=detail.get("transcript"), source=source)
368
+ return state
369
+
370
+
371
+ def _escalate(state: dict, prior: dict) -> str | None:
372
+ """Email the owner once per :data:`ESCALATE_TTL` while the outage persists.
373
+
374
+ Best-effort in the strong sense: a missing key or a provider failure must
375
+ never turn "we detected the outage and failed the task fast" into an
376
+ exception that fails it slowly instead. The outage state is written either
377
+ way, so the gate works with or without the email.
378
+
379
+ Consequence worth naming: only a SUCCESSFUL send stamps ``escalated_at``,
380
+ so a persistently broken sender is retried once per detection rather than
381
+ once per :data:`ESCALATE_TTL`. That is the intended trade — a send that
382
+ silently counted as delivered would lose the escalation entirely, and
383
+ losing it is strictly worse than retrying it. The retry is cheap (the
384
+ email path is already best-effort and off the critical path) and it stops
385
+ the moment one send lands.
386
+ """
387
+ previous = prior.get("escalated_at")
388
+ if previous:
389
+ try:
390
+ if _now() - datetime.fromisoformat(previous) < ESCALATE_TTL:
391
+ return previous
392
+ except (TypeError, ValueError):
393
+ pass
394
+ try:
395
+ from .channels.email import send_email
396
+
397
+ sessions = ", ".join(state.get("sessions") or []) or "(none recorded)"
398
+ body = "\n".join([
399
+ f"Claude Code on `{state.get('host')}` is refusing every turn with "
400
+ f"**{RENDERED}** (`error: {AUTH_ERROR}`).",
401
+ "",
402
+ f"- **First seen:** {state.get('detected_at')}",
403
+ f"- **Sessions affected so far:** {sessions}",
404
+ f"- **Evidence:** {state.get('transcript')}",
405
+ "",
406
+ "Scheduled dispatches are being skipped rather than each burning its "
407
+ "own timeout. Run `/login` in any Claude Code session to clear it; "
408
+ "the gate re-probes automatically and reopens on the first "
409
+ "successful turn.",
410
+ ])
411
+ result = send_email(
412
+ subject=f"[agentwire] Claude login expired on {state.get('host')} — dispatch gated",
413
+ body=body,
414
+ )
415
+ if getattr(result, "success", False):
416
+ log_event("escalated", sessions=state.get("sessions"))
417
+ return _now().isoformat()
418
+ log_event("escalate_failed", error=getattr(result, "error", None))
419
+ except Exception as exc: # never break the caller
420
+ log_event("escalate_failed", error=str(exc))
421
+ return previous
422
+
423
+
424
+ def check_and_flag(
425
+ session: str, project_path=None, since: float | None = None, source: str = "ensure"
426
+ ) -> dict | None:
427
+ """The fast-path probe for polling loops. Mirrors ``usage_limit.check_and_park``.
428
+
429
+ Cheap when nothing is wrong (one or two bounded tail reads), records the
430
+ machine-wide outage and escalates when it is. Returns the detail dict so
431
+ the caller can name the transcript in its own failure message.
432
+ """
433
+ detail = detect(session, project_path=project_path, since=since)
434
+ if detail is None:
435
+ return None
436
+ record_outage(detail, source=source)
437
+ return detail
438
+
439
+
440
+ def summary_line(detail: dict | None = None) -> str:
441
+ """The operator-facing reason string. Names the cause, not the symptom."""
442
+ where = f" (evidence: {detail['transcript']})" if detail and detail.get("transcript") else ""
443
+ return (
444
+ f"Claude login expired — the agent's turn was refused with "
445
+ f"'{RENDERED}' (error: {AUTH_ERROR}); no completion signal can arrive "
446
+ f"until `/login` is run{where}"
447
+ )