agentwire-dev 1.40.0__tar.gz → 1.42.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 (381) hide show
  1. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/PKG-INFO +1 -1
  2. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/__init__.py +1 -1
  3. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/__main__.py +278 -31
  4. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/cli_safety.py +43 -0
  5. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/config.py +11 -4
  6. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/state.py +55 -1
  7. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/view.py +22 -3
  8. agentwire_dev-1.42.0/agentwire/doctor_voice.py +383 -0
  9. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +126 -6
  10. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +79 -6
  11. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +79 -6
  12. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-member.md +17 -0
  13. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/safety/_core.py +79 -6
  14. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/scheduler.py +35 -6
  15. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/server.py +157 -77
  16. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/css/desktop.css +40 -1
  17. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/css/mobile.css +3 -0
  18. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/command-palette.js +91 -4
  19. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/council-window.js +45 -3
  20. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/desktop.js +94 -21
  21. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/mobile.js +32 -2
  22. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/notifications-panel.js +19 -0
  23. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/service-classification.js +9 -0
  24. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/session-window.js +18 -3
  25. agentwire_dev-1.42.0/agentwire/static/js/sidebar/council-section.js +114 -0
  26. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/sessions-section.js +3 -2
  27. agentwire_dev-1.42.0/agentwire/static/js/utils/swipe.js +68 -0
  28. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tasks.py +11 -0
  29. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/gh.yaml +1 -0
  30. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/git.yaml +4 -0
  31. agentwire_dev-1.42.0/agentwire/tts/__init__.py +32 -0
  32. agentwire_dev-1.42.0/agentwire/tts/kokoro_server.py +135 -0
  33. agentwire_dev-1.42.0/agentwire/wiki_audit.py +361 -0
  34. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/damage-control.md +65 -1
  35. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/troubleshooting.md +19 -0
  36. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/voice/tts-self-hosted.md +2 -2
  37. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_damage_control_hooks.py +89 -0
  38. agentwire_dev-1.42.0/tests/unit/test_doctor_voice.py +213 -0
  39. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_portal_api.py +64 -6
  40. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_scheduler.py +1 -1
  41. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_server_async.py +8 -10
  42. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_tts_local.py +101 -1
  43. agentwire_dev-1.42.0/tests/unit/test_wiki_audit.py +187 -0
  44. agentwire_dev-1.40.0/agentwire/static/js/sidebar/council-section.js +0 -89
  45. agentwire_dev-1.40.0/agentwire/tts/__init__.py +0 -13
  46. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/FUNDING.yml +0 -0
  47. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  48. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  49. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
  50. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  51. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/workflows/pytest.yml +0 -0
  52. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.github/workflows/tts-smoke.yml +0 -0
  53. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/.gitignore +0 -0
  54. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/CLA.md +0 -0
  55. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/CODE_OF_CONDUCT.md +0 -0
  56. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/CONTRIBUTING.md +0 -0
  57. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/Dockerfile.local +0 -0
  58. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/Dockerfile.runpod +0 -0
  59. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/LICENSE +0 -0
  60. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/README.md +0 -0
  61. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/RELEASING.md +0 -0
  62. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/SECURITY.md +0 -0
  63. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/SPONSORS.md +0 -0
  64. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/agents/__init__.py +0 -0
  65. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/agents/base.py +0 -0
  66. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/agents/tmux.py +0 -0
  67. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/cached_status.py +0 -0
  68. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/channels/__init__.py +0 -0
  69. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/channels/base.py +0 -0
  70. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/channels/email.py +0 -0
  71. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/channels/quo.py +0 -0
  72. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/completion.py +0 -0
  73. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/__init__.py +0 -0
  74. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/cli.py +0 -0
  75. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/council/inbox.py +0 -0
  76. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/fetch.py +0 -0
  77. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/__init__.py +0 -0
  78. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/git_state.py +0 -0
  79. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/instructions.py +0 -0
  80. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/parser.py +0 -0
  81. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/renderer.py +0 -0
  82. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/handoff/schema.py +0 -0
  83. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/history.py +0 -0
  84. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/__init__.py +0 -0
  85. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/agentwire-permission.sh +0 -0
  86. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/__init__.py +0 -0
  87. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
  88. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
  89. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
  90. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
  91. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
  92. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
  93. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
  94. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
  95. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
  96. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
  97. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
  98. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
  99. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
  100. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/idle-handler.sh +0 -0
  101. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/hooks/queue-processor.sh +0 -0
  102. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/inbox.py +0 -0
  103. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/limits_cli.py +0 -0
  104. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/listen.py +0 -0
  105. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/locking.py +0 -0
  106. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/mcp_server.py +0 -0
  107. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/msg_cli.py +0 -0
  108. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/network.py +0 -0
  109. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/onboarding.py +0 -0
  110. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/pane_manager.py +0 -0
  111. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/project_config.py +0 -0
  112. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/projects.py +0 -0
  113. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/prompt_router.py +0 -0
  114. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/prompts/__init__.py +0 -0
  115. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/prompts/init.md +0 -0
  116. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/prompts_cli.py +0 -0
  117. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/__init__.py +0 -0
  118. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/agentwire.md +0 -0
  119. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/chatbot.md +0 -0
  120. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-brain.md +0 -0
  121. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-conscience.md +0 -0
  122. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-critic.md +0 -0
  123. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-devils-advocate.md +0 -0
  124. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-gut.md +0 -0
  125. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-historian.md +0 -0
  126. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/council-orchestrator.md +0 -0
  127. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/init.md +0 -0
  128. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/notifications.md +0 -0
  129. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/orchestrator.md +0 -0
  130. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/soul.md +0 -0
  131. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/task-runner.md +0 -0
  132. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/voice.md +0 -0
  133. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/worker.md +0 -0
  134. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/roles/worktree-session.md +0 -0
  135. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/safety/__init__.py +0 -0
  136. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/scratchpad.py +0 -0
  137. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/security.py +0 -0
  138. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/services.py +0 -0
  139. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/session_ready.py +0 -0
  140. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/ssh.py +0 -0
  141. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-Echo--black.png +0 -0
  142. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-Echo--transparent.png +0 -0
  143. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-Echo.png +0 -0
  144. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-email-banner.png +0 -0
  145. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
  146. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
  147. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
  148. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
  149. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
  150. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
  151. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
  152. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
  153. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--transparent.png +0 -0
  154. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
  155. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
  156. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/announcements.json +0 -0
  157. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/favicon.png +0 -0
  158. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/android.jpeg +0 -0
  159. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/automaton.jpeg +0 -0
  160. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/bot.jpeg +0 -0
  161. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
  162. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/droid.jpeg +0 -0
  163. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/drone.jpeg +0 -0
  164. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/guardian.jpeg +0 -0
  165. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/mech.jpeg +0 -0
  166. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/probe.jpeg +0 -0
  167. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/robot.jpeg +0 -0
  168. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
  169. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/machines/unit.jpeg +0 -0
  170. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/blob.jpeg +0 -0
  171. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/cloud.jpeg +0 -0
  172. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/crystal.jpeg +0 -0
  173. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
  174. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/flame.jpeg +0 -0
  175. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
  176. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/horned.jpeg +0 -0
  177. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/moon.jpeg +0 -0
  178. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/slime.jpeg +0 -0
  179. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/star.jpeg +0 -0
  180. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
  181. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/projects/winged.jpeg +0 -0
  182. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/bear.jpeg +0 -0
  183. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/cat.jpeg +0 -0
  184. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/crown.jpeg +0 -0
  185. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
  186. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
  187. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
  188. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/deer.jpeg +0 -0
  189. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/drone.jpeg +0 -0
  190. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
  191. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/fox.jpeg +0 -0
  192. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
  193. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/horse.jpeg +0 -0
  194. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/lion.jpeg +0 -0
  195. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
  196. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/robot.jpeg +0 -0
  197. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
  198. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
  199. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/.gitkeep +0 -0
  200. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/announcement-modal.js +0 -0
  201. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/api.js +0 -0
  202. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/artifact-window.js +0 -0
  203. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/collage.js +0 -0
  204. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/components/icon-picker.js +0 -0
  205. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/components/list-card.js +0 -0
  206. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/components/type-tag.js +0 -0
  207. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
  208. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/desktop-manager.js +0 -0
  209. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/icon-manager.js +0 -0
  210. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/notification-prefs.js +0 -0
  211. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/safety-shared.js +0 -0
  212. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/safety-window.js +0 -0
  213. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/scratchpad.js +0 -0
  214. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/session-id.js +0 -0
  215. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
  216. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/config-section.js +0 -0
  217. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
  218. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
  219. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
  220. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
  221. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar/services-section.js +0 -0
  222. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/sidebar.js +0 -0
  223. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
  224. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/tile-manager.js +0 -0
  225. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/toast.js +0 -0
  226. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/token-modal.js +0 -0
  227. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/utils/ansi.js +0 -0
  228. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/utils/auto-refresh.js +0 -0
  229. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
  230. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/browser-stt.js +0 -0
  231. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/browser-tts.js +0 -0
  232. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/jargon.js +0 -0
  233. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/voice/prompt.js +0 -0
  234. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
  235. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/__init__.py +0 -0
  236. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/base.py +0 -0
  237. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/cloud.py +0 -0
  238. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/engine.py +0 -0
  239. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/local.py +0 -0
  240. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/server_backend.py +0 -0
  241. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/stt/stt_server.py +0 -0
  242. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/__init__.py +0 -0
  243. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/base.html +0 -0
  244. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/desktop.html +0 -0
  245. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/email_notification.html +0 -0
  246. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
  247. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
  248. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/mobile.html +0 -0
  249. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templates/tmux.conf +0 -0
  250. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/templating.py +0 -0
  251. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/aws.yaml +0 -0
  252. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/docker.yaml +0 -0
  253. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/gcp.yaml +0 -0
  254. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/gws.yaml +0 -0
  255. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/kubectl.yaml +0 -0
  256. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/npm.yaml +0 -0
  257. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/terraform.yaml +0 -0
  258. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tooldefs/uv.yaml +0 -0
  259. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/audio.py +0 -0
  260. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/base.py +0 -0
  261. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/__init__.py +0 -0
  262. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/chatterbox.py +0 -0
  263. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/kokoro.py +0 -0
  264. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/qwen_base.py +0 -0
  265. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/qwen_custom.py +0 -0
  266. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/qwen_design.py +0 -0
  267. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/engines/zonos.py +0 -0
  268. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/local.py +0 -0
  269. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts/registry.py +0 -0
  270. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tts_server.py +0 -0
  271. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/tunnels.py +0 -0
  272. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/usage_limit.py +0 -0
  273. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/__init__.py +0 -0
  274. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/chunker.py +0 -0
  275. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/file_io.py +0 -0
  276. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/paths.py +0 -0
  277. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/speech.py +0 -0
  278. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/utils/subprocess.py +0 -0
  279. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/validation.py +0 -0
  280. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voiceclone.py +0 -0
  281. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/darren.wav +0 -0
  282. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/default.wav +0 -0
  283. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/jessica.wav +0 -0
  284. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/lisa.wav +0 -0
  285. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/voices/may.wav +0 -0
  286. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/worktree.py +0 -0
  287. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/agentwire/worktree_registry.py +0 -0
  288. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/decisions/obsidian-second-brain.md +0 -0
  289. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/logo.png +0 -0
  290. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/INDEX.md +0 -0
  291. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/architecture.md +0 -0
  292. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/communication/channels.md +0 -0
  293. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/communication/hammerspoon.md +0 -0
  294. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/communication/handoff.md +0 -0
  295. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/concepts.md +0 -0
  296. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/council.md +0 -0
  297. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/deployment/remote-access.md +0 -0
  298. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/deployment/remote-machines.md +0 -0
  299. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/glossary.md +0 -0
  300. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
  301. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/portal.md +0 -0
  302. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/shell-escaping.md +0 -0
  303. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/internals/window-collage.md +0 -0
  304. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/quickstart.md +0 -0
  305. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
  306. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
  307. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/security/secrets.md +0 -0
  308. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/services.md +0 -0
  309. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
  310. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/messaging.md +0 -0
  311. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/pi.md +0 -0
  312. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/prompt-routing.md +0 -0
  313. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/window-sizing.md +0 -0
  314. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
  315. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/usage-limit-recovery.md +0 -0
  316. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/voice/shim-contract.md +0 -0
  317. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/voice/stt-cloud.md +0 -0
  318. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
  319. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/pyproject.toml +0 -0
  320. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/requirements-tts.txt +0 -0
  321. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/conftest.py +0 -0
  322. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/e2e/test_portal_ui.py +0 -0
  323. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/fixtures/sample_agentwire.yml +0 -0
  324. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/fixtures/sample_config.yaml +0 -0
  325. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/fixtures/sample_scheduler.yaml +0 -0
  326. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/integration/test_council_portal.py +0 -0
  327. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/integration/test_scheduler_board.py +0 -0
  328. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/integration/test_server_websockets.py +0 -0
  329. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/integration/test_worktree_cmd.py +0 -0
  330. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_announcements.py +0 -0
  331. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_build_agent_command.py +0 -0
  332. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_channels.py +0 -0
  333. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_cli_commands.py +0 -0
  334. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_cli_output.py +0 -0
  335. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_cli_safety.py +0 -0
  336. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_config.py +0 -0
  337. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_council_cli.py +0 -0
  338. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_council_inbox.py +0 -0
  339. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_council_state.py +0 -0
  340. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_council_view.py +0 -0
  341. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_damage_control_sync.py +0 -0
  342. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_file_io.py +0 -0
  343. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_handoff_git_state.py +0 -0
  344. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_handoff_instructions.py +0 -0
  345. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_handoff_parser.py +0 -0
  346. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_handoff_renderer.py +0 -0
  347. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_history.py +0 -0
  348. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_hooks_install.py +0 -0
  349. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_idle_handler.py +0 -0
  350. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_inbox.py +0 -0
  351. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_locking.py +0 -0
  352. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_mcp_server.py +0 -0
  353. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_mcp_tools_args.py +0 -0
  354. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_msg_cli.py +0 -0
  355. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_project_config.py +0 -0
  356. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_prompt_router.py +0 -0
  357. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_roles.py +0 -0
  358. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_safety_disabled_rules.py +0 -0
  359. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_safety_escape_hatch.py +0 -0
  360. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_safety_kill_switch.py +0 -0
  361. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_scheduler_parsing.py +0 -0
  362. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_scratchpad.py +0 -0
  363. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_security.py +0 -0
  364. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_server_pure.py +0 -0
  365. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_services.py +0 -0
  366. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_session_ready.py +0 -0
  367. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_speech_tags.py +0 -0
  368. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_ssh.py +0 -0
  369. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_stt_backend.py +0 -0
  370. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_stt_cloud.py +0 -0
  371. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_stt_engine.py +0 -0
  372. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_task_cli.py +0 -0
  373. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_tasks.py +0 -0
  374. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_templating.py +0 -0
  375. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_terminal_resize.py +0 -0
  376. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_tmux_template.py +0 -0
  377. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_tts_engine_resolution.py +0 -0
  378. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_usage_limit.py +0 -0
  379. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_validation.py +0 -0
  380. {agentwire_dev-1.40.0 → agentwire_dev-1.42.0}/tests/unit/test_worktree.py +0 -0
  381. {agentwire_dev-1.40.0 → agentwire_dev-1.42.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.40.0
3
+ Version: 1.42.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.40.0"
3
+ __version__ = "1.42.0"
@@ -103,6 +103,31 @@ class AgentCommand:
103
103
  env: dict[str, str] = field(default_factory=dict) # Secrets to inject via tmux set-environment (keeps keys out of `ps`)
104
104
 
105
105
 
106
+ _UNATTENDED_ENV_KEYS = ("AGENTWIRE_UNATTENDED", "AGENTWIRE_UNATTENDED_ALLOW")
107
+
108
+
109
+ def _with_unattended_env(env: dict[str, str]) -> dict[str, str]:
110
+ """Propagate the unattended marker into a session being created.
111
+
112
+ The scheduler is the single place that decides a dispatch is unattended —
113
+ it seeds ``AGENTWIRE_UNATTENDED[=1]`` (and any per-task
114
+ ``AGENTWIRE_UNATTENDED_ALLOW``) into the dispatch subprocess environment.
115
+ Every session-creation path funnels its env through here on the way to
116
+ ``tmux new-session -e K=V``, so the marker lands in the new session BEFORE
117
+ the agent launches and the damage-control hook can read it. A child session
118
+ an unattended agent spawns inherits the marker too (defense in depth).
119
+
120
+ No leak into interactive sessions: a human's ``agentwire new`` has no such
121
+ var in its environment, so nothing is propagated.
122
+ """
123
+ merged = dict(env)
124
+ for key in _UNATTENDED_ENV_KEYS:
125
+ val = os.environ.get(key)
126
+ if val and key not in merged:
127
+ merged[key] = val
128
+ return merged
129
+
130
+
106
131
  def _build_tmux_env_flags(env: dict[str, str]) -> list[str]:
107
132
  """Build `-e KEY=VAL` flag pairs for `tmux new-session`.
108
133
 
@@ -114,16 +139,17 @@ def _build_tmux_env_flags(env: dict[str, str]) -> list[str]:
114
139
  the var — and the agent command runs in that initial shell.
115
140
  """
116
141
  flags: list[str] = []
117
- for key, value in env.items():
142
+ for key, value in _with_unattended_env(env).items():
118
143
  flags.extend(["-e", f"{key}={value}"])
119
144
  return flags
120
145
 
121
146
 
122
147
  def _build_tmux_env_flags_shell(env: dict[str, str]) -> str:
123
148
  """Shell-quoted `-e 'K=V' …` fragment for inlining via SSH. Trailing space when non-empty."""
124
- if not env:
149
+ merged = _with_unattended_env(env)
150
+ if not merged:
125
151
  return ""
126
- parts = [f"-e {shlex.quote(f'{k}={v}')}" for k, v in env.items()]
152
+ parts = [f"-e {shlex.quote(f'{k}={v}')}" for k, v in merged.items()]
127
153
  return " ".join(parts) + " "
128
154
 
129
155
 
@@ -543,6 +569,12 @@ def get_stt_session_name() -> str:
543
569
  return config.get("services", {}).get("stt", {}).get("session_name", "agentwire-stt")
544
570
 
545
571
 
572
+ def get_kokoro_session_name() -> str:
573
+ """Get default-tier Kokoro TTS shim tmux session name from config."""
574
+ config = load_config()
575
+ return config.get("services", {}).get("kokoro", {}).get("session_name", "agentwire-kokoro")
576
+
577
+
546
578
  # === Wave 2: Remote Infrastructure Helpers ===
547
579
 
548
580
 
@@ -1929,6 +1961,148 @@ def cmd_stt_status(args) -> int:
1929
1961
  return 1
1930
1962
 
1931
1963
 
1964
+ # === Kokoro (default-tier TTS shim) Commands ===
1965
+
1966
+ def cmd_kokoro_start(args) -> int:
1967
+ """Start the default-tier Kokoro TTS shim in tmux (idempotent).
1968
+
1969
+ Mirrors ``agentwire stt start``: the portal's ``ensure_managed_tts`` calls
1970
+ this on startup, and the early-return on an existing session means a
1971
+ user-started shim is reused with no port clash."""
1972
+ session_name = get_kokoro_session_name()
1973
+
1974
+ if tmux_session_exists(session_name):
1975
+ print(f"Kokoro TTS shim already running in tmux session '{session_name}'")
1976
+ print(f" Attach: tmux attach -t {session_name}")
1977
+ return 0
1978
+
1979
+ port = args.port or 8102
1980
+ host = args.host or "0.0.0.0"
1981
+
1982
+ # Find agentwire source directory (for running from source venv)
1983
+ source_dir = get_source_dir()
1984
+ if not (source_dir / ".venv" / "bin" / "python").exists():
1985
+ print("Error: Cannot find agentwire source directory with .venv", file=sys.stderr)
1986
+ print(f"Configure dev.source_dir in ~/.agentwire/config.yaml (current: {source_dir})", file=sys.stderr)
1987
+ return 1
1988
+ agentwire_dir = source_dir
1989
+
1990
+ python_path = agentwire_dir / ".venv" / "bin" / "python"
1991
+ cmd = f"cd {agentwire_dir} && KOKORO_PORT={port} KOKORO_HOST={host} {python_path} -m agentwire.tts.kokoro_server"
1992
+
1993
+ subprocess.run([
1994
+ "tmux", "new-session", "-d", "-s", session_name, "-c", str(agentwire_dir)
1995
+ ], check=True)
1996
+
1997
+ subprocess.run([
1998
+ "tmux", "send-keys", "-t", session_name, cmd, "Enter"
1999
+ ], check=True)
2000
+
2001
+ print(f"Kokoro TTS shim starting in tmux session '{session_name}'")
2002
+ print(f" Port: {port}")
2003
+ print(f" Attach: tmux attach -t {session_name}")
2004
+ return 0
2005
+
2006
+
2007
+ def cmd_kokoro_serve(args) -> int:
2008
+ """Run the Kokoro TTS shim directly (foreground)."""
2009
+ import uvicorn
2010
+
2011
+ port = args.port or 8102
2012
+ host = args.host or "0.0.0.0"
2013
+
2014
+ os.environ["KOKORO_PORT"] = str(port)
2015
+ os.environ["KOKORO_HOST"] = host
2016
+
2017
+ print(f"Starting Kokoro TTS shim on {host}:{port}...")
2018
+ uvicorn.run(
2019
+ "agentwire.tts.kokoro_server:app",
2020
+ host=host,
2021
+ port=port,
2022
+ log_level="info",
2023
+ )
2024
+ return 0
2025
+
2026
+
2027
+ def cmd_kokoro_stop(args) -> int:
2028
+ """Stop the Kokoro TTS shim."""
2029
+ session_name = get_kokoro_session_name()
2030
+
2031
+ if not tmux_session_exists(session_name):
2032
+ print("Kokoro TTS shim is not running.")
2033
+ return 1
2034
+
2035
+ subprocess.run(["tmux", "kill-session", "-t", session_name])
2036
+ print("Kokoro TTS shim stopped.")
2037
+ return 0
2038
+
2039
+
2040
+ def cmd_kokoro_status(args) -> int:
2041
+ """Check Kokoro TTS shim status."""
2042
+ json_mode = getattr(args, 'json', False)
2043
+ session_name = get_kokoro_session_name()
2044
+ config = load_config()
2045
+ kokoro_url = config.get("tts", {}).get("url") or "http://localhost:8102"
2046
+
2047
+ probe_error = None
2048
+ try:
2049
+ req = urllib.request.Request(f"{kokoro_url}/health")
2050
+ with urllib.request.urlopen(req, timeout=3) as resp:
2051
+ data = json.loads(resp.read().decode())
2052
+ if json_mode:
2053
+ _output_json({
2054
+ "success": True,
2055
+ "running": True,
2056
+ "url": kokoro_url,
2057
+ "healthy": data.get("status") == "ok",
2058
+ "status": data.get("status", "unknown"),
2059
+ "percent": data.get("percent", 0),
2060
+ "session": session_name if tmux_session_exists(session_name) else None,
2061
+ })
2062
+ else:
2063
+ print("Kokoro TTS shim is running")
2064
+ print(f" State: {data.get('status', 'unknown')} ({data.get('percent', 0)}%)")
2065
+ print(f" URL: {kokoro_url}")
2066
+ if tmux_session_exists(session_name):
2067
+ print(f" Attach: tmux attach -t {session_name}")
2068
+ return 0
2069
+ except Exception as e:
2070
+ probe_error = _describe_probe_error(e)
2071
+
2072
+ if tmux_session_exists(session_name):
2073
+ if json_mode:
2074
+ _output_json({
2075
+ "success": True,
2076
+ "running": True,
2077
+ "url": kokoro_url,
2078
+ "healthy": False,
2079
+ "error": probe_error,
2080
+ "session": session_name,
2081
+ "starting": True,
2082
+ })
2083
+ else:
2084
+ print(f"Kokoro TTS shim is starting in tmux session '{session_name}'")
2085
+ if probe_error:
2086
+ print(f" Probe: {probe_error}")
2087
+ print(f" Attach: tmux attach -t {session_name}")
2088
+ return 0
2089
+
2090
+ if json_mode:
2091
+ _output_json({
2092
+ "success": True,
2093
+ "running": False,
2094
+ "url": kokoro_url,
2095
+ "healthy": False,
2096
+ "error": probe_error,
2097
+ })
2098
+ else:
2099
+ print("Kokoro TTS shim is not running.")
2100
+ if probe_error:
2101
+ print(f" Probe: {probe_error}")
2102
+ print(" Start: agentwire kokoro start")
2103
+ return 1
2104
+
2105
+
1932
2106
  # === Telegram Commands ===
1933
2107
 
1934
2108
 
@@ -6830,6 +7004,15 @@ def cmd_safety_status(args) -> int:
6830
7004
  return cli_safety.safety_status_cmd()
6831
7005
 
6832
7006
 
7007
+ def cmd_safety_notify_unattended_block(args) -> int:
7008
+ """CLI command: agentwire safety notify-unattended-block (hook-invoked)"""
7009
+ return cli_safety.safety_notify_unattended_block_cmd(
7010
+ getattr(args, "reason", "") or "",
7011
+ getattr(args, "rule_id", "") or "",
7012
+ getattr(args, "command", "") or "",
7013
+ )
7014
+
7015
+
6833
7016
  def cmd_safety_logs(args) -> int:
6834
7017
  """CLI command: agentwire safety logs"""
6835
7018
  tail = getattr(args, 'tail', None)
@@ -6854,6 +7037,29 @@ def cmd_safety_tooldefs_show(args) -> int:
6854
7037
  return cli_safety.safety_tooldefs_show_cmd(args.tool)
6855
7038
 
6856
7039
 
7040
+ def _render_voice_loop_section(config, ctx) -> int:
7041
+ """Print the voice-loop (push-to-talk) preflight. Returns failures found.
7042
+
7043
+ Read-only pass/fail per stage with an actionable fix line when red — the
7044
+ existing infra sections keep the auto-fix prompts.
7045
+ """
7046
+ from .doctor_voice import run_voice_loop_checks
7047
+
7048
+ print("\nChecking voice loop (push-to-talk)...")
7049
+ failures = 0
7050
+ for stage in run_voice_loop_checks(config, ctx):
7051
+ if stage.status == "ok":
7052
+ print(f" [ok] {stage.name}: {stage.detail}")
7053
+ elif stage.status == "info":
7054
+ print(f" [..] {stage.name}: {stage.detail}")
7055
+ else:
7056
+ print(f" [!!] {stage.name}: {stage.detail}")
7057
+ for fix in stage.fixes:
7058
+ print(f" Fix: {fix}")
7059
+ failures += 1
7060
+ return failures
7061
+
7062
+
6857
7063
  def cmd_doctor(args) -> int:
6858
7064
  """Auto-diagnose and fix common issues."""
6859
7065
  from .network import NetworkContext
@@ -6862,6 +7068,7 @@ def cmd_doctor(args) -> int:
6862
7068
 
6863
7069
  dry_run = getattr(args, 'dry_run', False)
6864
7070
  auto_confirm = getattr(args, 'yes', False)
7071
+ voice_only = getattr(args, 'voice', False)
6865
7072
 
6866
7073
  print("AgentWire Doctor")
6867
7074
  print("=" * 60)
@@ -6869,6 +7076,27 @@ def cmd_doctor(args) -> int:
6869
7076
  issues_found = 0
6870
7077
  issues_fixed = 0
6871
7078
 
7079
+ # --voice: run ONLY the end-to-end push-to-talk preflight (fast, no SSH
7080
+ # waits) — for tight first-run / break-a-dependency verification loops.
7081
+ if voice_only:
7082
+ try:
7083
+ from .config import load_config as load_config_typed
7084
+ config = load_config_typed()
7085
+ except Exception as e:
7086
+ print(f"\n [!!] Config file error: {e}")
7087
+ print(" Run: agentwire init")
7088
+ return 1
7089
+ try:
7090
+ ctx = NetworkContext.from_config()
7091
+ except Exception:
7092
+ ctx = None
7093
+ issues_found = _render_voice_loop_section(config, ctx)
7094
+ print()
7095
+ print("-" * 60)
7096
+ print("Voice loop ready!" if issues_found == 0
7097
+ else f"Voice loop: {issues_found} stage(s) need attention")
7098
+ return 0 if issues_found == 0 else 1
7099
+
6872
7100
  # 1. Check Python version
6873
7101
  print("\nChecking Python version...")
6874
7102
  py_version = sys.version_info
@@ -7158,34 +7386,12 @@ def cmd_doctor(args) -> int:
7158
7386
  else:
7159
7387
  print(f" -> Service is remote, start it on {service_config.machine}")
7160
7388
 
7161
- # 8b. Check STT shim. STT isn't a `services.*` entry it's configured via
7162
- # `stt.url`, so the loop above can't see it. Without this check, a crashed
7163
- # STT shim is invisible and every custom-tier push-to-talk fails at request
7164
- # time. Probe it explicitly. (Default tier transcribes in the browser — no
7165
- # service to check.)
7166
- stt_cfg = getattr(ctx.config, "stt", None)
7167
- if getattr(stt_cfg, "backend", "default") == "custom":
7168
- from agentwire.stt.server_backend import STTServerBackend
7169
-
7170
- stt_url = stt_cfg.url
7171
- if STTServerBackend.is_available(stt_url):
7172
- print(f" [ok] Stt: responding on {stt_url}")
7173
- else:
7174
- print(f" [!!] Stt: not responding on {stt_url}")
7175
- print(" Custom-tier push-to-talk will fail until it's back.")
7176
- print(" Fix: agentwire stt start")
7177
- print(" If it won't boot: uv pip install --python .venv/bin/python -e '.[stt]'")
7178
- issues_found += 1
7179
- elif getattr(stt_cfg, "backend", "default") == "cloud":
7180
- cloud_cfg = getattr(stt_cfg, "cloud", None) or {}
7181
- key_env = cloud_cfg.get("api_key_env", "OPENAI_API_KEY")
7182
- if os.environ.get(key_env):
7183
- print(f" [ok] Stt: cloud tier ({key_env} is set)")
7184
- else:
7185
- print(f" [!!] Stt: cloud tier but {key_env} is not set")
7186
- print(" The portal will refuse to start until the key is in its environment.")
7187
- print(" Fix: add the key to ~/.agentwire/.env (docs/wiki/security/secrets.md)")
7188
- issues_found += 1
7389
+ # 8b. Voice loop (push-to-talk) walk the live PTT path end to end and
7390
+ # report each stage pass/fail with a fix line when red: mic/audio capture,
7391
+ # the STT shim (incl. the default-tier Moonshine :8101 shim, invisible to
7392
+ # the services loop), portal/tunnel reachability, and tmux+PTT wiring. This
7393
+ # subsumes the old standalone STT probe — the STT stage covers all tiers.
7394
+ issues_found += _render_voice_loop_section(config, ctx)
7189
7395
 
7190
7396
  # 8c. Secrets — for each configured feature that needs a key, report
7191
7397
  # whether its env var is present. Names only, never values. Keys live in
@@ -10767,6 +10973,33 @@ def main() -> int:
10767
10973
  stt_status.add_argument("--json", action="store_true", help="Output JSON")
10768
10974
  stt_status.set_defaults(func=cmd_stt_status)
10769
10975
 
10976
+ # === kokoro command group (default-tier TTS shim) ===
10977
+ kokoro_parser = subparsers.add_parser(
10978
+ "kokoro", help="Manage the default-tier Kokoro TTS shim (process-isolated)"
10979
+ )
10980
+ kokoro_subparsers = kokoro_parser.add_subparsers(dest="kokoro_command")
10981
+
10982
+ # kokoro start
10983
+ kokoro_start = kokoro_subparsers.add_parser("start", help="Start Kokoro shim in tmux")
10984
+ kokoro_start.add_argument("--port", type=int, help="Server port (default: 8102)")
10985
+ kokoro_start.add_argument("--host", type=str, help="Server host (default: 0.0.0.0)")
10986
+ kokoro_start.set_defaults(func=cmd_kokoro_start)
10987
+
10988
+ # kokoro serve
10989
+ kokoro_serve = kokoro_subparsers.add_parser("serve", help="Run Kokoro shim in foreground")
10990
+ kokoro_serve.add_argument("--port", type=int, help="Server port (default: 8102)")
10991
+ kokoro_serve.add_argument("--host", type=str, help="Server host (default: 0.0.0.0)")
10992
+ kokoro_serve.set_defaults(func=cmd_kokoro_serve)
10993
+
10994
+ # kokoro stop
10995
+ kokoro_stop = kokoro_subparsers.add_parser("stop", help="Stop Kokoro shim")
10996
+ kokoro_stop.set_defaults(func=cmd_kokoro_stop)
10997
+
10998
+ # kokoro status
10999
+ kokoro_status = kokoro_subparsers.add_parser("status", help="Check Kokoro shim status")
11000
+ kokoro_status.add_argument("--json", action="store_true", help="Output JSON")
11001
+ kokoro_status.set_defaults(func=cmd_kokoro_status)
11002
+
10770
11003
  # === quo command ===
10771
11004
  from agentwire.channels.quo import cmd_quo
10772
11005
  quo_parser = subparsers.add_parser("quo", help="Send SMS via Quo (OpenPhone)")
@@ -11357,6 +11590,16 @@ def main() -> int:
11357
11590
  )
11358
11591
  safety_status.set_defaults(func=cmd_safety_status)
11359
11592
 
11593
+ # safety notify-unattended-block (hook-invoked, not for humans)
11594
+ safety_notify = safety_subparsers.add_parser(
11595
+ "notify-unattended-block",
11596
+ help="Email the owner that an unattended action was blocked (hook-internal)",
11597
+ )
11598
+ safety_notify.add_argument("--reason", default="", help="Why the command was blocked")
11599
+ safety_notify.add_argument("--rule-id", dest="rule_id", default="", help="Matched rule id")
11600
+ safety_notify.add_argument("--command", default="", help="The blocked command")
11601
+ safety_notify.set_defaults(func=cmd_safety_notify_unattended_block)
11602
+
11360
11603
  # safety logs
11361
11604
  safety_logs = safety_subparsers.add_parser(
11362
11605
  "logs", help="Query audit logs"
@@ -11406,6 +11649,10 @@ def main() -> int:
11406
11649
  "-y", "--yes", action="store_true",
11407
11650
  help="Auto-confirm all fixes without prompting"
11408
11651
  )
11652
+ doctor_parser.add_argument(
11653
+ "--voice", action="store_true",
11654
+ help="Run only the voice loop (push-to-talk) preflight — fast, no SSH waits"
11655
+ )
11409
11656
  doctor_parser.set_defaults(func=cmd_doctor)
11410
11657
 
11411
11658
  # === generate-certs (top-level shortcut) ===
@@ -8,6 +8,7 @@ stay in sync.
8
8
  """
9
9
 
10
10
  import json
11
+ import os
11
12
  import shutil
12
13
  import sys
13
14
  from datetime import datetime
@@ -342,6 +343,48 @@ def safety_status_cmd() -> int:
342
343
  return 0
343
344
 
344
345
 
346
+ def safety_notify_unattended_block_cmd(
347
+ reason: str, rule_id: str, command: str
348
+ ) -> int:
349
+ """CLI command: ``agentwire safety notify-unattended-block``.
350
+
351
+ Invoked fire-and-forget by the bash damage-control hook when an
352
+ unattended (scheduler) run hits an ``ask``-tier command that isn't on the
353
+ allowlist. Emails the owner via the shared Resend wiring so the blocked
354
+ action surfaces immediately instead of silently disappearing.
355
+ """
356
+ session = os.environ.get("AGENTWIRE_SESSION_NAME") or os.environ.get(
357
+ "AGENTWIRE_SESSION_ID", "unknown"
358
+ )
359
+ cwd = os.environ.get("PWD", "")
360
+ subject = f"[agentwire] Unattended action blocked: {reason[:80]}"
361
+ body = (
362
+ f"An unattended (scheduled) agent attempted an action that requires "
363
+ f"human confirmation, so it was **blocked** (fail-closed).\n\n"
364
+ f"- **Session:** {session}\n"
365
+ f"- **Working dir:** {cwd or 'unknown'}\n"
366
+ f"- **Rule:** {rule_id or 'unknown'}\n"
367
+ f"- **Reason:** {reason}\n"
368
+ f"- **Command:** `{command}`\n"
369
+ f"- **When:** {datetime.now().isoformat(timespec='seconds')}\n\n"
370
+ f"Nothing was executed. To permit this specific action for the task in "
371
+ f"future, add rule id `{rule_id}` to that task's `unattended_allow` in "
372
+ f"its `.agentwire.yml` (or to `safety.unattended_allow` globally)."
373
+ )
374
+ try:
375
+ from agentwire.channels.email import send_email
376
+
377
+ result = send_email(subject=subject, body=body)
378
+ if getattr(result, "success", False):
379
+ return 0
380
+ print(f"notify-unattended-block: email failed: "
381
+ f"{getattr(result, 'error', 'unknown')}", file=sys.stderr)
382
+ return 1
383
+ except Exception as e: # email not configured, etc. — never crash the notifier
384
+ print(f"notify-unattended-block: {e}", file=sys.stderr)
385
+ return 1
386
+
387
+
345
388
  def safety_logs_cmd(
346
389
  tail: Optional[int] = None,
347
390
  session: Optional[str] = None,
@@ -164,13 +164,20 @@ def _validate_voice_backend(
164
164
  class TTSConfig:
165
165
  """Text-to-speech configuration.
166
166
 
167
- Two tiers: ``default`` speaks via the browser (speechSynthesis) with an
168
- OS-voice fallback when no browser is connected; ``custom`` POSTs to any
169
- HTTP shim implementing the contract (docs/wiki/voice/shim-contract.md).
167
+ Two tiers: ``default`` speaks via Kokoro running in the portal-managed shim
168
+ **subprocess** (tmux ``agentwire-kokoro``, default ``:8102``) the portal
169
+ ensures it's running on startup and talks to it over HTTP, with process
170
+ isolation keeping the ~200 MB download + ONNX warm-up off the event loop
171
+ (#398, mirroring the STT shim). Browser speechSynthesis (and an OS-voice
172
+ fallback when no browser is connected) covers speech while the model loads
173
+ or when Kokoro can't load (py3.14+). For this tier ``url`` is optional and
174
+ resolves to ``http://localhost:8102``; if an operator overrides the shim
175
+ port (``KOKORO_PORT``) or ``url``, the two must agree. ``custom`` POSTs to
176
+ any HTTP shim implementing the contract (docs/wiki/voice/shim-contract.md).
170
177
  """
171
178
 
172
179
  backend: str = "default" # default | custom
173
- url: str | None = None # shim URL (required for custom backend)
180
+ url: str | None = None # shim URL (required for custom; optional override for default :8102)
174
181
  default_voice: str = "default"
175
182
  voices_dir: Path = field(default_factory=lambda: Path.home() / ".agentwire" / "voices")
176
183
  # Session-default knobs; sent to custom shims inside `options`
@@ -69,6 +69,11 @@ def sitting_path(name: str) -> Path:
69
69
  return council_dir(name) / "sitting.json"
70
70
 
71
71
 
72
+ def archive_path(name: str) -> Path:
73
+ """Preserved record of a dismissed sitting (kept so threads stay browsable)."""
74
+ return council_dir(name) / "archive.json"
75
+
76
+
72
77
  def workspace_dir(name: str) -> Path:
73
78
  return council_dir(name) / "workspace"
74
79
 
@@ -195,13 +200,62 @@ def write_sitting(name: str, sitting: Sitting) -> None:
195
200
 
196
201
 
197
202
  def clear_sitting(name: str) -> None:
198
- """End the sitting. Prompt history under ``prompts/`` is kept."""
203
+ """End the sitting. A thread that deliberated something is preserved to
204
+ ``archive.json`` (so it stays browsable/re-askable from the UI), and the
205
+ ``prompts/`` history is kept; only the live ``sitting.json`` is removed."""
206
+ sitting = read_sitting(name)
207
+ if sitting is not None and prompts_dir(name).is_dir():
208
+ data = sitting.to_dict()
209
+ data["dismissed_at"] = now_iso()
210
+ try:
211
+ _atomic_write(archive_path(name), data)
212
+ except OSError:
213
+ pass
199
214
  try:
200
215
  sitting_path(name).unlink()
201
216
  except FileNotFoundError:
202
217
  pass
203
218
 
204
219
 
220
+ def read_archive_dict(name: str) -> dict | None:
221
+ """Raw archive record (incl. ``dismissed_at``), or None if not archived."""
222
+ path = archive_path(name)
223
+ if not path.exists():
224
+ return None
225
+ try:
226
+ with open(path) as f:
227
+ data = json.load(f)
228
+ except (json.JSONDecodeError, OSError):
229
+ return None
230
+ return data if isinstance(data, dict) else None
231
+
232
+
233
+ def read_archived(name: str) -> Sitting | None:
234
+ """The preserved record of a dismissed sitting as a ``Sitting``, or None."""
235
+ data = read_archive_dict(name)
236
+ return Sitting.from_dict(data) if data is not None else None
237
+
238
+
239
+ def _has_rounds(name: str) -> bool:
240
+ pdir = prompts_dir(name)
241
+ if not pdir.is_dir():
242
+ return False
243
+ return any(p.is_dir() and p.name.isdigit() for p in pdir.iterdir())
244
+
245
+
246
+ def list_archive() -> list[str]:
247
+ """Dismissed threads: have prompt history but no live ``sitting.json``."""
248
+ if not COUNCIL_ROOT.is_dir():
249
+ return []
250
+ out = []
251
+ for child in COUNCIL_ROOT.iterdir():
252
+ if not child.is_dir() or (child / "sitting.json").exists():
253
+ continue # absent or still live
254
+ if _has_rounds(child.name):
255
+ out.append(child.name)
256
+ return out
257
+
258
+
205
259
  def allocate_prompt_id(name: str) -> int:
206
260
  """Bump and persist the sitting's prompt counter; return the new id.
207
261
 
@@ -143,13 +143,31 @@ def snapshot(
143
143
  the sitting ``name``; the per-prompt ``meta.json.roster`` (falling back to
144
144
  the sitting roster) fixes both soul order and grid size — nothing is
145
145
  hardcoded to a roster of six.
146
+
147
+ The thread artifact outlives the compute: a dismissed sitting (no live
148
+ ``sitting.json``) is still a fully readable thread, derived from the
149
+ preserved ``archive.json`` or, failing that, reconstructed from the
150
+ ``prompts/`` tree. ``archived`` flags which case the caller is looking at.
146
151
  """
147
152
  sitting = state.read_sitting(name)
153
+ archived = sitting is None
148
154
  if sitting is None:
149
- return None
150
-
155
+ sitting = state.read_archived(name)
156
+ if sitting is None:
157
+ if not available_prompt_ids(name):
158
+ return None
159
+ sitting = state.Sitting(
160
+ orchestrator=state.orchestrator_for(name),
161
+ roster=[],
162
+ sessions={},
163
+ started_at="",
164
+ )
165
+
166
+ # available_prompt_ids (disk-derived) works for live and archived alike —
167
+ # the sitting.json prompt counter is gone once dismissed.
151
168
  if prompt_id is None:
152
- prompt_id = state.latest_prompt_id(name)
169
+ ids = available_prompt_ids(name)
170
+ prompt_id = ids[-1] if ids else None
153
171
 
154
172
  dead_souls = dead_souls or set()
155
173
 
@@ -178,6 +196,7 @@ def snapshot(
178
196
  "tiles": tiles,
179
197
  "total": len(tiles),
180
198
  "final": final,
199
+ "archived": archived,
181
200
  }
182
201
 
183
202