agentwire-dev 1.60.0__tar.gz → 1.61.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 (489) hide show
  1. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/PKG-INFO +1 -1
  2. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/__init__.py +1 -1
  3. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/core.py +69 -20
  4. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/doctor_cli.py +24 -0
  5. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/limits_cli.py +16 -6
  6. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler/__init__.py +4 -0
  7. agentwire_dev-1.61.0/agentwire/scheduler/zombie.py +160 -0
  8. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/session_cli.py +92 -42
  9. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/integration/test_worktree_cmd.py +72 -0
  10. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_cli_commands.py +77 -0
  11. agentwire_dev-1.61.0/tests/unit/test_guarded_launch_command.py +73 -0
  12. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_limits_tick_isolation.py +5 -2
  13. agentwire_dev-1.61.0/tests/unit/test_scheduler_zombie.py +269 -0
  14. agentwire_dev-1.61.0/tests/unit/test_session_created_by_env.py +56 -0
  15. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.agentwire.yml.example +0 -0
  16. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.claude/commands/handoff.md +0 -0
  17. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.claude/skills/wiki/SKILL.md +0 -0
  18. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/FUNDING.yml +0 -0
  19. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  20. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  21. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
  22. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  23. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/workflows/pytest.yml +0 -0
  24. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/workflows/ruff.yml +0 -0
  25. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/workflows/security.yml +0 -0
  26. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.github/workflows/tts-smoke.yml +0 -0
  27. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/.gitignore +0 -0
  28. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/AGENTS.md +0 -0
  29. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/CODE_OF_CONDUCT.md +0 -0
  30. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/CONTRIBUTING.md +0 -0
  31. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/Dockerfile.local +0 -0
  32. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/LICENSE +0 -0
  33. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/README.md +0 -0
  34. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/RELEASING.md +0 -0
  35. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/SECURITY.md +0 -0
  36. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/SPONSORS.md +0 -0
  37. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/__main__.py +0 -0
  38. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/agents/__init__.py +0 -0
  39. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/agents/base.py +0 -0
  40. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/agents/tmux.py +0 -0
  41. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/cached_status.py +0 -0
  42. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/channels/__init__.py +0 -0
  43. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/channels/base.py +0 -0
  44. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/channels/email.py +0 -0
  45. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/channels/push.py +0 -0
  46. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/channels/quo.py +0 -0
  47. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/channels_cli.py +0 -0
  48. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/chrome_tabs.py +0 -0
  49. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/completion.py +0 -0
  50. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/config.py +0 -0
  51. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/config_cli.py +0 -0
  52. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/council/__init__.py +0 -0
  53. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/council/cli.py +0 -0
  54. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/council/inbox.py +0 -0
  55. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/council/minutes.py +0 -0
  56. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/council/state.py +0 -0
  57. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/council/view.py +0 -0
  58. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/devices.py +0 -0
  59. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/diff_cli.py +0 -0
  60. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/doctor_voice.py +0 -0
  61. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/ensure_cli.py +0 -0
  62. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/fetch.py +0 -0
  63. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/handoff/__init__.py +0 -0
  64. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/handoff/git_state.py +0 -0
  65. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/handoff/instructions.py +0 -0
  66. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/handoff/parser.py +0 -0
  67. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/handoff/renderer.py +0 -0
  68. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/handoff/schema.py +0 -0
  69. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/handoff_cli.py +0 -0
  70. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/history.py +0 -0
  71. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/history_cli.py +0 -0
  72. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/__init__.py +0 -0
  73. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/agentwire-permission.sh +0 -0
  74. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/__init__.py +0 -0
  75. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
  76. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
  77. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
  78. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
  79. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
  80. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
  81. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
  82. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
  83. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
  84. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
  85. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
  86. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
  87. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
  88. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
  89. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
  90. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
  91. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
  92. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
  93. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
  94. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
  95. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
  96. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/idle-handler.sh +0 -0
  97. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks/queue-processor.sh +0 -0
  98. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/hooks_cli.py +0 -0
  99. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/inbox.py +0 -0
  100. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/listen.py +0 -0
  101. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/locking.py +0 -0
  102. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/machine_cli.py +0 -0
  103. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_channels.py +0 -0
  104. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_chrome.py +0 -0
  105. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_cli.py +0 -0
  106. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_core.py +0 -0
  107. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_council.py +0 -0
  108. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_desktop.py +0 -0
  109. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_handoff.py +0 -0
  110. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_history.py +0 -0
  111. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_listen.py +0 -0
  112. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_lock.py +0 -0
  113. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_machine.py +0 -0
  114. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_msg.py +0 -0
  115. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_notify.py +0 -0
  116. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_pane.py +0 -0
  117. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_projects.py +0 -0
  118. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_scheduler.py +0 -0
  119. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_scratchpad.py +0 -0
  120. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_server.py +0 -0
  121. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_services.py +0 -0
  122. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_session.py +0 -0
  123. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_status.py +0 -0
  124. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_task.py +0 -0
  125. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_tunnels.py +0 -0
  126. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_voice.py +0 -0
  127. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_wiki.py +0 -0
  128. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/mcp_worktree.py +0 -0
  129. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/msg_cli.py +0 -0
  130. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/network.py +0 -0
  131. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/notify_cli.py +0 -0
  132. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/onboarding.py +0 -0
  133. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/palette_cli.py +0 -0
  134. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/pane_cli.py +0 -0
  135. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/pane_manager.py +0 -0
  136. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/portal_cli.py +0 -0
  137. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/project_config.py +0 -0
  138. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/projects.py +0 -0
  139. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/prompt_router.py +0 -0
  140. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/prompts_cli.py +0 -0
  141. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/push_cli.py +0 -0
  142. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/push_store.py +0 -0
  143. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/repo_cli.py +0 -0
  144. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/research.py +0 -0
  145. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/__init__.py +0 -0
  146. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/agentwire.md +0 -0
  147. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/anchor.md +0 -0
  148. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/chatbot.md +0 -0
  149. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/contributor.md +0 -0
  150. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/correspondent.md +0 -0
  151. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/council-brain.md +0 -0
  152. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/council-conscience.md +0 -0
  153. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/council-critic.md +0 -0
  154. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/council-devils-advocate.md +0 -0
  155. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/council-gut.md +0 -0
  156. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/council-historian.md +0 -0
  157. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/council-member.md +0 -0
  158. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/council-orchestrator.md +0 -0
  159. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/init.md +0 -0
  160. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/notifications.md +0 -0
  161. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/orchestrator.md +0 -0
  162. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/soul.md +0 -0
  163. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/task-runner.md +0 -0
  164. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/voice.md +0 -0
  165. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/worker-worktree.md +0 -0
  166. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles/worker.md +0 -0
  167. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/roles_cli.py +0 -0
  168. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/__init__.py +0 -0
  169. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/artifacts.py +0 -0
  170. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/config.py +0 -0
  171. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/council.py +0 -0
  172. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/desktop.py +0 -0
  173. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/history.py +0 -0
  174. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/machines.py +0 -0
  175. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/notify.py +0 -0
  176. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/palette.py +0 -0
  177. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/permission.py +0 -0
  178. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/projects.py +0 -0
  179. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/push.py +0 -0
  180. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/safety.py +0 -0
  181. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/scheduler.py +0 -0
  182. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/scratchpad.py +0 -0
  183. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/sessions.py +0 -0
  184. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/sessions_admin.py +0 -0
  185. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/routes/voice.py +0 -0
  186. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/safety/__init__.py +0 -0
  187. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/safety/_core.py +0 -0
  188. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/safety_cli.py +0 -0
  189. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/safety_commands.py +0 -0
  190. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler/dispatch.py +0 -0
  191. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler/gates.py +0 -0
  192. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler/loop.py +0 -0
  193. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler/models.py +0 -0
  194. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler/report.py +0 -0
  195. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler/schedule.py +0 -0
  196. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler/state.py +0 -0
  197. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scheduler_cli.py +0 -0
  198. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/scratchpad.py +0 -0
  199. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/security.py +0 -0
  200. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/send_cli.py +0 -0
  201. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/server.py +0 -0
  202. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/services.py +0 -0
  203. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/session_context.py +0 -0
  204. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/session_ready.py +0 -0
  205. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/ssh.py +0 -0
  206. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
  207. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
  208. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
  209. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
  210. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
  211. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/announcements.json +0 -0
  212. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/apple-touch-icon.png +0 -0
  213. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/css/desktop.css +0 -0
  214. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/css/mobile.css +0 -0
  215. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/favicon-32.png +0 -0
  216. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/favicon-64.png +0 -0
  217. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/bear.webp +0 -0
  218. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/cat.webp +0 -0
  219. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/crown.webp +0 -0
  220. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
  221. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
  222. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
  223. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/deer.webp +0 -0
  224. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/drone.webp +0 -0
  225. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/eagle.webp +0 -0
  226. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/fox.webp +0 -0
  227. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/hawk.webp +0 -0
  228. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/horse.webp +0 -0
  229. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/lion.webp +0 -0
  230. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/rabbit.webp +0 -0
  231. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/robot.webp +0 -0
  232. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/tiger.webp +0 -0
  233. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/icons/sessions/wolf.webp +0 -0
  234. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/img/icon-192.png +0 -0
  235. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/img/icon-512.png +0 -0
  236. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/.gitkeep +0 -0
  237. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/announcement-modal.js +0 -0
  238. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/api.js +0 -0
  239. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/artifact-window.js +0 -0
  240. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/collage.js +0 -0
  241. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/command-palette.js +0 -0
  242. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/council-window.js +0 -0
  243. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
  244. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/desktop-manager.js +0 -0
  245. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/desktop.js +0 -0
  246. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/help-modal.js +0 -0
  247. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/icon-manager.js +0 -0
  248. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/mobile.js +0 -0
  249. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/notification-prefs.js +0 -0
  250. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/notifications-panel.js +0 -0
  251. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/ptt.js +0 -0
  252. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/push-client.js +0 -0
  253. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/review-window.js +0 -0
  254. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/safety-shared.js +0 -0
  255. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/safety-window.js +0 -0
  256. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/scratchpad.js +0 -0
  257. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/service-classification.js +0 -0
  258. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/session-id.js +0 -0
  259. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/session-window.js +0 -0
  260. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/shortcuts.js +0 -0
  261. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
  262. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/config-section.js +0 -0
  263. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/council-section.js +0 -0
  264. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
  265. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
  266. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
  267. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
  268. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/services-section.js +0 -0
  269. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar/sessions-section.js +0 -0
  270. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/sidebar.js +0 -0
  271. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
  272. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/tile-manager.js +0 -0
  273. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/toast.js +0 -0
  274. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/token-modal.js +0 -0
  275. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/utils/ansi.js +0 -0
  276. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/utils/swipe.js +0 -0
  277. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
  278. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/voice/browser-stt.js +0 -0
  279. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/voice/browser-tts.js +0 -0
  280. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/voice/jargon.js +0 -0
  281. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/voice/prompt.js +0 -0
  282. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
  283. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/manifest.webmanifest +0 -0
  284. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/static/service-worker.js +0 -0
  285. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/stt/__init__.py +0 -0
  286. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/stt/base.py +0 -0
  287. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/stt/cloud.py +0 -0
  288. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/stt/engine.py +0 -0
  289. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/stt/local.py +0 -0
  290. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/stt/server_backend.py +0 -0
  291. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/stt/stt_server.py +0 -0
  292. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/system_cli.py +0 -0
  293. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tabs_cli.py +0 -0
  294. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tasks.py +0 -0
  295. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tasks_cli.py +0 -0
  296. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/__init__.py +0 -0
  297. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/base.html +0 -0
  298. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/council/minutes.html.j2 +0 -0
  299. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/desktop.html +0 -0
  300. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/email_notification.html +0 -0
  301. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
  302. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
  303. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/mobile.html +0 -0
  304. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/pair.html +0 -0
  305. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templates/tmux.conf +0 -0
  306. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/templating.py +0 -0
  307. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/aws.yaml +0 -0
  308. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/docker.yaml +0 -0
  309. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/gcp.yaml +0 -0
  310. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/gh.yaml +0 -0
  311. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/git.yaml +0 -0
  312. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/gws.yaml +0 -0
  313. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/kubectl.yaml +0 -0
  314. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/npm.yaml +0 -0
  315. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/terraform.yaml +0 -0
  316. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tooldefs/uv.yaml +0 -0
  317. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/__init__.py +0 -0
  318. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/audio.py +0 -0
  319. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/base.py +0 -0
  320. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/engines/__init__.py +0 -0
  321. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/engines/chatterbox.py +0 -0
  322. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/engines/kokoro.py +0 -0
  323. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/engines/zonos.py +0 -0
  324. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/kokoro_server.py +0 -0
  325. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/local.py +0 -0
  326. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts/registry.py +0 -0
  327. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts_cli.py +0 -0
  328. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tts_server.py +0 -0
  329. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tunnels.py +0 -0
  330. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/tunnels_cli.py +0 -0
  331. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/usage_limit.py +0 -0
  332. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/utils/__init__.py +0 -0
  333. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/utils/chunker.py +0 -0
  334. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/utils/event_log.py +0 -0
  335. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/utils/file_io.py +0 -0
  336. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/utils/paths.py +0 -0
  337. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/utils/speech.py +0 -0
  338. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/utils/subprocess.py +0 -0
  339. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/validation.py +0 -0
  340. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/voice_status.py +0 -0
  341. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/wiki.py +0 -0
  342. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/wiki_audit.py +0 -0
  343. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/wiki_cli.py +0 -0
  344. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/worktree.py +0 -0
  345. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/agentwire/worktree_registry.py +0 -0
  346. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/decisions/obsidian-second-brain.md +0 -0
  347. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/logo.png +0 -0
  348. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/INDEX.md +0 -0
  349. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/architecture.md +0 -0
  350. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/briefing-mode.md +0 -0
  351. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/communication/channels.md +0 -0
  352. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/communication/hammerspoon.md +0 -0
  353. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/communication/handoff.md +0 -0
  354. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/concepts.md +0 -0
  355. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/council.md +0 -0
  356. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/deployment/remote-access.md +0 -0
  357. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/deployment/remote-machines.md +0 -0
  358. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/glossary.md +0 -0
  359. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
  360. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/internals/damage-control.md +0 -0
  361. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/internals/parallel-refactor.md +0 -0
  362. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/internals/portal.md +0 -0
  363. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/internals/shell-escaping.md +0 -0
  364. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/internals/troubleshooting.md +0 -0
  365. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/internals/window-collage.md +0 -0
  366. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/quickstart.md +0 -0
  367. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
  368. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
  369. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
  370. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/security/damage-control-hardening.md +0 -0
  371. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/security/pip-audit.md +0 -0
  372. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/security/remote-access-hardening.md +0 -0
  373. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/security/secrets.md +0 -0
  374. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/services.md +0 -0
  375. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
  376. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/sessions/messaging.md +0 -0
  377. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/sessions/prompt-routing.md +0 -0
  378. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/sessions/window-sizing.md +0 -0
  379. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
  380. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/usage-limit-recovery.md +0 -0
  381. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/voice/shim-contract.md +0 -0
  382. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/voice/stt-cloud.md +0 -0
  383. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
  384. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
  385. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/pyproject.toml +0 -0
  386. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/conftest.py +0 -0
  387. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/e2e/test_portal_ui.py +0 -0
  388. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/fixtures/sample_agentwire.yml +0 -0
  389. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/fixtures/sample_config.yaml +0 -0
  390. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/fixtures/sample_scheduler.yaml +0 -0
  391. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/integration/test_council_portal.py +0 -0
  392. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/integration/test_scheduler_board.py +0 -0
  393. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/integration/test_send_verified_tmux.py +0 -0
  394. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/integration/test_server_websockets.py +0 -0
  395. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_announcements.py +0 -0
  396. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_build_agent_command.py +0 -0
  397. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_channels.py +0 -0
  398. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_chrome_tabs.py +0 -0
  399. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_cli_output.py +0 -0
  400. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_cli_smoke.py +0 -0
  401. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_config.py +0 -0
  402. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_config_cli.py +0 -0
  403. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_control_plane_protection.py +0 -0
  404. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_core_created_by_rooting.py +0 -0
  405. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_council_cli.py +0 -0
  406. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_council_inbox.py +0 -0
  407. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_council_minutes.py +0 -0
  408. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_council_state.py +0 -0
  409. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_council_view.py +0 -0
  410. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_damage_control_bypass.py +0 -0
  411. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_damage_control_hooks.py +0 -0
  412. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_damage_control_sync.py +0 -0
  413. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_dangling_worktrees.py +0 -0
  414. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_devices.py +0 -0
  415. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_diff_cli.py +0 -0
  416. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_doctor_task_migration.py +0 -0
  417. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_doctor_voice.py +0 -0
  418. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_event_log.py +0 -0
  419. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_file_io.py +0 -0
  420. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_handoff_git_state.py +0 -0
  421. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_handoff_instructions.py +0 -0
  422. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_handoff_parser.py +0 -0
  423. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_handoff_renderer.py +0 -0
  424. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_history.py +0 -0
  425. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_hooks_install.py +0 -0
  426. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_idle_handler.py +0 -0
  427. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_idle_nag.py +0 -0
  428. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_inbox.py +0 -0
  429. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_init_command.py +0 -0
  430. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_install_parity.py +0 -0
  431. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_locking.py +0 -0
  432. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_mcp_server.py +0 -0
  433. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_mcp_tools_args.py +0 -0
  434. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_msg_cli.py +0 -0
  435. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_notify_cli.py +0 -0
  436. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_onboarding_reinit.py +0 -0
  437. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_palette_cli.py +0 -0
  438. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_pip_environment.py +0 -0
  439. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_portal_api.py +0 -0
  440. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_posture_default.py +0 -0
  441. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_project_config.py +0 -0
  442. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_prompt_router.py +0 -0
  443. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_push.py +0 -0
  444. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_rebuild_guard.py +0 -0
  445. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_repo_cli.py +0 -0
  446. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_roles.py +0 -0
  447. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_routes_snapshot.py +0 -0
  448. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_safety_commands.py +0 -0
  449. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_safety_disabled_rules.py +0 -0
  450. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_safety_escape_hatch.py +0 -0
  451. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_safety_heal.py +0 -0
  452. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_safety_kill_switch.py +0 -0
  453. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_scheduler.py +0 -0
  454. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_scheduler_parsing.py +0 -0
  455. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_scratchpad.py +0 -0
  456. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_security.py +0 -0
  457. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_server_async.py +0 -0
  458. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_server_pure.py +0 -0
  459. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_services.py +0 -0
  460. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_session_context.py +0 -0
  461. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_session_ready.py +0 -0
  462. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_shared_dir_guard.py +0 -0
  463. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_shim_selfheal.py +0 -0
  464. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_skill_install.py +0 -0
  465. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_speech_tags.py +0 -0
  466. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_ssh.py +0 -0
  467. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_stt_backend.py +0 -0
  468. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_stt_cloud.py +0 -0
  469. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_stt_engine.py +0 -0
  470. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_task_cli.py +0 -0
  471. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_tasks.py +0 -0
  472. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_tasks_cli.py +0 -0
  473. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_templating.py +0 -0
  474. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_terminal_resize.py +0 -0
  475. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_tmux_template.py +0 -0
  476. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_tts_engine_resolution.py +0 -0
  477. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_tts_local.py +0 -0
  478. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_tunnels_probe.py +0 -0
  479. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_unattended_env_isolation.py +0 -0
  480. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_usage_limit.py +0 -0
  481. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_validation.py +0 -0
  482. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_voice_status.py +0 -0
  483. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_wiki.py +0 -0
  484. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_wiki_audit.py +0 -0
  485. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_window_cycling_binding.py +0 -0
  486. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_worktree.py +0 -0
  487. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_worktree_branch_cleanup.py +0 -0
  488. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_worktree_layout.py +0 -0
  489. {agentwire_dev-1.60.0 → agentwire_dev-1.61.0}/tests/unit/test_worktree_registry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentwire-dev
3
- Version: 1.60.0
3
+ Version: 1.61.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.60.0"
3
+ __version__ = "1.61.0"
@@ -148,15 +148,25 @@ def _build_tmux_env_flags_shell(env: dict[str, str]) -> str:
148
148
  return " ".join(parts) + " "
149
149
 
150
150
 
151
- def _set_session_name_env(agent: "AgentCommand", session_name: str) -> None:
152
- """Stamp ``AGENTWIRE_SESSION_NAME`` onto an ``AgentCommand.env``.
151
+ def _set_session_name_env(agent: "AgentCommand", session_name: str, created_by: str | None = None) -> None:
152
+ """Stamp ``AGENTWIRE_SESSION_NAME`` (and, when there's a real parent,
153
+ ``AGENTWIRE_CREATED_BY``) onto an ``AgentCommand.env``.
153
154
 
154
155
  Every session created via ``cmd_new`` / ``cmd_spawn`` / ``cmd_recreate``
155
- / ``cmd_fork`` / scheduler-spawn paths gets this so downstream tooling
156
- (notably the worker damage-control rules in ``safety/_core.py``)
157
- can identify which agentwire session the running tool is part of.
156
+ / ``cmd_fork`` / scheduler-spawn paths gets ``AGENTWIRE_SESSION_NAME`` so
157
+ downstream tooling (notably the worker damage-control rules in
158
+ ``safety/_core.py``) can identify which agentwire session the running
159
+ tool is part of.
160
+
161
+ ``created_by`` of ``''`` (root/orchestrator) or ``None`` means no
162
+ parent — ``AGENTWIRE_CREATED_BY`` is deliberately left UNSET rather than
163
+ set to an empty string, so the bare pre-agent shell's launch-crash guard
164
+ (``_guarded_launch_command``) can tell "has a parent to escalate to"
165
+ apart from "root session, email the owner" with a plain ``-n`` test (#743).
158
166
  """
159
167
  agent.env["AGENTWIRE_SESSION_NAME"] = session_name
168
+ if created_by:
169
+ agent.env["AGENTWIRE_CREATED_BY"] = created_by
160
170
 
161
171
 
162
172
  def inject_session_env(session: str, env: dict[str, str], remote_host: str | None = None) -> None:
@@ -847,6 +857,52 @@ def _run_remote(machine_id: str, command: str) -> subprocess.CompletedProcess:
847
857
  )
848
858
 
849
859
 
860
+ def _guarded_launch_command(path_str: str, agent_cmd: str | None) -> str:
861
+ """Build the pane's ``cd <path> && <agent_cmd>`` line with a missing-dir guard (#739).
862
+
863
+ A crashed worktree create can leave ``path_str`` absent by the time the
864
+ pane actually runs its ``cd`` (race between ``agentwire new`` reporting
865
+ success and the async pane launch, or an external actor removing the
866
+ dir). Without a guard, ``cd`` fails, the shell prints an error and
867
+ carries on, and ``agent_cmd`` (e.g. ``claude``) then launches from the
868
+ WRONG cwd and crashes — dropping the pane to a bare shell that the
869
+ idle-reaper never touches (it only reaps a *running* agent going idle),
870
+ so it lingers forever.
871
+
872
+ On a missing dir this instead alerts and exits the shell, which tears the
873
+ tmux session down instead of leaving a zombie. ``agent_cmd`` never runs.
874
+
875
+ Two alert routes, both shell-runtime-gated on env vars stamped at launch
876
+ (``_set_session_name_env``), so this function stays a pure string builder
877
+ with no Python-level knowledge of the session's parent (#743):
878
+ - A real recorded parent (``$AGENTWIRE_CREATED_BY`` set) gets the crash
879
+ escalated to its msg inbox — in-band, not just an email the human has
880
+ to forward.
881
+ - No parent (root/orchestrator sessions, the genuine scheduler-dispatch
882
+ case) falls back to the original owner email, still gated on
883
+ ``$AGENTWIRE_UNATTENDED=1`` (see ``_with_unattended_env``).
884
+ """
885
+ quoted_path = shlex.quote(path_str)
886
+ session_ref = "${AGENTWIRE_SESSION_NAME:-unknown session}"
887
+ missing_body = f"cd failed at launch: {path_str}"
888
+ notify_parent = (
889
+ '[ -n "$AGENTWIRE_CREATED_BY" ] && agentwire msg send --to "$AGENTWIRE_CREATED_BY" '
890
+ f'--kind escalation --subject "agentwire: worktree missing at launch — {session_ref}" '
891
+ f'--body "{missing_body}" >/dev/null 2>&1'
892
+ )
893
+ notify_owner = (
894
+ '[ -z "$AGENTWIRE_CREATED_BY" ] && [ "$AGENTWIRE_UNATTENDED" = "1" ] && agentwire email '
895
+ f'--subject "agentwire: worktree missing — {session_ref}" '
896
+ f'--body "{missing_body}" >/dev/null 2>&1'
897
+ )
898
+ alert = (
899
+ f"echo \"agentwire: worktree missing at launch, aborting: {path_str}\" >&2; "
900
+ f"{notify_parent}; {notify_owner}"
901
+ )
902
+ guard = f"cd {quoted_path} || {{ {alert}; exit 1; }}"
903
+ return f"{guard} && {agent_cmd}" if agent_cmd else guard
904
+
905
+
850
906
  def _launch_tmux_session(
851
907
  session_name: str,
852
908
  session_path,
@@ -859,8 +915,9 @@ def _launch_tmux_session(
859
915
  The one launch sequence shared by ``new`` / ``recreate`` / ``fork`` (#630):
860
916
  `tmux new-session -e K=V` injects *env* into the session environment
861
917
  BEFORE the initial shell starts (post-hoc `set-environment` never reaches
862
- it), then `send-keys` cd's into place and, if *agent_cmd* is non-empty,
863
- starts the agent after a short settle.
918
+ it), then `send-keys` cd's into place (guarded see
919
+ ``_guarded_launch_command``) and, if *agent_cmd* is non-empty, starts the
920
+ agent after a short settle.
864
921
 
865
922
  Local (machine_id None): runs subprocess calls with check=True (raises on
866
923
  tmux failure) and returns None. Remote: runs one composite shell command
@@ -869,17 +926,14 @@ def _launch_tmux_session(
869
926
  import time
870
927
 
871
928
  path_str = str(session_path)
929
+ launch_cmd = _guarded_launch_command(path_str, agent_cmd)
872
930
  if machine_id:
873
931
  env_flags = _build_tmux_env_flags_shell(env)
874
932
  create_cmd = (
875
933
  f"tmux new-session -d -s {shlex.quote(session_name)} -c {shlex.quote(path_str)} {env_flags}&& "
876
- f"tmux send-keys -t {shlex.quote(session_name)} 'cd {shlex.quote(path_str)}' Enter"
934
+ f"sleep 0.1 && "
935
+ f"tmux send-keys -t {shlex.quote(session_name)} {shlex.quote(launch_cmd)} Enter"
877
936
  )
878
- if agent_cmd:
879
- create_cmd += (
880
- f" && sleep 0.1 && "
881
- f"tmux send-keys -t {shlex.quote(session_name)} {shlex.quote(agent_cmd)} Enter"
882
- )
883
937
  return _run_remote(machine_id, create_cmd)
884
938
 
885
939
  subprocess.run(
@@ -887,16 +941,11 @@ def _launch_tmux_session(
887
941
  *_build_tmux_env_flags(env)],
888
942
  check=True,
889
943
  )
944
+ time.sleep(0.1)
890
945
  subprocess.run(
891
- ["tmux", "send-keys", "-t", session_name, f"cd {shlex.quote(path_str)}", "Enter"],
946
+ ["tmux", "send-keys", "-t", session_name, launch_cmd, "Enter"],
892
947
  check=True,
893
948
  )
894
- time.sleep(0.1)
895
- if agent_cmd:
896
- subprocess.run(
897
- ["tmux", "send-keys", "-t", session_name, agent_cmd, "Enter"],
898
- check=True,
899
- )
900
949
  return None
901
950
 
902
951
 
@@ -1008,6 +1008,30 @@ def cmd_doctor(args) -> int:
1008
1008
  except Exception as e:
1009
1009
  print(f" [..] Could not check managed voice shim liveness: {e}")
1010
1010
 
1011
+ # 14. Zombie scheduler sessions (#739): a worktree dispatch whose launch
1012
+ # crashed before the agent started (e.g. the worktree dir went missing
1013
+ # between `agentwire new` reporting success and the pane's `cd`) drops to
1014
+ # a bare shell the idle-reaper never touches. `agentwire limits tick`
1015
+ # self-heals these every minute, so a live one here means the watchdog
1016
+ # isn't installed/running, not that reaping is broken.
1017
+ print("\nChecking for zombie scheduler sessions (#739)...")
1018
+ try:
1019
+ from .scheduler import scan_zombie_sessions
1020
+
1021
+ zombie_sessions = scan_zombie_sessions()
1022
+ if not zombie_sessions:
1023
+ print(" [ok] No zombie scheduler sessions found")
1024
+ else:
1025
+ issues_found += 1
1026
+ print(f" [!!] {len(zombie_sessions)} scheduler session(s) stuck at a bare shell:")
1027
+ for z in zombie_sessions:
1028
+ print(f" - {z['session']} ({z['command']}, {z['age_seconds']}s old)")
1029
+ print(" `agentwire limits tick` reaps these automatically — "
1030
+ "run it now, or check the usage-limit watchdog is installed "
1031
+ "(`agentwire limits install`).")
1032
+ except Exception as e:
1033
+ print(f" [..] Could not check for zombie scheduler sessions: {e}")
1034
+
1011
1035
  # Summary
1012
1036
  print()
1013
1037
  print("-" * 60)
@@ -177,16 +177,20 @@ def cmd_limits_tick(args) -> int:
177
177
  """One watchdog pass (called by launchd every minute).
178
178
 
179
179
  Runs the usage-limit sweep FIRST, then prompt routing (#276), then the
180
- polite-message inbox drain (#296), then context auto-management (#442)
181
- the ordering guarantees a usage-limit dialog is parked before any sweep
182
- looks at the pane, that the inbox only ever delivers to panes the prompt
183
- sweep already cleared, and that auto-``/clear`` runs LAST so it never fights
184
- a pending paste/prompt for the same idle, empty box.
180
+ polite-message inbox drain (#296), then context auto-management (#442),
181
+ then the zombie-scheduler-session reap (#739) the ordering guarantees a
182
+ usage-limit dialog is parked before any sweep looks at the pane, that the
183
+ inbox only ever delivers to panes the prompt sweep already cleared, that
184
+ auto-``/clear`` runs before the reap so it never fights a pending
185
+ paste/prompt for the same idle, empty box, and that the reap runs LAST
186
+ since it kills sessions outright (nothing later should still be acting on
187
+ one).
185
188
 
186
189
  Each stage runs inside :func:`_run_stage` so an exception in one subsystem
187
190
  is logged and skipped rather than aborting the whole cycle (#490).
188
191
  """
189
192
  from agentwire import inbox, prompt_router, session_context
193
+ from agentwire.scheduler import zombie as scheduler_zombie
190
194
 
191
195
  result = _run_stage(
192
196
  "usage_limit", usage_limit.tick,
@@ -197,9 +201,12 @@ def cmd_limits_tick(args) -> int:
197
201
  "inbox", inbox.tick, {"flushed": [], "deferred": []})
198
202
  context = _run_stage(
199
203
  "session_context", session_context.tick, {"acted": [], "deferred": []})
204
+ zombies = _run_stage(
205
+ "scheduler_zombie", scheduler_zombie.tick, {"killed": []})
200
206
  if getattr(args, "json", False):
201
207
  print(json.dumps({
202
- **result, "prompts": prompts, "messages": messages, "context": context,
208
+ **result, "prompts": prompts, "messages": messages,
209
+ "context": context, "zombies": zombies,
203
210
  }))
204
211
  return 0
205
212
  if result.get("skipped"):
@@ -237,6 +244,9 @@ def cmd_limits_tick(args) -> int:
237
244
  if ctx_deferred:
238
245
  print("context deferred: " + ", ".join(
239
246
  f"{e['session']}({e['deferred']})" for e in ctx_deferred))
247
+ killed = zombies.get("killed") or []
248
+ if killed:
249
+ print("zombie scheduler sessions reaped: " + ", ".join(killed))
240
250
  return 0
241
251
 
242
252
 
@@ -24,6 +24,7 @@ from datetime import datetime, timezone
24
24
  import yaml
25
25
 
26
26
  from ..core import _atomic_write
27
+ from . import zombie
27
28
  from .dispatch import (
28
29
  _WORKFLOW_STATUS_TO_SCHED,
29
30
  _apply_max_runs,
@@ -110,3 +111,6 @@ from .state import (
110
111
  load_board,
111
112
  save_board,
112
113
  )
114
+ from .zombie import reap as reap_zombie_sessions
115
+ from .zombie import scan as scan_zombie_sessions
116
+ from .zombie import tick as zombie_tick
@@ -0,0 +1,160 @@
1
+ """Reap bare-shell scheduler sessions (#739).
2
+
3
+ ``_dispatch_worktree_task`` names every worktree branch
4
+ ``scheduler-<task>-<ts>``. If the session's launch crashes before the agent
5
+ starts (e.g. the worktree directory went missing between ``agentwire new``
6
+ reporting success and the pane's ``cd``), the tmux session drops to a bare
7
+ shell — which the idle-reaper correctly never touches, since it only reaps a
8
+ *running* agent that goes idle. Nothing else would ever clean that up, so it
9
+ lingers indefinitely. This module finds and kills those sessions.
10
+
11
+ Detected by branch naming rather than ``worktree_registry`` — scheduler
12
+ dispatch goes through ``agentwire new``, which (unlike ``agentwire
13
+ worktree``) never registers there.
14
+ """
15
+
16
+ import subprocess
17
+ import time
18
+
19
+ from ..worktree import parse_session_name
20
+
21
+ BRANCH_PREFIX = "scheduler-"
22
+
23
+ # tmux `session_created` is whole seconds. A healthy launch's pre-agent shell
24
+ # moment lasts well under a second (see `_launch_tmux_session`'s 0.1s
25
+ # settle), but this gives a slow `claude` cold start real headroom before a
26
+ # session still mid-launch could be mistaken for a zombie.
27
+ MIN_AGE_SECONDS = 60
28
+
29
+ _SHELL_COMMANDS = frozenset({"zsh", "bash", "sh", "fish", "tcsh", "csh", "dash"})
30
+
31
+
32
+ def _is_bare_shell(command: str) -> bool:
33
+ """True if *command* (a ``pane_current_command`` value) is a login shell."""
34
+ return command.strip().lstrip("-") in _SHELL_COMMANDS
35
+
36
+
37
+ def scan() -> list[dict]:
38
+ """Live scheduler-dispatched worktree sessions stuck at a bare shell.
39
+
40
+ Each entry: ``session``, ``branch``, ``command``, ``age_seconds``.
41
+ """
42
+ result = subprocess.run(
43
+ ["tmux", "list-sessions", "-F", "#{session_name}\t#{session_created}"],
44
+ capture_output=True, text=True,
45
+ )
46
+ if result.returncode != 0:
47
+ return []
48
+
49
+ now = time.time()
50
+ zombies = []
51
+ for line in result.stdout.strip().splitlines():
52
+ if "\t" not in line:
53
+ continue
54
+ session, created = line.split("\t", 1)
55
+ _, branch, machine = parse_session_name(session)
56
+ if machine or not branch or not branch.startswith(BRANCH_PREFIX):
57
+ continue
58
+ try:
59
+ age = now - float(created)
60
+ except ValueError:
61
+ continue
62
+ if age < MIN_AGE_SECONDS:
63
+ continue
64
+
65
+ panes = subprocess.run(
66
+ ["tmux", "list-panes", "-t", f"={session}", "-F", "#{pane_current_command}"],
67
+ capture_output=True, text=True,
68
+ )
69
+ if panes.returncode != 0:
70
+ continue
71
+ commands = [p for p in panes.stdout.strip().splitlines() if p]
72
+ if len(commands) == 1 and _is_bare_shell(commands[0]):
73
+ zombies.append({
74
+ "session": session, "branch": branch,
75
+ "command": commands[0], "age_seconds": int(age),
76
+ })
77
+ return zombies
78
+
79
+
80
+ def _notify(session: str, branch: str, command: str) -> None:
81
+ """Alert on a reaped zombie session (#739 + #743).
82
+
83
+ Always posts a portal toast, so the reap is visible in-band rather than
84
+ only in an email the human has to notice and forward. When the session
85
+ has a recorded parent (``created_by`` in its metadata — set at
86
+ ``agentwire new`` time, see ``_record_session_creator``), the crash is
87
+ ALSO escalated there via the msg inbox (drained by the same watchdog that
88
+ runs this reap) — a worktree worker's crash reaches its orchestrator, not
89
+ just the owner's inbox. Owner email — the reused Resend wiring, mirrors
90
+ ``dispatch._notify_dispatch_timeout`` — is strictly the fallback for a
91
+ session with no recorded parent (the genuine root/scheduler-dispatch
92
+ case #739 originally covered). Each channel is independently
93
+ best-effort; this must never raise into the caller.
94
+ """
95
+ text = (
96
+ f"agentwire: reaped zombie scheduler session `{session}` (branch "
97
+ f"`{branch}`) — launch crashed at a bare shell (`{command}`) before "
98
+ "the agent started."
99
+ )
100
+
101
+ try:
102
+ from ..core import _post_desktop_notification
103
+ _post_desktop_notification(text, session=session, priority="high")
104
+ except Exception:
105
+ pass
106
+
107
+ parent = None
108
+ try:
109
+ from ..core import load_session_metadata
110
+ parent = load_session_metadata(session).get("created_by") or None
111
+ except Exception:
112
+ parent = None
113
+
114
+ if parent:
115
+ try:
116
+ from ..inbox import enqueue
117
+ enqueue(parent, text, kind="escalation", sender="agentwire")
118
+ except Exception:
119
+ pass
120
+ return
121
+
122
+ try:
123
+ import socket
124
+
125
+ from ..channels.email import send_email
126
+ send_email(
127
+ subject=f"[agentwire] reaped zombie scheduler session: {session}",
128
+ body=(
129
+ f"Scheduler dispatch session `{session}` (branch `{branch}`) "
130
+ f"on `{socket.gethostname()}` never reached its agent — the "
131
+ f"pane was stuck at a bare shell (`{command}`), the #739 "
132
+ "failure mode where the worktree launch crashes before "
133
+ "`claude` starts (e.g. a missing worktree directory). The "
134
+ "watchdog killed the session so it can't linger.\n\n"
135
+ "Check the scheduler events log for the originating "
136
+ "dispatch failure."
137
+ ),
138
+ )
139
+ except Exception:
140
+ pass
141
+
142
+
143
+ def reap() -> dict:
144
+ """Kill every detected zombie session, logging + emailing each one."""
145
+ from agentwire import scheduler as _sched
146
+
147
+ killed = []
148
+ for z in scan():
149
+ _sched._kill_session(z["session"])
150
+ _sched._log_event("zombie_session_reaped", session=z["session"],
151
+ branch=z["branch"], command=z["command"],
152
+ age_seconds=z["age_seconds"])
153
+ _notify(z["session"], z["branch"], z["command"])
154
+ killed.append(z["session"])
155
+ return {"killed": killed}
156
+
157
+
158
+ def tick() -> dict:
159
+ """Watchdog stage entry point — same ``{"killed": [...]}`` shape as ``reap()``."""
160
+ return reap()
@@ -402,7 +402,17 @@ def cmd_new(args) -> int:
402
402
  return _output_result(False, json_mode, hint)
403
403
 
404
404
  if not session_path.exists():
405
- if args.force or path:
405
+ if branch:
406
+ # #739: a worktree session's path is only ever meant to come from
407
+ # `_spawn_worktree`/`ensure_worktree` above. Reaching here with it
408
+ # still missing means that creation silently didn't happen (or
409
+ # the dir vanished right after) — mkdir-ing an empty placeholder
410
+ # would launch the agent into a directory with no git checkout at
411
+ # all. Fail loud instead of returning a `path` that doesn't back
412
+ # a real worktree.
413
+ return _output_result(False, json_mode,
414
+ f"Worktree path does not exist after creation: {session_path}")
415
+ elif args.force or path:
406
416
  # Auto-create directory with -f flag or when custom path explicitly provided
407
417
  session_path.mkdir(parents=True, exist_ok=True)
408
418
  else:
@@ -445,14 +455,51 @@ def cmd_new(args) -> int:
445
455
  # Kind default posture (no global default-role lookup).
446
456
  posture, _ = _resolve_posture_from_args(args)
447
457
 
458
+ # Record the creating session as parent for prompt routing. --created-by
459
+ # overrides (including '' to opt out); otherwise default to the caller
460
+ # ONLY when the new session is in the caller's own project — a
461
+ # cross-project spawn gets its own root instead of flattening into the
462
+ # caller's subtree (#715). --caller-session is the candidate caller for
463
+ # that check (MCP forwards it; direct CLI use falls back to the current
464
+ # tmux session). Resolved before building the agent env (#743 needs the
465
+ # real parent, if any, in AGENTWIRE_CREATED_BY BEFORE `tmux new-session
466
+ # -e` fires) and before seeding so a failed seed can name its sender.
467
+ #
468
+ # Joint default with role (#716): an EXPLICITLY requested orchestrator
469
+ # roots by default instead — a durable orchestrator shouldn't answer to
470
+ # whoever happened to spawn it. Gated on the explicit --kind flag (not
471
+ # the resolved `kind`, which is "orchestrator" by default for any
472
+ # branchless name) so the ubiquitous plain `agentwire new` case keeps
473
+ # its existing same-project-inherit behavior untouched. This is the one
474
+ # place this default lives — cmd_worktree's `_launch_session` forwards
475
+ # its own `--kind` straight through as `kind` here, so `agentwire
476
+ # worktree --kind orchestrator` / `agentwire orchestrator` compose with
477
+ # it for free.
478
+ created_by = getattr(args, 'created_by', None)
479
+ caller = None
480
+ if created_by is None and getattr(args, 'kind', None) == 'orchestrator':
481
+ created_by = ''
482
+ elif created_by is None:
483
+ caller = getattr(args, 'caller_session', None) or pane_manager.get_current_session()
484
+ created_by = resolve_default_created_by(caller, session_path)
485
+
448
486
  # Build agent command
449
487
  model_override = getattr(args, 'model', None)
450
488
  agent = build_agent_command(posture, roles if roles else None, model=model_override)
451
489
  agent.env.update(parse_env_args(getattr(args, 'env', None)))
452
- _set_session_name_env(agent, session_name)
490
+ _set_session_name_env(agent, session_name, created_by=created_by)
453
491
 
454
492
  agent_cmd = agent.command
455
493
 
494
+ # #739: re-verify right before launch — closes the window between the
495
+ # earlier worktree-creation check and this point (shared-dir probe,
496
+ # posture/agent-command resolution) during which an external actor could
497
+ # still remove the directory. `agentwire new --json` must never report
498
+ # success with a `path` that doesn't exist on disk.
499
+ if not session_path.exists():
500
+ return _output_result(False, json_mode,
501
+ f"Session path vanished before launch: {session_path}")
502
+
456
503
  # Create new tmux session with env vars injected at creation time, cd
457
504
  # into place, and start the agent (skipped when bare).
458
505
  _launch_tmux_session(session_name, session_path, agent.env, agent_cmd)
@@ -479,33 +526,6 @@ def cmd_new(args) -> int:
479
526
  )
480
527
  save_project_config(project_config, session_path)
481
528
 
482
- # Record the creating session as parent for prompt routing. --created-by
483
- # overrides (including '' to opt out); otherwise default to the caller
484
- # ONLY when the new session is in the caller's own project — a
485
- # cross-project spawn gets its own root instead of flattening into the
486
- # caller's subtree (#715). --caller-session is the candidate caller for
487
- # that check (MCP forwards it; direct CLI use falls back to the current
488
- # tmux session). Resolved before seeding so a failed seed can name its
489
- # sender.
490
- #
491
- # Joint default with role (#716): an EXPLICITLY requested orchestrator
492
- # roots by default instead — a durable orchestrator shouldn't answer to
493
- # whoever happened to spawn it. Gated on the explicit --kind flag (not
494
- # the resolved `kind`, which is "orchestrator" by default for any
495
- # branchless name) so the ubiquitous plain `agentwire new` case keeps
496
- # its existing same-project-inherit behavior untouched. This is the one
497
- # place this default lives — cmd_worktree's `_launch_session` forwards
498
- # its own `--kind` straight through as `kind` here, so `agentwire
499
- # worktree --kind orchestrator` / `agentwire orchestrator` compose with
500
- # it for free.
501
- created_by = getattr(args, 'created_by', None)
502
- caller = None
503
- if created_by is None and getattr(args, 'kind', None) == 'orchestrator':
504
- created_by = ''
505
- elif created_by is None:
506
- caller = getattr(args, 'caller_session', None) or pane_manager.get_current_session()
507
- created_by = resolve_default_created_by(caller, session_path)
508
-
509
529
  # Deliver the first message once the agent is ready (verified paste).
510
530
  # Delivery failure doesn't fail the command — the session exists — but it
511
531
  # must be LOUD (#695): clear the partial paste out of the box and fall
@@ -787,6 +807,24 @@ def cmd_recreate(args) -> int:
787
807
  return 0
788
808
 
789
809
 
810
+ def _resolve_project_arg(project_arg: str, projects_dir: Path) -> Path:
811
+ """Resolve ``--project`` to an absolute repo path, independent of cwd.
812
+
813
+ An explicit path (absolute, or one that actually exists relative to cwd —
814
+ ``.``, ``../sibling``) is honored as given. Otherwise ``project_arg`` is
815
+ treated as a bare project NAME and resolved against the configured
816
+ projects dir, the same way ``cmd_new`` resolves a bare project name from
817
+ ``project/branch`` session syntax — never by blindly joining it onto
818
+ whatever directory the command happens to run from. That naive join is
819
+ what path-doubled ``<cwd>/<project>`` into a nonexistent dir when cwd was
820
+ already the project's own directory (#740).
821
+ """
822
+ expanded = Path(project_arg).expanduser()
823
+ if expanded.is_absolute() or expanded.exists():
824
+ return expanded.resolve()
825
+ return (projects_dir / project_arg).resolve()
826
+
827
+
790
828
  def cmd_worktree(args) -> int:
791
829
  """Create a git worktree + agentwire session in one command.
792
830
 
@@ -816,13 +854,14 @@ def cmd_worktree(args) -> int:
816
854
  ref = getattr(args, 'ref', None)
817
855
 
818
856
  from .config import load_config as load_config_typed
819
- wt_config = load_config_typed().worktree
857
+ full_config = load_config_typed()
858
+ wt_config = full_config.worktree
820
859
 
821
860
  # Resolve the repo: explicit --project → config default → git root of cwd
822
861
  # (so a worktree session can be spawned from any subdir of a monorepo).
823
862
  project_arg = getattr(args, 'project', None)
824
863
  if project_arg:
825
- project_base = Path(project_arg).expanduser().resolve()
864
+ project_base = _resolve_project_arg(project_arg, full_config.projects.dir)
826
865
  elif wt_config.default_project:
827
866
  project_base = Path(wt_config.default_project).expanduser().resolve()
828
867
  else:
@@ -846,7 +885,7 @@ def cmd_worktree(args) -> int:
846
885
  return _worktree_list(args, project_path, json_mode)
847
886
  if getattr(args, 'watch', False):
848
887
  return _worktree_watch(args, project_path, json_mode)
849
- if getattr(args, 'prune', False):
888
+ if getattr(args, 'prune', False) or getattr(args, 'gc_merged', False):
850
889
  return _worktree_prune(args, project_path, worktree_dir, json_mode)
851
890
  if getattr(args, 'dangling', False):
852
891
  return _worktree_dangling(args, project_path, json_mode)
@@ -1233,6 +1272,11 @@ def _worktree_prune(args, project_path: Path, worktree_dir: Path, json_mode: boo
1233
1272
  branch is already merged" sweep from #717. Off by default: this command
1234
1273
  is normally a safe, read-mostly cleanup and shouldn't kill a live,
1235
1274
  in-flight session just because its branch happens to look merged.
1275
+
1276
+ ``--gc-merged`` alone (no ``--prune``) also dispatches here and runs the
1277
+ same sweep — cmd_worktree treats it as implying --prune (#740), so
1278
+ ``--help`` and behavior agree instead of --gc-merged falling through to
1279
+ the usage error.
1236
1280
  """
1237
1281
  removed = []
1238
1282
  gc_merged_out = []
@@ -1443,7 +1487,7 @@ def _teardown_entry(
1443
1487
  project_path: Path, worktree_dir: Path, session_name: str, worktree_path: Path,
1444
1488
  branch: str | None, base: str | None, *, keep_branch: bool = False, force_branch: bool = False,
1445
1489
  ) -> dict:
1446
- """Core atomic teardown: kill session, force-remove the worktree + prune,
1490
+ """Core atomic teardown: force-remove the worktree + prune, kill session,
1447
1491
  unregister, best-effort branch cleanup. Shared by --remove and
1448
1492
  --prune --gc-merged so both paths go through the exact same steps (#717).
1449
1493
 
@@ -1451,12 +1495,13 @@ def _teardown_entry(
1451
1495
  `git worktree remove --force` can't clear it, this fails LOUDLY
1452
1496
  (success: False) and leaves the registry entry in place, instead of
1453
1497
  silently "unregistering" an orphan.
1454
- """
1455
- killed = False
1456
- if tmux_session_exists(session_name):
1457
- subprocess.run(["tmux", "kill-session", "-t", session_name], capture_output=True)
1458
- killed = True
1459
1498
 
1499
+ The worktree removal is attempted BEFORE the session is killed, and the
1500
+ session is only killed once removal is confirmed — never the reverse.
1501
+ Killing first would leave a live session's worktree+branch orphaned on
1502
+ disk with no session left to notice, on any removal failure (bad
1503
+ project_path, a stuck worktree, ...) (#740).
1504
+ """
1460
1505
  # Force-remove the git worktree, then prune admin files either way.
1461
1506
  _, remove_error = remove_worktree(project_path, worktree_path, force=True)
1462
1507
  subprocess.run(["git", "-C", str(project_path), "worktree", "prune"], capture_output=True)
@@ -1464,7 +1509,12 @@ def _teardown_entry(
1464
1509
  if worktree_path.exists():
1465
1510
  reason = remove_error or "worktree directory still present after `git worktree remove --force`"
1466
1511
  return {"success": False, "session": session_name, "path": str(worktree_path),
1467
- "killed": killed, "worktree_removed": False, "error": reason}
1512
+ "killed": False, "worktree_removed": False, "error": reason}
1513
+
1514
+ killed = False
1515
+ if tmux_session_exists(session_name):
1516
+ subprocess.run(["tmux", "kill-session", "-t", session_name], capture_output=True)
1517
+ killed = True
1468
1518
 
1469
1519
  # Removing a project's last worktree also removes the now-empty
1470
1520
  # ~/worktrees/<project>/ dir.
@@ -1490,7 +1540,7 @@ def _teardown_entry(
1490
1540
 
1491
1541
 
1492
1542
  def _worktree_remove(args, project_path: Path, worktree_dir: Path, json_mode: bool) -> int:
1493
- """Teardown: kill the session, force-remove the worktree + prune, unregister,
1543
+ """Teardown: force-remove the worktree + prune, kill the session, unregister,
1494
1544
  and (best-effort) delete the branch — one atomic call (#717)."""
1495
1545
  name = getattr(args, 'name', None)
1496
1546
  if not name:
@@ -1960,11 +2010,11 @@ def register_session_parser(subparsers) -> None:
1960
2010
  "parent — a PR nobody is positioned to review/merge (--all for every "
1961
2011
  "repo). Distinct from --list's 'orphan' state (dead session, disk "
1962
2012
  "remnant) — this flags a LIVE session no one is watching.")
1963
- parser.add_argument("--remove", action="store_true", help="Atomic teardown: kill the session, force-remove the worktree, delete the branch once merged, and unregister (cleanup/recovery)")
2013
+ parser.add_argument("--remove", action="store_true", help="Atomic teardown: force-remove the worktree, kill the session, delete the branch once merged, and unregister (cleanup/recovery)")
1964
2014
  parser.add_argument("--keep-branch", action="store_true", help="With --remove: skip branch cleanup entirely (default: best-effort delete once confirmed merged)")
1965
2015
  parser.add_argument("--force-delete-branch", action="store_true", help="With --remove: delete the branch (local + remote) even if not confirmed merged")
1966
2016
  parser.add_argument("--prune", action="store_true", help="Drop registry entries whose worktree is gone + git worktree prune")
1967
- parser.add_argument("--gc-merged", action="store_true", help="With --prune: also tear down (session/worktree/branch) any registered entry whose branch is confirmed merged")
2017
+ parser.add_argument("--gc-merged", action="store_true", help="Tear down (session/worktree/branch) any registered entry whose branch is confirmed merged; implies --prune (runs standalone too)")
1968
2018
  parser.add_argument("--all", action="store_true", help="With --list/--dangling: include worktree sessions across every repo")
1969
2019
  _add_posture_flag(parser)
1970
2020
  parser.add_argument("--roles", help="Comma-separated roles, STACKED on top of the always-present worker etiquette (kind=orchestrator: REPLACES the default persona instead)")