agentwire-dev 1.40.0__tar.gz → 1.41.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 (375) hide show
  1. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/PKG-INFO +1 -1
  2. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/__init__.py +1 -1
  3. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/council/state.py +55 -1
  4. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/council/view.py +22 -3
  5. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/council-member.md +17 -0
  6. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/server.py +53 -10
  7. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/css/desktop.css +40 -1
  8. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/css/mobile.css +3 -0
  9. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/command-palette.js +91 -4
  10. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/council-window.js +45 -3
  11. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/desktop.js +91 -21
  12. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/mobile.js +32 -2
  13. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/service-classification.js +9 -0
  14. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/session-window.js +18 -3
  15. agentwire_dev-1.41.0/agentwire/static/js/sidebar/council-section.js +114 -0
  16. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar/sessions-section.js +3 -2
  17. agentwire_dev-1.41.0/agentwire/static/js/utils/swipe.js +68 -0
  18. agentwire_dev-1.40.0/agentwire/static/js/sidebar/council-section.js +0 -89
  19. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/.github/FUNDING.yml +0 -0
  20. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  21. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  22. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
  23. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  24. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/.github/workflows/pytest.yml +0 -0
  25. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/.github/workflows/tts-smoke.yml +0 -0
  26. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/.gitignore +0 -0
  27. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/CLA.md +0 -0
  28. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/CODE_OF_CONDUCT.md +0 -0
  29. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/CONTRIBUTING.md +0 -0
  30. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/Dockerfile.local +0 -0
  31. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/Dockerfile.runpod +0 -0
  32. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/LICENSE +0 -0
  33. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/README.md +0 -0
  34. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/RELEASING.md +0 -0
  35. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/SECURITY.md +0 -0
  36. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/SPONSORS.md +0 -0
  37. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/__main__.py +0 -0
  38. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/agents/__init__.py +0 -0
  39. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/agents/base.py +0 -0
  40. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/agents/tmux.py +0 -0
  41. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/cached_status.py +0 -0
  42. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/channels/__init__.py +0 -0
  43. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/channels/base.py +0 -0
  44. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/channels/email.py +0 -0
  45. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/channels/quo.py +0 -0
  46. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/cli_safety.py +0 -0
  47. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/completion.py +0 -0
  48. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/config.py +0 -0
  49. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/council/__init__.py +0 -0
  50. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/council/cli.py +0 -0
  51. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/council/inbox.py +0 -0
  52. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/fetch.py +0 -0
  53. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/handoff/__init__.py +0 -0
  54. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/handoff/git_state.py +0 -0
  55. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/handoff/instructions.py +0 -0
  56. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/handoff/parser.py +0 -0
  57. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/handoff/renderer.py +0 -0
  58. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/handoff/schema.py +0 -0
  59. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/history.py +0 -0
  60. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/__init__.py +0 -0
  61. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/agentwire-permission.sh +0 -0
  62. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/__init__.py +0 -0
  63. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/audit_logger.py +0 -0
  64. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
  65. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
  66. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
  67. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
  68. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
  69. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
  70. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
  71. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
  72. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
  73. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
  74. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
  75. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
  76. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
  77. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
  78. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
  79. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/idle-handler.sh +0 -0
  80. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/hooks/queue-processor.sh +0 -0
  81. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/inbox.py +0 -0
  82. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/limits_cli.py +0 -0
  83. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/listen.py +0 -0
  84. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/locking.py +0 -0
  85. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/mcp_server.py +0 -0
  86. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/msg_cli.py +0 -0
  87. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/network.py +0 -0
  88. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/onboarding.py +0 -0
  89. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/pane_manager.py +0 -0
  90. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/project_config.py +0 -0
  91. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/projects.py +0 -0
  92. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/prompt_router.py +0 -0
  93. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/prompts/__init__.py +0 -0
  94. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/prompts/init.md +0 -0
  95. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/prompts_cli.py +0 -0
  96. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/__init__.py +0 -0
  97. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/agentwire.md +0 -0
  98. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/chatbot.md +0 -0
  99. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/council-brain.md +0 -0
  100. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/council-conscience.md +0 -0
  101. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/council-critic.md +0 -0
  102. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/council-devils-advocate.md +0 -0
  103. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/council-gut.md +0 -0
  104. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/council-historian.md +0 -0
  105. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/council-orchestrator.md +0 -0
  106. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/init.md +0 -0
  107. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/notifications.md +0 -0
  108. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/orchestrator.md +0 -0
  109. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/soul.md +0 -0
  110. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/task-runner.md +0 -0
  111. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/voice.md +0 -0
  112. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/worker.md +0 -0
  113. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/roles/worktree-session.md +0 -0
  114. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/safety/__init__.py +0 -0
  115. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/safety/_core.py +0 -0
  116. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/scheduler.py +0 -0
  117. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/scratchpad.py +0 -0
  118. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/security.py +0 -0
  119. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/services.py +0 -0
  120. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/session_ready.py +0 -0
  121. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/ssh.py +0 -0
  122. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-Echo--black.png +0 -0
  123. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-Echo--transparent.png +0 -0
  124. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-Echo.png +0 -0
  125. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-email-banner.png +0 -0
  126. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
  127. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
  128. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
  129. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
  130. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
  131. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
  132. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
  133. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
  134. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--transparent.png +0 -0
  135. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
  136. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
  137. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/announcements.json +0 -0
  138. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/favicon.png +0 -0
  139. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/android.jpeg +0 -0
  140. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/automaton.jpeg +0 -0
  141. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/bot.jpeg +0 -0
  142. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
  143. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/droid.jpeg +0 -0
  144. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/drone.jpeg +0 -0
  145. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/guardian.jpeg +0 -0
  146. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/mech.jpeg +0 -0
  147. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/probe.jpeg +0 -0
  148. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/robot.jpeg +0 -0
  149. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
  150. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/machines/unit.jpeg +0 -0
  151. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/blob.jpeg +0 -0
  152. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/cloud.jpeg +0 -0
  153. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/crystal.jpeg +0 -0
  154. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
  155. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/flame.jpeg +0 -0
  156. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
  157. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/horned.jpeg +0 -0
  158. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/moon.jpeg +0 -0
  159. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/slime.jpeg +0 -0
  160. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/star.jpeg +0 -0
  161. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
  162. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/projects/winged.jpeg +0 -0
  163. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/bear.jpeg +0 -0
  164. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/cat.jpeg +0 -0
  165. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/crown.jpeg +0 -0
  166. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
  167. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
  168. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
  169. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/deer.jpeg +0 -0
  170. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/drone.jpeg +0 -0
  171. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
  172. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/fox.jpeg +0 -0
  173. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
  174. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/horse.jpeg +0 -0
  175. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/lion.jpeg +0 -0
  176. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
  177. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/robot.jpeg +0 -0
  178. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
  179. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
  180. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/.gitkeep +0 -0
  181. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/announcement-modal.js +0 -0
  182. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/api.js +0 -0
  183. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/artifact-window.js +0 -0
  184. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/collage.js +0 -0
  185. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/components/icon-picker.js +0 -0
  186. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/components/list-card.js +0 -0
  187. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/components/type-tag.js +0 -0
  188. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/dead-key-suppressor.js +0 -0
  189. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/desktop-manager.js +0 -0
  190. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/icon-manager.js +0 -0
  191. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/notification-prefs.js +0 -0
  192. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/notifications-panel.js +0 -0
  193. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/safety-shared.js +0 -0
  194. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/safety-window.js +0 -0
  195. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/scratchpad.js +0 -0
  196. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/session-id.js +0 -0
  197. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
  198. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar/config-section.js +0 -0
  199. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar/machines-section.js +0 -0
  200. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar/projects-section.js +0 -0
  201. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar/safety-section.js +0 -0
  202. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
  203. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar/services-section.js +0 -0
  204. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/sidebar.js +0 -0
  205. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/terminal-font-prefs.js +0 -0
  206. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/tile-manager.js +0 -0
  207. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/toast.js +0 -0
  208. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/token-modal.js +0 -0
  209. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/utils/ansi.js +0 -0
  210. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/utils/auto-refresh.js +0 -0
  211. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/voice/autosend-prefs.js +0 -0
  212. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/voice/browser-stt.js +0 -0
  213. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/voice/browser-tts.js +0 -0
  214. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/voice/jargon.js +0 -0
  215. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/voice/prompt.js +0 -0
  216. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/static/js/winbox.bundle.min.js +0 -0
  217. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/stt/__init__.py +0 -0
  218. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/stt/base.py +0 -0
  219. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/stt/cloud.py +0 -0
  220. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/stt/engine.py +0 -0
  221. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/stt/local.py +0 -0
  222. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/stt/server_backend.py +0 -0
  223. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/stt/stt_server.py +0 -0
  224. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tasks.py +0 -0
  225. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templates/__init__.py +0 -0
  226. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templates/base.html +0 -0
  227. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templates/desktop.html +0 -0
  228. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templates/email_notification.html +0 -0
  229. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
  230. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templates/handoff/theme.css.j2 +0 -0
  231. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templates/mobile.html +0 -0
  232. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templates/tmux.conf +0 -0
  233. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/templating.py +0 -0
  234. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/aws.yaml +0 -0
  235. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/docker.yaml +0 -0
  236. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/gcp.yaml +0 -0
  237. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/gh.yaml +0 -0
  238. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/git.yaml +0 -0
  239. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/gws.yaml +0 -0
  240. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/kubectl.yaml +0 -0
  241. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/npm.yaml +0 -0
  242. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/terraform.yaml +0 -0
  243. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tooldefs/uv.yaml +0 -0
  244. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/__init__.py +0 -0
  245. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/audio.py +0 -0
  246. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/base.py +0 -0
  247. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/engines/__init__.py +0 -0
  248. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/engines/chatterbox.py +0 -0
  249. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/engines/kokoro.py +0 -0
  250. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/engines/qwen_base.py +0 -0
  251. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/engines/qwen_custom.py +0 -0
  252. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/engines/qwen_design.py +0 -0
  253. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/engines/zonos.py +0 -0
  254. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/local.py +0 -0
  255. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts/registry.py +0 -0
  256. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tts_server.py +0 -0
  257. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/tunnels.py +0 -0
  258. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/usage_limit.py +0 -0
  259. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/utils/__init__.py +0 -0
  260. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/utils/chunker.py +0 -0
  261. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/utils/file_io.py +0 -0
  262. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/utils/paths.py +0 -0
  263. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/utils/speech.py +0 -0
  264. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/utils/subprocess.py +0 -0
  265. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/validation.py +0 -0
  266. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/voiceclone.py +0 -0
  267. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/voices/darren.wav +0 -0
  268. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/voices/default.wav +0 -0
  269. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/voices/jessica.wav +0 -0
  270. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/voices/lisa.wav +0 -0
  271. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/voices/may.wav +0 -0
  272. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/worktree.py +0 -0
  273. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/agentwire/worktree_registry.py +0 -0
  274. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/decisions/obsidian-second-brain.md +0 -0
  275. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/logo.png +0 -0
  276. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/INDEX.md +0 -0
  277. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/architecture.md +0 -0
  278. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/communication/channels.md +0 -0
  279. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/communication/hammerspoon.md +0 -0
  280. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/communication/handoff.md +0 -0
  281. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/concepts.md +0 -0
  282. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/council.md +0 -0
  283. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/deployment/remote-access.md +0 -0
  284. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/deployment/remote-machines.md +0 -0
  285. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/glossary.md +0 -0
  286. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
  287. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/internals/damage-control.md +0 -0
  288. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/internals/portal.md +0 -0
  289. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/internals/shell-escaping.md +0 -0
  290. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/internals/troubleshooting.md +0 -0
  291. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/internals/window-collage.md +0 -0
  292. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/quickstart.md +0 -0
  293. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
  294. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
  295. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/security/secrets.md +0 -0
  296. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/services.md +0 -0
  297. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
  298. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/sessions/messaging.md +0 -0
  299. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/sessions/pi.md +0 -0
  300. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/sessions/prompt-routing.md +0 -0
  301. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/sessions/window-sizing.md +0 -0
  302. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/sessions/worktree-sessions.md +0 -0
  303. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/usage-limit-recovery.md +0 -0
  304. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/voice/shim-contract.md +0 -0
  305. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/voice/stt-cloud.md +0 -0
  306. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/voice/stt-self-hosted.md +0 -0
  307. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/docs/wiki/voice/tts-self-hosted.md +0 -0
  308. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/pyproject.toml +0 -0
  309. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/requirements-tts.txt +0 -0
  310. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/conftest.py +0 -0
  311. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/e2e/test_portal_ui.py +0 -0
  312. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/fixtures/sample_agentwire.yml +0 -0
  313. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/fixtures/sample_config.yaml +0 -0
  314. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/fixtures/sample_scheduler.yaml +0 -0
  315. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/integration/test_council_portal.py +0 -0
  316. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/integration/test_scheduler_board.py +0 -0
  317. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/integration/test_server_websockets.py +0 -0
  318. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/integration/test_worktree_cmd.py +0 -0
  319. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_announcements.py +0 -0
  320. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_build_agent_command.py +0 -0
  321. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_channels.py +0 -0
  322. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_cli_commands.py +0 -0
  323. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_cli_output.py +0 -0
  324. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_cli_safety.py +0 -0
  325. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_config.py +0 -0
  326. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_council_cli.py +0 -0
  327. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_council_inbox.py +0 -0
  328. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_council_state.py +0 -0
  329. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_council_view.py +0 -0
  330. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_damage_control_hooks.py +0 -0
  331. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_damage_control_sync.py +0 -0
  332. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_file_io.py +0 -0
  333. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_handoff_git_state.py +0 -0
  334. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_handoff_instructions.py +0 -0
  335. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_handoff_parser.py +0 -0
  336. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_handoff_renderer.py +0 -0
  337. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_history.py +0 -0
  338. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_hooks_install.py +0 -0
  339. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_idle_handler.py +0 -0
  340. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_inbox.py +0 -0
  341. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_locking.py +0 -0
  342. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_mcp_server.py +0 -0
  343. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_mcp_tools_args.py +0 -0
  344. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_msg_cli.py +0 -0
  345. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_portal_api.py +0 -0
  346. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_project_config.py +0 -0
  347. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_prompt_router.py +0 -0
  348. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_roles.py +0 -0
  349. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_safety_disabled_rules.py +0 -0
  350. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_safety_escape_hatch.py +0 -0
  351. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_safety_kill_switch.py +0 -0
  352. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_scheduler.py +0 -0
  353. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_scheduler_parsing.py +0 -0
  354. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_scratchpad.py +0 -0
  355. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_security.py +0 -0
  356. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_server_async.py +0 -0
  357. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_server_pure.py +0 -0
  358. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_services.py +0 -0
  359. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_session_ready.py +0 -0
  360. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_speech_tags.py +0 -0
  361. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_ssh.py +0 -0
  362. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_stt_backend.py +0 -0
  363. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_stt_cloud.py +0 -0
  364. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_stt_engine.py +0 -0
  365. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_task_cli.py +0 -0
  366. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_tasks.py +0 -0
  367. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_templating.py +0 -0
  368. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_terminal_resize.py +0 -0
  369. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_tmux_template.py +0 -0
  370. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_tts_engine_resolution.py +0 -0
  371. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_tts_local.py +0 -0
  372. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_usage_limit.py +0 -0
  373. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_validation.py +0 -0
  374. {agentwire_dev-1.40.0 → agentwire_dev-1.41.0}/tests/unit/test_worktree.py +0 -0
  375. {agentwire_dev-1.40.0 → agentwire_dev-1.41.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.41.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.41.0"
@@ -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
 
@@ -32,6 +32,23 @@ The full prompt text is also on disk — the `[COUNCIL PROMPT #N]` message gives
32
32
  the exact path (under `~/.agentwire/council/<council>/prompts/<NNNN>/prompt.md`)
33
33
  if the message was truncated.
34
34
 
35
+ ## Memory — consult past deliberations
36
+
37
+ Earlier rounds and earlier sittings are on disk; a take grounded in what this
38
+ council already concluded beats one argued from scratch. Before answering a
39
+ question that echoes past work, read the history:
40
+
41
+ - **This sitting's earlier rounds** — `~/.agentwire/council/<council>/prompts/`
42
+ holds every round (`NNNN/prompt.md` + `replies/<soul>.*.md`). Skim them so you
43
+ don't re-litigate a settled point or contradict your own prior take.
44
+ - **Other councils' threads (incl. archived/dismissed)** — sibling directories
45
+ under `~/.agentwire/council/<other>/prompts/` are durable thread artifacts that
46
+ outlive their sessions. When a decision was made elsewhere, cite it.
47
+
48
+ Keep it cheap: a quick `ls`/read of the relevant `prompts/` dir, not an
49
+ exhaustive trawl. When a past round changes your answer, say so in your take
50
+ (e.g. "consistent with round 2's call to …") so the orchestrator can attribute it.
51
+
35
52
  ## Rules
36
53
 
37
54
  - **Passing is expected and free.** If your lens has nothing real to add, pass.
@@ -308,6 +308,7 @@ class AgentWireServer:
308
308
  self.app.router.add_get("/api/scheduler/output", self.api_scheduler_session_output)
309
309
  # Council seating board: live sittings + per-prompt snapshot
310
310
  self.app.router.add_get("/api/council/sittings", self.api_council_sittings)
311
+ self.app.router.add_get("/api/council/archive", self.api_council_archive)
311
312
  self.app.router.add_get("/api/council/live", self.api_council_live)
312
313
  self.app.router.add_get("/api/council/status", self.api_council_status)
313
314
  self.app.router.add_post("/api/council/start", self.api_council_start)
@@ -5007,6 +5008,48 @@ projects:
5007
5008
  except Exception as e:
5008
5009
  return web.json_response({"error": str(e)}, status=500)
5009
5010
 
5011
+ async def api_council_archive(self, request: web.Request) -> web.Response:
5012
+ """GET /api/council/archive - Dismissed threads, newest first.
5013
+
5014
+ Each entry: ``{name, rounds, last_prompt_text, dismissed_at, cwd}`` —
5015
+ enough for the sidebar to list past deliberations; the board reads the
5016
+ full thread via ``/api/council/live?sitting=<name>``.
5017
+ """
5018
+ try:
5019
+ from .council import state as council_state
5020
+ from .council import inbox as council_inbox
5021
+ from .council import view as council_view
5022
+
5023
+ out = []
5024
+ for name in council_state.list_archive():
5025
+ ids = council_view.available_prompt_ids(name)
5026
+ last_text = ""
5027
+ if ids:
5028
+ last_text = self._read_text_safe(
5029
+ council_inbox.prompt_dir(name, ids[-1]) / "prompt.md"
5030
+ )
5031
+ rec = council_state.read_archive_dict(name) or {}
5032
+ out.append(
5033
+ {
5034
+ "name": name,
5035
+ "rounds": len(ids),
5036
+ "last_prompt_text": last_text,
5037
+ "dismissed_at": rec.get("dismissed_at", ""),
5038
+ "cwd": rec.get("cwd", ""),
5039
+ }
5040
+ )
5041
+ out.sort(key=lambda e: e.get("dismissed_at", ""), reverse=True)
5042
+ return web.json_response({"archive": out})
5043
+ except Exception as e:
5044
+ return web.json_response({"error": str(e)}, status=500)
5045
+
5046
+ @staticmethod
5047
+ def _read_text_safe(path) -> str:
5048
+ try:
5049
+ return path.read_text()
5050
+ except OSError:
5051
+ return ""
5052
+
5010
5053
  async def api_council_live(self, request: web.Request) -> web.Response:
5011
5054
  """GET /api/council/live - Board snapshot for a sitting (mirrors
5012
5055
  /api/scheduler/live).
@@ -5033,20 +5076,20 @@ projects:
5033
5076
  {"running": False, "sittings": live}, status=409
5034
5077
  )
5035
5078
 
5036
- sitting = council_state.read_sitting(name)
5037
- if sitting is None:
5038
- return web.json_response(
5039
- {"running": False, "sittings": council_state.list_sittings()},
5040
- status=404,
5041
- )
5042
-
5079
+ # A dismissed thread has no live sitting.json but is still a fully
5080
+ # readable artifact (archive.json + prompts/). Only 404 when there
5081
+ # is genuinely nothing on disk.
5082
+ live = council_state.read_sitting(name)
5043
5083
  prompt_id_raw = request.query.get("prompt_id")
5044
5084
  prompt_id = int(prompt_id_raw) if prompt_id_raw else None
5045
- dead = await self._council_dead_souls(sitting)
5085
+ dead = await self._council_dead_souls(live) if live else set()
5046
5086
  snap = council_view.snapshot(name, prompt_id, dead_souls=dead)
5047
5087
  if snap is None:
5048
- return web.json_response({"running": False}, status=404)
5049
- snap["running"] = True
5088
+ return web.json_response(
5089
+ {"running": False, "sittings": council_state.list_sittings()},
5090
+ status=404,
5091
+ )
5092
+ snap["running"] = live is not None
5050
5093
  snap["sittings"] = council_state.list_sittings()
5051
5094
  return web.json_response(snap)
5052
5095
  except Exception as e:
@@ -141,6 +141,23 @@ body {
141
141
  position: relative;
142
142
  overflow: hidden;
143
143
  background: var(--background);
144
+ /* Tablets: keep vertical pan native (terminal scroll) but hand horizontal
145
+ drags to JS for swipe-to-cycle instead of browser back/forward nav. */
146
+ touch-action: pan-y;
147
+ }
148
+
149
+ /* Window content must also opt into pan-y. WebKit/iPadOS resolves touch-action
150
+ on the directly-touched element rather than reliably intersecting with the
151
+ ancestor, so an xterm terminal / Monitor <pre> left at the default `auto`
152
+ lets the browser claim horizontal swipes — that's why swipe-to-cycle only
153
+ fired once the terminal was focused. Forcing pan-y here hands every
154
+ horizontal drag over a window to JS regardless of focus. */
155
+ .wb-body,
156
+ .xterm,
157
+ .xterm-viewport,
158
+ .xterm-screen,
159
+ .session-output {
160
+ touch-action: pan-y;
144
161
  }
145
162
 
146
163
  .desktop-wallpaper {
@@ -1608,6 +1625,13 @@ body {
1608
1625
  border-color: var(--accent);
1609
1626
  }
1610
1627
 
1628
+ .cmdk-council-note {
1629
+ margin: 8px 2px 0;
1630
+ font-size: 11px;
1631
+ line-height: 1.4;
1632
+ color: var(--text-dim, var(--muted-foreground, #94a3b8));
1633
+ }
1634
+
1611
1635
  .cmdk-idea-mic {
1612
1636
  position: absolute;
1613
1637
  top: 6px;
@@ -5961,4 +5985,19 @@ body.sidebar-pinned .sidebar-tab {
5961
5985
  }
5962
5986
  .council-section-item:hover { background: var(--hover); }
5963
5987
  .council-section-name { font-weight: 600; font-size: 13px; }
5964
- .council-section-count { font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
5988
+ .council-section-count { font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
5989
+ .council-section-item--open { border-style: dashed; }
5990
+ .council-section-subhead {
5991
+ margin: 10px 2px 2px; font-size: 10px; font-weight: 700; letter-spacing: 0.08em;
5992
+ text-transform: uppercase; color: var(--text-muted);
5993
+ }
5994
+ .council-section-item--archived { flex-wrap: wrap; opacity: 0.85; }
5995
+ .council-section-item--archived:hover { opacity: 1; }
5996
+ .council-section-snip {
5997
+ flex-basis: 100%; font-size: 11px; color: var(--text-muted); font-weight: 400;
5998
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
5999
+ }
6000
+ .council-archived-tag {
6001
+ font-size: 9px; font-weight: 700; letter-spacing: 0.1em; padding: 2px 6px; border-radius: 4px;
6002
+ background: rgba(255,255,255,0.06); color: var(--text-muted); border: 1px solid var(--chrome-border);
6003
+ }
@@ -44,6 +44,9 @@ html, body {
44
44
  max-width: 560px;
45
45
  margin: 0 auto;
46
46
  padding: env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left);
47
+ /* Vertical scrolling stays native; horizontal drags are handed to JS for
48
+ swipe-to-cycle (setupSwipeCycling) instead of becoming scroll/back-nav. */
49
+ touch-action: pan-y;
47
50
  }
48
51
 
49
52
  /* Header */
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Command Palette — unified Cmd/Ctrl+K launcher for quick create/open actions.
3
3
  *
4
- * Cmd/Ctrl+K opens straight into the idea-first capture (Esc reaches the root
5
- * menu). Root view actions:
4
+ * Cmd/Ctrl+K opens the root list with "Ask council" selected by default (Esc
5
+ * closes). Root view actions:
6
+ * - Ask council → open the council board to seat/ask a question
6
7
  * - New idea → idea (typed or dictated) + derived name → create project
7
8
  * → spawn session → idea delivered as the agent's first
8
9
  * message → open (you watch it land live)
@@ -16,7 +17,7 @@
16
17
 
17
18
  import { apiFetch } from './api.js';
18
19
  import { normalizeMachine, sameMachine } from './session-id.js';
19
- import { isService } from './service-classification.js';
20
+ import { isService, isCouncil } from './service-classification.js';
20
21
  import * as browserStt from './voice/browser-stt.js';
21
22
 
22
23
  const PILL_TYPES = ['feat', 'fix', 'chore', 'refactor', 'docs'];
@@ -33,6 +34,7 @@ let currentView = 'root'; // 'root' | 'new-idea' | 'new-session' | 'workt
33
34
  let prefillProject = '';
34
35
 
35
36
  const COMMANDS = [
37
+ { id: 'ask-council', icon: '🏛', label: 'Ask council', keywords: 'council ask question deliberate lenses brainstorm advice decide soul', run: () => setView('ask-council') },
36
38
  { id: 'new-idea', icon: '💡', label: 'New idea', keywords: 'idea create new project repo clone git init build start', run: () => setView('new-idea') },
37
39
  { id: 'new-session', icon: '▶', label: 'New session', keywords: 'create new session start spawn run project', run: () => setView('new-session') },
38
40
  { id: 'worktree', icon: '⎇', label: 'New worktree', keywords: 'worktree branch quicktask task feat fix base', run: () => setView('worktree') },
@@ -123,7 +125,7 @@ async function loadSessions() {
123
125
  if (!names.has(s.name)) out.push(s);
124
126
  }
125
127
  } catch (e) { /* ignore */ }
126
- sessionsCache = out.filter((s) => !isService(s.name || ''));
128
+ sessionsCache = out.filter((s) => !isService(s.name || '') && !isCouncil(s.name || ''));
127
129
  return sessionsCache;
128
130
  }
129
131
 
@@ -571,6 +573,87 @@ function bindWorktreeForm(form) {
571
573
  });
572
574
  }
573
575
 
576
+ // ---------------------------------------------------------------------------
577
+ // Ask council — question-first front door (seat-if-needed → ask → watch board)
578
+ // ---------------------------------------------------------------------------
579
+
580
+ function askCouncilFormHtml() {
581
+ return `
582
+ <div class="quicktask-error" data-error hidden></div>
583
+ <div class="quicktask-progress" data-progress hidden></div>
584
+ <form class="quicktask-form" data-form="ask-council">
585
+ <label class="quicktask-field">
586
+ <span class="quicktask-label">Ask the council</span>
587
+ <textarea name="prompt" class="cmdk-idea-input" rows="4"
588
+ placeholder="A question or decision to put to the lenses…"
589
+ autocomplete="off" spellcheck="false"></textarea>
590
+ </label>
591
+ <p class="cmdk-council-note">One model, six lenses — structured self-critique, not a panel of experts. Seats a council if none is live (~6 sessions).</p>
592
+ <div class="quicktask-footer">
593
+ <button type="button" class="quicktask-btn-cancel" data-action="back">Back</button>
594
+ <button type="submit" class="quicktask-btn-submit">Convene &amp; ask</button>
595
+ </div>
596
+ </form>`;
597
+ }
598
+
599
+ function bindAskCouncilForm(form) {
600
+ const input = form.querySelector('textarea[name="prompt"]');
601
+ // Enter submits; Shift+Enter for a newline. Escape must bubble to the
602
+ // palette's overlay handler (goBack), so don't swallow it.
603
+ input?.addEventListener('keydown', (e) => {
604
+ if (e.key === 'Escape') return;
605
+ if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); form.requestSubmit(); }
606
+ e.stopPropagation(); // keep other keystrokes off global shortcuts
607
+ });
608
+ form.addEventListener('submit', async (e) => {
609
+ e.preventDefault();
610
+ const prompt = input.value.trim();
611
+ if (!prompt) { input.focus(); return; }
612
+ await submitAskCouncil(prompt);
613
+ });
614
+ }
615
+
616
+ /** Resolve a sitting (seat one if none live), fan the prompt out, open the board.
617
+ * Fire-and-forget: we don't wait for the takes — the board fills them live. */
618
+ async function submitAskCouncil(prompt) {
619
+ showProgress('Convening the council…');
620
+ try {
621
+ let sitting = null;
622
+ const sres = await apiFetch('/api/council/sittings');
623
+ const live = (sres.ok ? (await sres.json()).sittings : []) || [];
624
+ if (live.length === 1) {
625
+ sitting = live[0];
626
+ } else if (live.length === 0) {
627
+ showProgress('Seating the council…');
628
+ const st = await apiFetch('/api/council/start', { method: 'POST' });
629
+ const sd = await st.json().catch(() => ({}));
630
+ if (!st.ok) { showError(sd.error || 'Could not seat the council.'); return; }
631
+ sitting = sd.council || null;
632
+ } else {
633
+ // Several live — let the user pick which chamber in the board.
634
+ closeCommandPalette();
635
+ const { openCouncilWindow } = await import('./desktop.js');
636
+ openCouncilWindow(null);
637
+ return;
638
+ }
639
+ showProgress('Asking the council…');
640
+ const body = { prompt };
641
+ if (sitting) body.sitting = sitting;
642
+ const ares = await apiFetch('/api/council/ask', {
643
+ method: 'POST',
644
+ headers: { 'Content-Type': 'application/json' },
645
+ body: JSON.stringify(body),
646
+ });
647
+ const adata = await ares.json().catch(() => ({}));
648
+ if (!ares.ok) { showError(adata.error || 'Could not ask the council.'); return; }
649
+ closeCommandPalette();
650
+ const { openCouncilWindow } = await import('./desktop.js');
651
+ openCouncilWindow(sitting || adata.council || null);
652
+ } catch (err) {
653
+ showError(err?.message || 'Network error');
654
+ }
655
+ }
656
+
574
657
  // ---------------------------------------------------------------------------
575
658
  // List views (root + open-session)
576
659
  // ---------------------------------------------------------------------------
@@ -650,10 +733,14 @@ function renderView() {
650
733
  if (currentView === 'new-idea') {
651
734
  footer.textContent = '↵ create & run · ⇧↵ newline · esc back';
652
735
  body.innerHTML = newIdeaFormHtml();
736
+ } else if (currentView === 'ask-council') {
737
+ footer.textContent = '↵ convene & ask · ⇧↵ newline · esc back';
738
+ body.innerHTML = askCouncilFormHtml();
653
739
  } else if (currentView === 'new-session') body.innerHTML = newSessionFormHtml();
654
740
  else if (currentView === 'worktree') body.innerHTML = worktreeFormHtml();
655
741
  const form = body.querySelector('.quicktask-form');
656
742
  if (currentView === 'new-idea') bindNewIdeaForm(form);
743
+ else if (currentView === 'ask-council') bindAskCouncilForm(form);
657
744
  else if (currentView === 'new-session') bindNewSessionForm(form);
658
745
  else if (currentView === 'worktree') bindWorktreeForm(form);
659
746
  }
@@ -44,6 +44,8 @@ const state = {
44
44
  roundTexts: {}, // prompt_id -> question text, cached as rounds are visited
45
45
  liveness: {}, // soul -> bool (lens session alive — from /status)
46
46
  seated: false, // is a sitting present at all
47
+ archived: false, // viewing a dismissed thread (no live sessions)
48
+ running: true, // a live sitting backs the view
47
49
  busy: false, // a seat/ask/dismiss POST is in flight
48
50
  };
49
51
 
@@ -157,6 +159,8 @@ async function loadSnapshot(sitting, promptId) {
157
159
  function applySnapshot(snap) {
158
160
  state.sitting = snap.sitting;
159
161
  state.seated = true;
162
+ state.archived = !!snap.archived; // dismissed thread, no live sessions
163
+ state.running = snap.running !== false; // live sitting present
160
164
  state.promptId = snap.prompt_id;
161
165
  state.promptIds = snap.prompt_ids || [];
162
166
  state.latestPromptId = state.promptIds.length
@@ -295,6 +299,15 @@ function seatControlHtml() {
295
299
  ${state.busy ? 'Seating…' : 'Seat the council'}
296
300
  </button>`;
297
301
  }
302
+ if (state.archived) {
303
+ // Dismissed thread: read-only, no live sessions to dismiss. Re-asking
304
+ // (from the ask row) re-seats the same roster under the same name.
305
+ return `
306
+ <span class="council-seat-summary council-seat-summary--archived">
307
+ <span class="council-counter">${esc(counterText())}</span>
308
+ <span class="council-archived-tag">ARCHIVED</span>
309
+ </span>`;
310
+ }
298
311
  return `
299
312
  <span class="council-seat-summary"><span class="council-seat-led"></span><span class="council-counter">${esc(counterText())}</span></span>
300
313
  <button class="council-btn council-btn--ghost" data-action="dismiss" ${state.busy ? 'disabled' : ''}>Dismiss</button>`;
@@ -355,12 +368,18 @@ function roundsCrumbHtml() {
355
368
  /** The header ASK row — re-prompt the seated sitting; compact input + button. */
356
369
  function askHtml() {
357
370
  if (!state.seated || !state.sitting) return '';
371
+ const placeholder = state.archived
372
+ ? 'Re-ask this thread — re-seats the same lenses…'
373
+ : 'Ask the council, or add context…';
374
+ const label = state.busy
375
+ ? (state.archived ? 'Re-seating…' : 'Asking…')
376
+ : (state.archived ? 'Re-seat &amp; ask →' : 'Ask the council →');
358
377
  return `
359
378
  <div class="council-ask">
360
379
  <div class="council-ask-row">
361
- <textarea class="council-ask-input" rows="1" placeholder="Ask the council, or add context…" ${state.busy ? 'disabled' : ''}></textarea>
380
+ <textarea class="council-ask-input" rows="1" placeholder="${esc(placeholder)}" ${state.busy ? 'disabled' : ''}></textarea>
362
381
  <button class="council-btn council-btn--primary council-btn--compact" data-action="ask" ${state.busy ? 'disabled' : ''}>
363
- ${state.busy ? 'Asking…' : 'Ask the council →'}
382
+ ${label}
364
383
  </button>
365
384
  </div>
366
385
  <div class="council-ask-err" data-slot="ask-err"></div>
@@ -651,10 +670,33 @@ async function askCouncil(input) {
651
670
  if (!prompt) { input.focus(); return; }
652
671
  state.busy = true;
653
672
  const btn = container?.querySelector('[data-action="ask"]');
654
- if (btn) { btn.disabled = true; btn.textContent = 'Asking…'; }
673
+ const reseating = state.archived || !state.running;
674
+ if (btn) { btn.disabled = true; btn.textContent = reseating ? 'Re-seating…' : 'Asking…'; }
655
675
  input.disabled = true;
656
676
  setAskError('');
657
677
  try {
678
+ // Archived thread → re-seat the same roster under the same name first,
679
+ // so the fan-out has live lens sessions to land in.
680
+ if (reseating) {
681
+ const startBody = { sitting: state.sitting };
682
+ if (state.roster.length) startBody.roster = state.roster.join(',');
683
+ const sres = await apiFetch('/api/council/start', {
684
+ method: 'POST',
685
+ headers: { 'Content-Type': 'application/json' },
686
+ body: JSON.stringify(startBody),
687
+ });
688
+ const sdata = await sres.json().catch(() => ({}));
689
+ if (!sres.ok) {
690
+ state.busy = false;
691
+ if (btn) { btn.disabled = false; }
692
+ input.disabled = false;
693
+ setAskError(sdata.error || 'Could not re-seat the council.');
694
+ return;
695
+ }
696
+ state.archived = false;
697
+ state.running = true;
698
+ if (btn) btn.textContent = 'Asking…';
699
+ }
658
700
  const res = await apiFetch('/api/council/ask', {
659
701
  method: 'POST',
660
702
  headers: { 'Content-Type': 'application/json' },