agentwire-dev 1.2.0__tar.gz → 1.3.1__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 (261) hide show
  1. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/CHANGELOG.md +21 -1
  2. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/PKG-INFO +1 -1
  3. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/__init__.py +1 -1
  4. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/__main__.py +88 -58
  5. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/completion.py +71 -40
  6. agentwire_dev-1.2.0/agentwire/hooks/suppress-bg-notifications.sh → agentwire_dev-1.3.1/agentwire/hooks/idle-handler.sh +14 -8
  7. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/locking.py +9 -0
  8. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/mcp_server.py +20 -1
  9. agentwire_dev-1.3.1/agentwire/onboarding.py +435 -0
  10. agentwire_dev-1.3.1/agentwire/roles/init.md +194 -0
  11. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/server.py +65 -42
  12. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/css/desktop.css +58 -12
  13. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/desktop-manager.js +31 -13
  14. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/desktop.js +103 -18
  15. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/list-window.js +41 -50
  16. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/session-window.js +20 -79
  17. agentwire_dev-1.3.1/agentwire/static/js/tile-manager.js +346 -0
  18. agentwire_dev-1.3.1/agentwire/stt/__init__.py +58 -0
  19. agentwire_dev-1.3.1/agentwire/stt/server_backend.py +88 -0
  20. agentwire_dev-1.3.1/agentwire/utils/chunker.py +27 -0
  21. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/TROUBLESHOOTING.md +1 -1
  22. agentwire_dev-1.3.1/docs/brainstorms/idea-agent-hot-swap.md +376 -0
  23. agentwire_dev-1.3.1/docs/brainstorms/idea-checkpoint-commits.md +345 -0
  24. agentwire_dev-1.3.1/docs/brainstorms/idea-context-window-gauge.md +360 -0
  25. agentwire_dev-1.3.1/docs/brainstorms/idea-cross-session-events.md +244 -0
  26. agentwire_dev-1.3.1/docs/brainstorms/idea-delegation-replay.md +152 -0
  27. agentwire_dev-1.3.1/docs/brainstorms/idea-device-session-tethering.md +88 -0
  28. agentwire_dev-1.3.1/docs/brainstorms/idea-periodic-voice-briefings.md +257 -0
  29. agentwire_dev-1.3.1/docs/brainstorms/idea-session-drift-detection.md +359 -0
  30. agentwire_dev-1.3.1/docs/brainstorms/idea-session-energy-model.md +407 -0
  31. agentwire_dev-1.3.1/docs/brainstorms/idea-session-momentum.md +319 -0
  32. agentwire_dev-1.3.1/docs/brainstorms/idea-session-replay.md +173 -0
  33. agentwire_dev-1.3.1/docs/brainstorms/idea-session-thermal-throttling.md +138 -0
  34. agentwire_dev-1.3.1/docs/brainstorms/idea-spatial-voice-mixing.md +153 -0
  35. agentwire_dev-1.3.1/docs/brainstorms/idea-speculative-execution.md +408 -0
  36. agentwire_dev-1.3.1/docs/brainstorms/idea-task-time-budgets.md +120 -0
  37. agentwire_dev-1.3.1/docs/brainstorms/idea-voice-activity-zones.md +487 -0
  38. agentwire_dev-1.3.1/docs/brainstorms/idea-voice-breakpoints.md +179 -0
  39. agentwire_dev-1.3.1/docs/brainstorms/idea-voice-code-review.md +246 -0
  40. agentwire_dev-1.3.1/docs/brainstorms/idea-voice-command-undo.md +468 -0
  41. agentwire_dev-1.3.1/docs/brainstorms/idea-worker-fencing.md +370 -0
  42. agentwire_dev-1.3.1/docs/brainstorms/idea-worker-proof-of-work.md +296 -0
  43. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/notification-hooks.md +1 -1
  44. agentwire_dev-1.2.0/agentwire/onboarding.py +0 -1580
  45. agentwire_dev-1.2.0/agentwire/stt/__init__.py +0 -41
  46. agentwire_dev-1.2.0/docs/brainstorms/idea-session-replay.md +0 -247
  47. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/.github/FUNDING.yml +0 -0
  48. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  49. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  50. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/.github/ISSUE_TEMPLATE/question.md +0 -0
  51. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  52. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/.github/workflows/ci.yml +0 -0
  53. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/.github/workflows/publish.yml +0 -0
  54. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/.gitignore +0 -0
  55. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/CLA.md +0 -0
  56. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/CODE_OF_CONDUCT.md +0 -0
  57. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/CONTRIBUTING.md +0 -0
  58. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/Dockerfile.local +0 -0
  59. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/Dockerfile.runpod +0 -0
  60. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/LICENSE +0 -0
  61. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/README.md +0 -0
  62. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/RELEASING.md +0 -0
  63. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/SECURITY.md +0 -0
  64. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/SPONSORS.md +0 -0
  65. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/agents/__init__.py +0 -0
  66. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/agents/base.py +0 -0
  67. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/agents/tmux.py +0 -0
  68. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/cached_status.py +0 -0
  69. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/cli_safety.py +0 -0
  70. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/config.py +0 -0
  71. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/errors.py +0 -0
  72. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/history.py +0 -0
  73. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/hooks/__init__.py +0 -0
  74. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/hooks/agentwire-permission.sh +0 -0
  75. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/hooks/damage-control/__init__.py +0 -0
  76. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/hooks/damage-control/audit_logger.py +0 -0
  77. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
  78. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
  79. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/hooks/damage-control/patterns.yaml +0 -0
  80. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
  81. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/init_agentwire.py +0 -0
  82. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/listen.py +0 -0
  83. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/network.py +0 -0
  84. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/notifications.py +0 -0
  85. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/pane_manager.py +0 -0
  86. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/project_config.py +0 -0
  87. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/projects.py +0 -0
  88. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/prompts/__init__.py +0 -0
  89. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/prompts/init.md +0 -0
  90. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/__init__.py +0 -0
  91. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/chatbot.md +0 -0
  92. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/claude-delegation.md +0 -0
  93. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/claude-worker-haiku.md +0 -0
  94. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/claude-worker-sonnet.md +0 -0
  95. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/claude-worker.md +0 -0
  96. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/glm-delegation.md +0 -0
  97. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/glm-worker-flash.md +0 -0
  98. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/glm-worker.md +0 -0
  99. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/leader-claude.md +0 -0
  100. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/leader-glm.md +0 -0
  101. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/leader-openai.md +0 -0
  102. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/leader.md +0 -0
  103. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/openai-delegation.md +0 -0
  104. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/openai-worker-mini.md +0 -0
  105. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/openai-worker.md +0 -0
  106. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/task-runner.md +0 -0
  107. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/voice.md +0 -0
  108. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/roles/worker.md +0 -0
  109. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-Echo--black.png +0 -0
  110. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-Echo--transparent.png +0 -0
  111. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-Echo.png +0 -0
  112. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-email-banner.png +0 -0
  113. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
  114. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
  115. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
  116. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
  117. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
  118. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
  119. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
  120. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
  121. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
  122. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
  123. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/favicon.png +0 -0
  124. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/android.jpeg +0 -0
  125. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/automaton.jpeg +0 -0
  126. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/bot.jpeg +0 -0
  127. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
  128. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/droid.jpeg +0 -0
  129. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/drone.jpeg +0 -0
  130. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/guardian.jpeg +0 -0
  131. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/mech.jpeg +0 -0
  132. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/probe.jpeg +0 -0
  133. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/robot.jpeg +0 -0
  134. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
  135. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/machines/unit.jpeg +0 -0
  136. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/blob.jpeg +0 -0
  137. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/cloud.jpeg +0 -0
  138. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/crystal.jpeg +0 -0
  139. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
  140. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/flame.jpeg +0 -0
  141. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
  142. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/horned.jpeg +0 -0
  143. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/moon.jpeg +0 -0
  144. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/slime.jpeg +0 -0
  145. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/star.jpeg +0 -0
  146. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
  147. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/projects/winged.jpeg +0 -0
  148. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/bear.jpeg +0 -0
  149. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/cat.jpeg +0 -0
  150. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/crown.jpeg +0 -0
  151. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
  152. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
  153. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
  154. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/deer.jpeg +0 -0
  155. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/drone.jpeg +0 -0
  156. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
  157. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/fox.jpeg +0 -0
  158. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
  159. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/horse.jpeg +0 -0
  160. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/lion.jpeg +0 -0
  161. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
  162. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/robot.jpeg +0 -0
  163. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
  164. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
  165. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/.gitkeep +0 -0
  166. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/components/icon-picker.js +0 -0
  167. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/components/list-card.js +0 -0
  168. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/components/type-tag.js +0 -0
  169. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/icon-manager.js +0 -0
  170. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/utils/auto-refresh.js +0 -0
  171. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/winbox.bundle.min.js +0 -0
  172. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/windows/chat-window.js +0 -0
  173. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/windows/config-window.js +0 -0
  174. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/windows/machines-window.js +0 -0
  175. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/windows/projects-window.js +0 -0
  176. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/static/js/windows/sessions-window.js +0 -0
  177. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/stt/base.py +0 -0
  178. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/stt/stt_server.py +0 -0
  179. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/stt/whisperkit.py +0 -0
  180. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tasks.py +0 -0
  181. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/templates/__init__.py +0 -0
  182. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/templates/base.html +0 -0
  183. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/templates/desktop.html +0 -0
  184. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/templates/email_notification.html +0 -0
  185. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/templating.py +0 -0
  186. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/__init__.py +0 -0
  187. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/base.py +0 -0
  188. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/engines/__init__.py +0 -0
  189. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/engines/chatterbox.py +0 -0
  190. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/engines/qwen_base.py +0 -0
  191. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/engines/qwen_custom.py +0 -0
  192. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/engines/qwen_design.py +0 -0
  193. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/registry.py +0 -0
  194. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts/runpod_handler.py +0 -0
  195. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tts_server.py +0 -0
  196. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/tunnels.py +0 -0
  197. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/utils/__init__.py +0 -0
  198. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/utils/file_io.py +0 -0
  199. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/utils/paths.py +0 -0
  200. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/utils/subprocess.py +0 -0
  201. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/validation.py +0 -0
  202. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/voiceclone.py +0 -0
  203. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/voices/darren.wav +0 -0
  204. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/voices/default.wav +0 -0
  205. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/voices/jessica.wav +0 -0
  206. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/voices/lisa.wav +0 -0
  207. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/voices/may.wav +0 -0
  208. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/agentwire/worktree.py +0 -0
  209. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/PORTAL.md +0 -0
  210. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/SHELL_ESCAPING.md +0 -0
  211. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/SPONSORS.md +0 -0
  212. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/README.md +0 -0
  213. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-ambient-context-stream.md +0 -0
  214. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-ambient-listening-mode.md +0 -0
  215. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-audio-cues.md +0 -0
  216. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-context-compression-protocol.md +0 -0
  217. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-contextual-bookmarks.md +0 -0
  218. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-conversation-archaeology.md +0 -0
  219. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-cost-tracking-dashboard.md +0 -0
  220. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-failure-memory.md +0 -0
  221. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-notification-escalation.md +0 -0
  222. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-presence-aware-sessions.md +0 -0
  223. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-session-handshake.md +0 -0
  224. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-session-snapshots.md +0 -0
  225. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-session-templates.md +0 -0
  226. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-smart-session-routing.md +0 -0
  227. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-task-pipeline-chaining.md +0 -0
  228. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-task-pivot-protocol.md +0 -0
  229. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-voice-handoff.md +0 -0
  230. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-voice-identity.md +0 -0
  231. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-voice-interrupts-v2.md +0 -0
  232. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-voice-interrupts.md +0 -0
  233. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-voice-macros.md +0 -0
  234. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-voice-transcript-logs.md +0 -0
  235. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-watchdog-mode.md +0 -0
  236. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-worker-file-coordination.md +0 -0
  237. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-worker-health-dashboard.md +0 -0
  238. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-worker-heartbeat-watchdog.md +0 -0
  239. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-worker-progress-streaming.md +0 -0
  240. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-worker-warmup.md +0 -0
  241. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/brainstorms/idea-x-api-integration.md +0 -0
  242. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/critical-analysis.md +0 -0
  243. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/demo-script.md +0 -0
  244. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/issues/pending-code-changes.md +0 -0
  245. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/issues/remote-tts-session-detection.md +0 -0
  246. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/logo.png +0 -0
  247. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/progressive-loading-pattern.md +0 -0
  248. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/prompts/agentwire-website.md +0 -0
  249. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/releasing.md +0 -0
  250. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/remote-access.md +0 -0
  251. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/remote-machines.md +0 -0
  252. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/runpod-tts.md +0 -0
  253. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/scheduled-workloads.md +0 -0
  254. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/security/damage-control-migration.md +0 -0
  255. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/security/damage-control.md +0 -0
  256. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/tmux-hooks.md +0 -0
  257. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/tts-self-hosted.md +0 -0
  258. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/docs/youtube-channel.md +0 -0
  259. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/opencode-plugin/agentwire-notify.ts +0 -0
  260. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/pyproject.toml +0 -0
  261. {agentwire_dev-1.2.0 → agentwire_dev-1.3.1}/requirements-tts.txt +0 -0
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.0] - 2026-02-10
11
+
12
+ ### Added
13
+
14
+ - Drag-to-tile window management for side-by-side session workflows
15
+ - Auto-chunk long TTS messages into separate audio segments for sequential playback
16
+ - Redesigned onboarding flow that asks 3 questions then spawns Claude for setup
17
+
18
+ ### Fixed
19
+
20
+ - Chunk pasted terminal input to prevent PTY buffer flooding and session freezes
21
+ - Poll summary file directly instead of relying on two-idle completion signal
22
+ - Move TTS chunker to utils to avoid torch import in MCP server
23
+ - Namespace task summary files by session to prevent cross-session collisions
24
+ - Don't clear task context on ensure timeout (race condition)
25
+ - Stale lock detection in `--wait-lock` + add `--skip-if-locked`
26
+ - Use STT server when configured instead of always falling back to WhisperKit
27
+
10
28
  ## [1.2.0] - 2026-02-03
11
29
 
12
30
  ### Added
@@ -112,4 +130,6 @@ Initial public release of AgentWire.
112
130
  [1.0.0]: https://github.com/dotdevdotdev/agentwire-dev/releases/tag/v1.0.0
113
131
 
114
132
  [1.1.0]: https://github.com/dotdevdotdev/agentwire-dev/compare/v1.0.0...v1.1.0
115
- [Unreleased]: https://github.com/dotdevdotdev/agentwire-dev/compare/v1.1.0...HEAD
133
+ [1.2.0]: https://github.com/dotdevdotdev/agentwire-dev/compare/v1.1.0...v1.2.0
134
+ [1.3.0]: https://github.com/dotdevdotdev/agentwire-dev/compare/v1.2.0...v1.3.0
135
+ [Unreleased]: https://github.com/dotdevdotdev/agentwire-dev/compare/v1.3.0...HEAD
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentwire-dev
3
- Version: 1.2.0
3
+ Version: 1.3.1
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.2.0"
3
+ __version__ = "1.3.1"
@@ -331,6 +331,32 @@ def tmux_session_exists(name: str) -> bool:
331
331
  return result.returncode == 0
332
332
 
333
333
 
334
+ def _get_session_project_path(session: str) -> Path | None:
335
+ """Get a session's project path from its tmux working directory.
336
+
337
+ Queries tmux for the session's actual working directory. Falls back to
338
+ deriving it from the session name if the session isn't running.
339
+
340
+ Returns:
341
+ Path to the project directory, or None if not determinable.
342
+ """
343
+ # Try to get the actual working directory from tmux
344
+ if tmux_session_exists(session):
345
+ result = subprocess.run(
346
+ ["tmux", "display-message", "-t", session, "-p", "#{pane_current_path}"],
347
+ capture_output=True,
348
+ text=True,
349
+ )
350
+ if result.returncode == 0 and result.stdout.strip():
351
+ return Path(result.stdout.strip())
352
+
353
+ # Fallback: derive from session name
354
+ config = load_config()
355
+ projects_dir = Path(config.get("projects", {}).get("dir", "~/projects")).expanduser()
356
+ project, _, _ = parse_session_name(session)
357
+ return projects_dir / project
358
+
359
+
334
360
  def tmux_session_has_agent(name: str) -> bool:
335
361
  """Check if a tmux session has an agent running (not just a bare shell).
336
362
 
@@ -991,11 +1017,11 @@ def _start_tts_local(args, venv_override: str | None = None) -> int:
991
1017
  print(f"Create it with: cd {source_dir} && uv venv {venv_name}", file=sys.stderr)
992
1018
  return 1
993
1019
 
994
- # Build command with venv
1020
+ # Build command using venv python directly (avoids broken activate scripts and conda interference)
1021
+ venv_python = source_dir / venv_name / "bin" / "python"
995
1022
  tts_cmd = (
996
1023
  f"cd {source_dir} && "
997
- f"source {venv_name}/bin/activate && "
998
- f"python -m agentwire tts serve --host {host} --port {port} --backend {backend} --venv {venv}"
1024
+ f"{venv_python} -m agentwire tts serve --host {host} --port {port} --backend {backend} --venv {venv}"
999
1025
  )
1000
1026
 
1001
1027
  print(f"Starting TTS server on {host}:{port} (backend: {backend}, venv: {venv})...")
@@ -1991,19 +2017,27 @@ def cmd_say(args) -> int:
1991
2017
  _handle_voice_notifications(text, voice, args, session)
1992
2018
 
1993
2019
  # Try portal first if we have a session
2020
+ # Portal handles chunking internally (sequential generation + broadcast)
1994
2021
  if session:
1995
2022
  portal_url = _get_portal_url()
1996
2023
  has_connections, actual_session = _check_portal_connections(session, portal_url)
1997
2024
 
1998
2025
  if has_connections:
1999
- # Send to portal - browser will play the audio
2000
2026
  return _remote_say(text, actual_session, portal_url)
2001
2027
 
2002
- # No portal connections (or no session) - generate locally
2003
- return _local_say_runpod(
2004
- text, voice, exaggeration, cfg_weight, tts_config,
2005
- backend=backend, instruct=instruct, language=language, stream=stream
2006
- )
2028
+ # No portal connections chunk locally for better TTS quality
2029
+ from .utils.chunker import chunk_text
2030
+ chunks = chunk_text(text)
2031
+
2032
+ for chunk in chunks:
2033
+ result = _local_say_runpod(
2034
+ chunk, voice, exaggeration, cfg_weight, tts_config,
2035
+ backend=backend, instruct=instruct, language=language, stream=stream
2036
+ )
2037
+ if result != 0:
2038
+ return result
2039
+
2040
+ return 0
2007
2041
 
2008
2042
 
2009
2043
  def cmd_alert(args) -> int:
@@ -5074,7 +5108,7 @@ def cmd_init(args) -> int:
5074
5108
  # Quick mode: run wizard but skip agentwire step
5075
5109
  # We do this by running onboarding and returning before agentwire prompt
5076
5110
  # The onboarding module handles this internally
5077
- return run_onboarding(skip_agentwire=True)
5111
+ return run_onboarding(skip_session=True)
5078
5112
 
5079
5113
  # Default: run full wizard (ends with optional agentwire setup)
5080
5114
  return run_onboarding()
@@ -5408,7 +5442,7 @@ def cmd_doctor(args) -> int:
5408
5442
  print(" Run: agentwire hooks install")
5409
5443
 
5410
5444
  # Check Claude Code idle notification hook
5411
- idle_hook = CLAUDE_HOOKS_DIR / "suppress-bg-notifications.sh"
5445
+ idle_hook = CLAUDE_HOOKS_DIR / "idle-handler.sh"
5412
5446
  if idle_hook.exists():
5413
5447
  print(f" [ok] Idle notification hook: {idle_hook}")
5414
5448
  else:
@@ -6659,7 +6693,6 @@ def cmd_ensure(args) -> int:
6659
6693
  CompletionTimeout,
6660
6694
  generate_summary_filename,
6661
6695
  get_summary_prompt,
6662
- parse_summary_file,
6663
6696
  status_to_exit_code,
6664
6697
  wait_for_file,
6665
6698
  wait_for_idle,
@@ -6682,6 +6715,7 @@ def cmd_ensure(args) -> int:
6682
6715
  dry_run = getattr(args, 'dry_run', False)
6683
6716
  wait_lock = getattr(args, 'wait_lock', False)
6684
6717
  lock_timeout = getattr(args, 'lock_timeout', 60)
6718
+ skip_if_locked = getattr(args, 'skip_if_locked', False)
6685
6719
  json_mode = getattr(args, 'json', False)
6686
6720
 
6687
6721
  # Parse session target
@@ -6690,14 +6724,11 @@ def cmd_ensure(args) -> int:
6690
6724
  if machine_id:
6691
6725
  return _output_result(False, json_mode, "Remote sessions not yet supported for ensure", exit_code=ENSURE_EXIT_SESSION_ERROR)
6692
6726
 
6693
- # Find project path from --project flag, or derive from session name
6727
+ # Find project path from --project flag, or session's working directory
6694
6728
  if hasattr(args, 'project') and args.project:
6695
6729
  project_path = Path(args.project).expanduser().resolve()
6696
6730
  else:
6697
- config = load_config()
6698
- projects_dir = Path(config.get("projects", {}).get("dir", "~/projects")).expanduser()
6699
- project, branch, _ = parse_session_name(session_name)
6700
- project_path = projects_dir / project
6731
+ project_path = _get_session_project_path(session)
6701
6732
 
6702
6733
  if not project_path.exists():
6703
6734
  return _output_result(False, json_mode, f"Project path not found: {project_path}", exit_code=ENSURE_EXIT_SESSION_ERROR)
@@ -6776,8 +6807,12 @@ def cmd_ensure(args) -> int:
6776
6807
  args, session, task, ctx, shell, project_path, timeout, json_mode
6777
6808
  )
6778
6809
  except LockConflict as e:
6810
+ if skip_if_locked:
6811
+ return 0
6779
6812
  return _output_result(False, json_mode, str(e), exit_code=ENSURE_EXIT_LOCK_CONFLICT)
6780
6813
  except LockTimeout as e:
6814
+ if skip_if_locked:
6815
+ return 0
6781
6816
  return _output_result(False, json_mode, str(e), exit_code=ENSURE_EXIT_LOCK_CONFLICT)
6782
6817
 
6783
6818
 
@@ -6787,15 +6822,14 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, timeout, jso
6787
6822
  Uses hook-based completion detection:
6788
6823
  1. Write task context file (tells hook a scheduled task is running)
6789
6824
  2. Send task prompt
6790
- 3. Hook handles: first idle → send summary prompt, second idle → write completion signal
6791
- 4. Wait for completion signal file
6792
- 5. Read and parse summary
6825
+ 3. Hook handles: first idle → send summary prompt
6826
+ 4. Poll for summary file (agent writes it after receiving summary prompt)
6827
+ 5. Parse summary and return result
6793
6828
  """
6794
6829
  from .completion import (
6795
6830
  CompletionTimeout,
6796
6831
  clear_task_context,
6797
6832
  generate_summary_filename,
6798
- parse_summary_file,
6799
6833
  status_to_exit_code,
6800
6834
  wait_for_completion_signal,
6801
6835
  write_task_context,
@@ -6867,8 +6901,8 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, timeout, jso
6867
6901
  except TemplateError as e:
6868
6902
  return _output_result(False, json_mode, str(e), exit_code=ENSURE_EXIT_PRE_FAILURE)
6869
6903
 
6870
- # Generate summary filename
6871
- summary_filename = generate_summary_filename(task.name)
6904
+ # Generate summary filename (scoped to session to avoid collisions)
6905
+ summary_filename = generate_summary_filename(session, task.name)
6872
6906
  summary_path = project_path / summary_filename
6873
6907
  ctx.summary_file = summary_filename
6874
6908
 
@@ -6880,7 +6914,7 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, timeout, jso
6880
6914
  clear_task_context(session)
6881
6915
 
6882
6916
  # Write task context for hook coordination
6883
- # Hook will: first idle → send summary prompt, second idle write completion signal
6917
+ # Hook will: first idle → send summary prompt (ensure polls for summary file directly)
6884
6918
  write_task_context(
6885
6919
  session=session,
6886
6920
  task_name=task.name,
@@ -6889,6 +6923,18 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, timeout, jso
6889
6923
  exit_on_complete=task.exit_on_complete,
6890
6924
  )
6891
6925
 
6926
+ # Find previous summaries for this task to give the agent context
6927
+ summary_glob = f".agentwire/task-summary-{session}-{task.name}-*.md"
6928
+ prev_summaries = sorted(
6929
+ project_path.glob(summary_glob),
6930
+ key=lambda p: p.stat().st_mtime,
6931
+ reverse=True,
6932
+ )[:5]
6933
+ if prev_summaries:
6934
+ prompt += "\n\nPrevious task summaries (consider them when generating your output):"
6935
+ for p in prev_summaries:
6936
+ prompt += f"\n- {p}"
6937
+
6892
6938
  if not json_mode:
6893
6939
  print("Sending task prompt...")
6894
6940
 
@@ -6897,13 +6943,20 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, timeout, jso
6897
6943
 
6898
6944
  # Wait for completion signal from hook
6899
6945
  if not json_mode:
6900
- print("Waiting for task completion (hook-based)...")
6946
+ print("Waiting for task completion...")
6901
6947
 
6902
6948
  try:
6903
- signal = wait_for_completion_signal(session, timeout=timeout)
6949
+ signal = wait_for_completion_signal(
6950
+ session, timeout=timeout, summary_path=summary_path
6951
+ )
6904
6952
  last_status = signal.get("status", "incomplete")
6953
+ last_summary = signal.get("summary", "")
6954
+ ctx.status = last_status
6955
+ ctx.summary = last_summary
6905
6956
  except CompletionTimeout:
6906
- clear_task_context(session)
6957
+ # Don't clear task context here — the hook may still need it.
6958
+ # Hook cleans up after itself (exit_on_complete kills session).
6959
+ # Task context files are cleared at the START of next run.
6907
6960
  last_status = "incomplete"
6908
6961
  last_summary = "Timeout waiting for task completion"
6909
6962
  if attempt < max_attempts:
@@ -6916,17 +6969,6 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, timeout, jso
6916
6969
  # Clean up task context
6917
6970
  clear_task_context(session)
6918
6971
 
6919
- # Parse summary file
6920
- try:
6921
- result = parse_summary_file(summary_path)
6922
- last_status = result.status
6923
- last_summary = result.summary
6924
- ctx.status = result.status
6925
- ctx.summary = result.summary
6926
- except Exception as e:
6927
- last_status = "incomplete"
6928
- last_summary = f"Failed to parse summary: {e}"
6929
-
6930
6972
  if not json_mode:
6931
6973
  print(f"Task status: {last_status}")
6932
6974
  if last_summary:
@@ -7070,18 +7112,13 @@ def cmd_task_list(args) -> int:
7070
7112
  session = getattr(args, 'session', None)
7071
7113
  json_mode = getattr(args, 'json', False)
7072
7114
 
7073
- # Find project path
7074
- config = load_config()
7075
- projects_dir = Path(config.get("projects", {}).get("dir", "~/projects")).expanduser()
7076
-
7115
+ # Find project path from session's working directory or cwd
7077
7116
  if session:
7078
- project, _, _ = parse_session_name(session)
7079
- project_path = projects_dir / project
7117
+ project_path = _get_session_project_path(session)
7080
7118
  else:
7081
- # Use current directory
7082
7119
  project_path = Path.cwd()
7083
7120
 
7084
- if not project_path.exists():
7121
+ if not project_path or not project_path.exists():
7085
7122
  return _output_result(False, json_mode, f"Project path not found: {project_path}")
7086
7123
 
7087
7124
  tasks = list_tasks(project_path)
@@ -7119,13 +7156,9 @@ def cmd_task_show(args) -> int:
7119
7156
  session = None
7120
7157
  task_name = task_arg
7121
7158
 
7122
- # Find project path
7123
- config = load_config()
7124
- projects_dir = Path(config.get("projects", {}).get("dir", "~/projects")).expanduser()
7125
-
7159
+ # Find project path from session's working directory or cwd
7126
7160
  if session:
7127
- project, _, _ = parse_session_name(session)
7128
- project_path = projects_dir / project
7161
+ project_path = _get_session_project_path(session)
7129
7162
  else:
7130
7163
  project_path = Path.cwd()
7131
7164
 
@@ -7207,13 +7240,9 @@ def cmd_task_validate(args) -> int:
7207
7240
  session = None
7208
7241
  task_name = task_arg
7209
7242
 
7210
- # Find project path
7211
- config = load_config()
7212
- projects_dir = Path(config.get("projects", {}).get("dir", "~/projects")).expanduser()
7213
-
7243
+ # Find project path from session's working directory or cwd
7214
7244
  if session:
7215
- project, _, _ = parse_session_name(session)
7216
- project_path = projects_dir / project
7245
+ project_path = _get_session_project_path(session)
7217
7246
  else:
7218
7247
  project_path = Path.cwd()
7219
7248
 
@@ -8003,6 +8032,7 @@ def main() -> int:
8003
8032
  ensure_parser.add_argument("--dry-run", action="store_true", help="Show what would execute without running")
8004
8033
  ensure_parser.add_argument("--wait-lock", action="store_true", help="Wait for lock instead of failing if locked")
8005
8034
  ensure_parser.add_argument("--lock-timeout", type=int, default=60, help="Max time to wait for lock (default: 60s)")
8035
+ ensure_parser.add_argument("--skip-if-locked", action="store_true", help="Exit 0 silently if session is locked (for cron use cases)")
8006
8036
  ensure_parser.add_argument("--json", action="store_true", help="Output JSON")
8007
8037
  ensure_parser.set_defaults(func=cmd_ensure)
8008
8038
 
@@ -66,17 +66,21 @@ Status meanings:
66
66
  Write the file now."""
67
67
 
68
68
 
69
- def generate_summary_filename(task_name: str) -> str:
70
- """Generate a timestamped summary filename.
69
+ def generate_summary_filename(session: str, task_name: str) -> str:
70
+ """Generate a session-scoped timestamped summary filename.
71
+
72
+ Includes session name so multiple sessions sharing a project directory
73
+ don't collide on summary files or trigger false TASK-ORPHAN detection.
71
74
 
72
75
  Args:
73
- task_name: Task name (for context, not used in filename currently)
76
+ session: tmux session name
77
+ task_name: Task name (for context)
74
78
 
75
79
  Returns:
76
- Relative path like .agentwire/task-summary-2024-01-15T07-00-00.md
80
+ Relative path like .agentwire/task-summary-mysession-2024-01-15T07-00-00.md
77
81
  """
78
82
  timestamp = datetime.now().strftime("%Y-%m-%dT%H-%M-%S")
79
- return f".agentwire/task-summary-{timestamp}.md"
83
+ return f".agentwire/task-summary-{session}-{task_name}-{timestamp}.md"
80
84
 
81
85
 
82
86
  # =============================================================================
@@ -183,44 +187,28 @@ def clear_task_context(session: str) -> None:
183
187
  pass
184
188
 
185
189
 
186
- def write_completion_signal(session: str, status: str, summary_file: str) -> Path:
187
- """Write completion signal file (called by hook).
188
-
189
- Args:
190
- session: tmux session name
191
- status: Task status from summary
192
- summary_file: Path to summary file
193
-
194
- Returns:
195
- Path to the completion signal file
196
- """
197
- TASKS_DIR.mkdir(parents=True, exist_ok=True)
198
-
199
- signal = {
200
- "completed_at": datetime.now().isoformat(),
201
- "status": status,
202
- "summary_file": summary_file,
203
- }
204
-
205
- complete_file = TASKS_DIR / f"{session}.complete"
206
- complete_file.write_text(json.dumps(signal, indent=2))
207
- return complete_file
208
-
209
-
210
190
  def wait_for_completion_signal(
211
191
  session: str,
212
192
  timeout: float = 300.0,
213
193
  poll_interval: float = 2.0,
194
+ summary_path: Path | None = None,
214
195
  ) -> dict:
215
- """Wait for completion signal from hook.
196
+ """Wait for task completion by polling the summary file directly.
197
+
198
+ Primary detection: polls for the summary file the agent writes after
199
+ receiving the summary prompt. When found, parses it and returns the result.
200
+
201
+ Fallback: also checks for the legacy .complete signal file in case the
202
+ hook writes one (e.g. manual trigger).
216
203
 
217
204
  Args:
218
205
  session: tmux session name
219
206
  timeout: Maximum seconds to wait
220
207
  poll_interval: Seconds between checks
208
+ summary_path: Path to the summary .md file the agent will write
221
209
 
222
210
  Returns:
223
- Completion signal dict with status and summary_file
211
+ Dict with 'status', 'summary', 'summary_file' keys
224
212
 
225
213
  Raises:
226
214
  CompletionTimeout: If timeout exceeded
@@ -229,6 +217,21 @@ def wait_for_completion_signal(
229
217
  start_time = time.time()
230
218
 
231
219
  while True:
220
+ # Primary: check if the agent has written the summary file
221
+ if summary_path and summary_path.exists() and summary_path.stat().st_size > 0:
222
+ # Give a moment for the file to be fully written
223
+ time.sleep(0.5)
224
+ try:
225
+ result = parse_summary_file(summary_path)
226
+ return {
227
+ "status": result.status,
228
+ "summary": result.summary,
229
+ "summary_file": str(summary_path),
230
+ }
231
+ except CompletionError:
232
+ pass # File may be partially written, retry
233
+
234
+ # Fallback: check for legacy .complete signal file
232
235
  if complete_file.exists():
233
236
  try:
234
237
  signal = json.loads(complete_file.read_text())
@@ -397,18 +400,26 @@ def wait_for_file(
397
400
 
398
401
 
399
402
  def parse_summary_file(path: Path) -> SummaryResult:
400
- """Parse a task summary file with YAML front matter.
403
+ """Parse a task summary file.
401
404
 
402
- Expected format:
405
+ Supports two formats:
406
+
407
+ 1. YAML front matter (from Python SYSTEM_SUMMARY_PROMPT):
403
408
  ---
404
409
  status: complete
405
410
  summary: Did the thing
406
411
  files_modified:
407
412
  - path/to/file
408
- blockers: []
409
413
  ---
410
414
 
411
- Additional notes here...
415
+ 2. Markdown headings (from hook summary prompt):
416
+ # Task Summary
417
+ ## Status
418
+ complete
419
+ ## What Was Done
420
+ Description here
421
+ ## Notes
422
+ Extra context
412
423
 
413
424
  Args:
414
425
  path: Path to the summary file
@@ -430,9 +441,8 @@ def parse_summary_file(path: Path) -> SummaryResult:
430
441
  files_modified: list[str] = []
431
442
  blockers: list[str] = []
432
443
 
433
- # Parse YAML front matter
434
444
  if content.startswith("---"):
435
- # Find closing ---
445
+ # Parse YAML front matter format
436
446
  end_match = re.search(r"\n---\s*\n", content[3:])
437
447
  if end_match:
438
448
  yaml_content = content[3:3 + end_match.start()]
@@ -461,10 +471,31 @@ def parse_summary_file(path: Path) -> SummaryResult:
461
471
  files_modified.append(item)
462
472
  elif current_list == "blockers":
463
473
  blockers.append(item)
464
-
465
- # Validate status
474
+ else:
475
+ # Parse markdown heading format (## Status, ## What Was Done, etc.)
476
+ sections: dict[str, list[str]] = {}
477
+ current_section: str | None = None
478
+
479
+ for line in content.split("\n"):
480
+ stripped = line.strip()
481
+ heading = re.match(r"^#{1,3}\s+(.+)", stripped)
482
+ if heading:
483
+ current_section = heading.group(1).lower()
484
+ continue
485
+ if current_section and stripped:
486
+ sections.setdefault(current_section, []).append(stripped)
487
+
488
+ if "status" in sections:
489
+ status = sections["status"][0].strip().lower()
490
+ if "what was done" in sections:
491
+ summary = " ".join(sections["what was done"])
492
+ elif "summary" in sections:
493
+ summary = " ".join(sections["summary"])
494
+
495
+ # Validate status — also accept "error" as "failed"
496
+ if status == "error":
497
+ status = "failed"
466
498
  if status not in ("complete", "incomplete", "failed"):
467
- # Default to incomplete if status is unrecognized
468
499
  status = "incomplete"
469
500
 
470
501
  return SummaryResult(
@@ -190,18 +190,18 @@ complete | incomplete | error
190
190
  $AGENTWIRE send -s "$tmux_session" "$instruction" >/dev/null 2>&1 &
191
191
  echo "[$(date -Iseconds)] TASK: summary prompt sent" >> "$dlog"
192
192
  else
193
- # Second+ idle: task complete, write completion signal and optionally exit
194
- echo "[$(date -Iseconds)] TASK: second idle, writing completion signal" >> "$dlog"
195
-
196
- # Write completion signal file
197
- complete_file="$HOME/.agentwire/tasks/${tmux_session}.complete"
198
- echo "{\"completed_at\":\"$(date -Iseconds)\",\"status\":\"complete\",\"summary_file\":\"${summary_file}\"}" > "$complete_file"
193
+ # Second+ idle: optionally exit session (ensure polls summary file directly)
194
+ echo "[$(date -Iseconds)] TASK: second idle" >> "$dlog"
199
195
 
200
196
  if [[ "$exit_on_complete" == "true" ]]; then
201
197
  echo "[$(date -Iseconds)] TASK: exit_on_complete=true, sending /exit" >> "$dlog"
202
198
  sleep 1
203
199
  $AGENTWIRE send -s "$tmux_session" "/exit" >/dev/null 2>&1
204
200
 
201
+ # Clean up task context file so it doesn't haunt future sessions
202
+ rm "$task_context_file" 2>/dev/null
203
+ echo "[$(date -Iseconds)] TASK: cleaned up task context" >> "$dlog"
204
+
205
205
  # Wait for Claude to exit, then kill the tmux session
206
206
  sleep 3
207
207
  echo "[$(date -Iseconds)] TASK: killing tmux session" >> "$dlog"
@@ -211,8 +211,9 @@ complete | incomplete | error
211
211
  ) &
212
212
  else
213
213
  # No task context file - check if this might be a scheduled task that lost its context
214
- # Look for recent task summary files in the project directory
215
- recent_summary=$(find "${cwd}/.agentwire" -name "task-summary-*.md" -mmin -5 2>/dev/null | head -1)
214
+ # Look for recent task summary files scoped to THIS session (avoids false matches
215
+ # when multiple sessions share the same project directory)
216
+ recent_summary=$(find "${cwd}/.agentwire" -name "task-summary-${tmux_session}-*.md" -mmin -5 2>/dev/null | head -1)
216
217
 
217
218
  if [[ -n "$recent_summary" ]]; then
218
219
  log "No task context but found recent summary file, cleaning up session"
@@ -222,6 +223,11 @@ complete | incomplete | error
222
223
  echo "[$(date -Iseconds)] TASK-ORPHAN: found summary at $recent_summary, exiting session" >> "$dlog"
223
224
  sleep 1
224
225
  $AGENTWIRE send -s "$tmux_session" "/exit" >/dev/null 2>&1
226
+
227
+ # Clean up orphan summary so it doesn't trigger again
228
+ rm "$recent_summary" 2>/dev/null
229
+ echo "[$(date -Iseconds)] TASK-ORPHAN: cleaned up orphan summary" >> "$dlog"
230
+
225
231
  sleep 3
226
232
  echo "[$(date -Iseconds)] TASK-ORPHAN: killing tmux session" >> "$dlog"
227
233
  tmux kill-session -t "$tmux_session" 2>/dev/null &
@@ -100,6 +100,15 @@ def session_lock(
100
100
  f"Timeout waiting for lock on session '{session}' "
101
101
  f"after {timeout:.1f}s"
102
102
  )
103
+ # Check if the lock holder is still alive
104
+ holder_pid = get_lock_holder(session)
105
+ if holder_pid is not None and not _is_process_running(holder_pid):
106
+ # Stale lock from a dead process — clean it up
107
+ remove_lock(session)
108
+ # Close our current file handle (the old lock file is gone)
109
+ lock_file.close()
110
+ lock_file = open(lock_path, "w")
111
+ continue # Retry immediately
103
112
  time.sleep(poll_interval)
104
113
  else:
105
114
  # Non-blocking - fail immediately if locked
@@ -588,6 +588,21 @@ def say(text: str, session: str | None = None, voice: str | None = None) -> str:
588
588
  Returns:
589
589
  Success message or error description.
590
590
  """
591
+ # Quick TTS health check — fail fast if server is unreachable
592
+ try:
593
+ from .config import load_config as load_typed_config
594
+ from .network import NetworkContext
595
+ import urllib.request
596
+
597
+ cfg = load_typed_config()
598
+ if cfg.tts.backend not in ("runpod", "none"):
599
+ ctx = NetworkContext.from_config()
600
+ tts_url = ctx.get_service_url("tts", use_tunnel=True)
601
+ urllib.request.urlopen(f"{tts_url}/health", timeout=3)
602
+ except Exception as e:
603
+ url = locals().get("tts_url", "unknown")
604
+ return f"TTS server unreachable at {url}: {e}"
605
+
591
606
  args = ["say"]
592
607
  if session:
593
608
  args.extend(["-s", session])
@@ -598,7 +613,11 @@ def say(text: str, session: str | None = None, voice: str | None = None) -> str:
598
613
  # Say command doesn't return JSON, run without --json
599
614
  data = run_agentwire_cmd(args, json_output=False)
600
615
  if data.get("success"):
601
- return "Text queued for speech."
616
+ from .utils.chunker import chunk_text
617
+ chunks = chunk_text(text)
618
+ if len(chunks) > 1:
619
+ return f"Queued speech ({len(chunks)} chunks)."
620
+ return "Queued speech."
602
621
  return f"Failed to speak: {data.get('error', 'Unknown error')}"
603
622
 
604
623