agentwire-dev 1.65.1__tar.gz → 1.65.2__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 (509) hide show
  1. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/PKG-INFO +1 -1
  2. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/__init__.py +1 -1
  3. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/desktop.py +17 -1
  4. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/session_cli.py +23 -3
  5. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/desktop.js +19 -1
  6. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/notifications-panel.js +12 -3
  7. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/worktree.py +33 -0
  8. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_worktree_cmd.py +32 -0
  9. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_mcp_tools_args.py +29 -0
  10. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_portal_api.py +69 -3
  11. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_worktree.py +43 -0
  12. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.agentwire.yml.example +0 -0
  13. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.claude/commands/handoff.md +0 -0
  14. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.claude/skills/wiki/SKILL.md +0 -0
  15. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/FUNDING.yml +0 -0
  16. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  17. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  18. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/ISSUE_TEMPLATE/question.md +0 -0
  19. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  20. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/workflows/pytest.yml +0 -0
  21. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/workflows/ruff.yml +0 -0
  22. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/workflows/security.yml +0 -0
  23. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.github/workflows/tts-smoke.yml +0 -0
  24. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/.gitignore +0 -0
  25. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/AGENTS.md +0 -0
  26. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/CODE_OF_CONDUCT.md +0 -0
  27. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/CONTRIBUTING.md +0 -0
  28. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/Dockerfile.local +0 -0
  29. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/LICENSE +0 -0
  30. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/README.md +0 -0
  31. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/RELEASING.md +0 -0
  32. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/SECURITY.md +0 -0
  33. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/SPONSORS.md +0 -0
  34. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/__main__.py +0 -0
  35. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/agents/__init__.py +0 -0
  36. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/agents/base.py +0 -0
  37. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/agents/tmux.py +0 -0
  38. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/cached_status.py +0 -0
  39. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/__init__.py +0 -0
  40. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/base.py +0 -0
  41. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/email.py +0 -0
  42. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/push.py +0 -0
  43. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels/quo.py +0 -0
  44. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/channels_cli.py +0 -0
  45. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/chrome_tabs.py +0 -0
  46. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/completion.py +0 -0
  47. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/config.py +0 -0
  48. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/config_cli.py +0 -0
  49. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/core.py +0 -0
  50. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/__init__.py +0 -0
  51. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/cli.py +0 -0
  52. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/inbox.py +0 -0
  53. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/minutes.py +0 -0
  54. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/state.py +0 -0
  55. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/council/view.py +0 -0
  56. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/devices.py +0 -0
  57. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/diff_cli.py +0 -0
  58. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/doctor_cli.py +0 -0
  59. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/doctor_voice.py +0 -0
  60. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/ensure_cli.py +0 -0
  61. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/fetch.py +0 -0
  62. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/__init__.py +0 -0
  63. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/git_state.py +0 -0
  64. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/instructions.py +0 -0
  65. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/parser.py +0 -0
  66. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/renderer.py +0 -0
  67. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff/schema.py +0 -0
  68. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/handoff_cli.py +0 -0
  69. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/history.py +0 -0
  70. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/history_cli.py +0 -0
  71. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/__init__.py +0 -0
  72. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/agentwire-permission.sh +0 -0
  73. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/__init__.py +0 -0
  74. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/audit_logger.py +0 -0
  75. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/bash-tool-damage-control.py +0 -0
  76. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/edit-tool-damage-control.py +0 -0
  77. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/mcp-tool-damage-control.py +0 -0
  78. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/read-tool-damage-control.py +0 -0
  79. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
  80. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
  81. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
  82. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
  83. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/control-plane.yaml +0 -0
  84. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
  85. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
  86. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
  87. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
  88. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
  89. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
  90. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
  91. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/outbound.yaml +0 -0
  92. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/publish.yaml +0 -0
  93. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
  94. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/damage-control/write-tool-damage-control.py +0 -0
  95. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/idle-handler.sh +0 -0
  96. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks/queue-processor.sh +0 -0
  97. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/hooks_cli.py +0 -0
  98. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/inbox.py +0 -0
  99. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/limits_cli.py +0 -0
  100. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/listen.py +0 -0
  101. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/locking.py +0 -0
  102. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/machine_cli.py +0 -0
  103. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_channels.py +0 -0
  104. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_chrome.py +0 -0
  105. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_cli.py +0 -0
  106. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_core.py +0 -0
  107. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_council.py +0 -0
  108. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_desktop.py +0 -0
  109. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_handoff.py +0 -0
  110. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_history.py +0 -0
  111. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_listen.py +0 -0
  112. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_lock.py +0 -0
  113. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_machine.py +0 -0
  114. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_msg.py +0 -0
  115. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_notify.py +0 -0
  116. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_pane.py +0 -0
  117. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_projects.py +0 -0
  118. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_scheduler.py +0 -0
  119. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_scratchpad.py +0 -0
  120. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_server.py +0 -0
  121. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_services.py +0 -0
  122. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_session.py +0 -0
  123. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_status.py +0 -0
  124. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_task.py +0 -0
  125. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_tunnels.py +0 -0
  126. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_voice.py +0 -0
  127. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_wiki.py +0 -0
  128. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/mcp_worktree.py +0 -0
  129. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/msg_cli.py +0 -0
  130. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/network.py +0 -0
  131. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/notify_cli.py +0 -0
  132. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/onboarding.py +0 -0
  133. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/palette_cli.py +0 -0
  134. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/pane_cli.py +0 -0
  135. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/pane_manager.py +0 -0
  136. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/portal_cli.py +0 -0
  137. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/project_config.py +0 -0
  138. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/projects.py +0 -0
  139. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/prompt_router.py +0 -0
  140. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/prompts_cli.py +0 -0
  141. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/push_cli.py +0 -0
  142. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/push_store.py +0 -0
  143. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/repo_cli.py +0 -0
  144. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/research.py +0 -0
  145. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/__init__.py +0 -0
  146. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/agentwire.md +0 -0
  147. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/anchor.md +0 -0
  148. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/chatbot.md +0 -0
  149. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/contributor.md +0 -0
  150. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/correspondent.md +0 -0
  151. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-brain.md +0 -0
  152. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-conscience.md +0 -0
  153. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-critic.md +0 -0
  154. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-devils-advocate.md +0 -0
  155. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-gut.md +0 -0
  156. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-historian.md +0 -0
  157. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-member.md +0 -0
  158. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/council-orchestrator.md +0 -0
  159. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/init.md +0 -0
  160. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/notifications.md +0 -0
  161. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/orchestrator.md +0 -0
  162. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/reviewer-worktree.md +0 -0
  163. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/reviewer.md +0 -0
  164. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/soul.md +0 -0
  165. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/task-runner.md +0 -0
  166. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/voice.md +0 -0
  167. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/worker-worktree.md +0 -0
  168. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles/worker.md +0 -0
  169. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/roles_cli.py +0 -0
  170. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/__init__.py +0 -0
  171. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/artifacts.py +0 -0
  172. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/config.py +0 -0
  173. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/council.py +0 -0
  174. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/history.py +0 -0
  175. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/machines.py +0 -0
  176. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/notify.py +0 -0
  177. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/palette.py +0 -0
  178. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/permission.py +0 -0
  179. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/projects.py +0 -0
  180. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/push.py +0 -0
  181. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/safety.py +0 -0
  182. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/scheduler.py +0 -0
  183. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/scratchpad.py +0 -0
  184. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/sessions.py +0 -0
  185. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/sessions_admin.py +0 -0
  186. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/routes/voice.py +0 -0
  187. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/safety/__init__.py +0 -0
  188. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/safety/_core.py +0 -0
  189. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/safety_cli.py +0 -0
  190. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/safety_commands.py +0 -0
  191. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/__init__.py +0 -0
  192. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/dispatch.py +0 -0
  193. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/gates.py +0 -0
  194. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/loop.py +0 -0
  195. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/models.py +0 -0
  196. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/report.py +0 -0
  197. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/schedule.py +0 -0
  198. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/state.py +0 -0
  199. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler/zombie.py +0 -0
  200. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scheduler_cli.py +0 -0
  201. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/scratchpad.py +0 -0
  202. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/security.py +0 -0
  203. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/send_cli.py +0 -0
  204. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/server.py +0 -0
  205. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/services.py +0 -0
  206. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/session_context.py +0 -0
  207. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/session_ready.py +0 -0
  208. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/ssh.py +0 -0
  209. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
  210. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
  211. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
  212. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
  213. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
  214. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/announcements.json +0 -0
  215. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/apple-touch-icon.png +0 -0
  216. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/css/desktop.css +0 -0
  217. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/css/mobile.css +0 -0
  218. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/favicon-32.png +0 -0
  219. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/favicon-64.png +0 -0
  220. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/bear.webp +0 -0
  221. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/cat.webp +0 -0
  222. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/crown.webp +0 -0
  223. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/custom/agentwire-portal.webp +0 -0
  224. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/custom/agentwire-tts.webp +0 -0
  225. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/custom/agentwire.webp +0 -0
  226. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/deer.webp +0 -0
  227. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/drone.webp +0 -0
  228. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/eagle.webp +0 -0
  229. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/fox.webp +0 -0
  230. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/hawk.webp +0 -0
  231. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/horse.webp +0 -0
  232. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/lion.webp +0 -0
  233. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/rabbit.webp +0 -0
  234. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/robot.webp +0 -0
  235. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/tiger.webp +0 -0
  236. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/icons/sessions/wolf.webp +0 -0
  237. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/img/icon-192.png +0 -0
  238. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/img/icon-512.png +0 -0
  239. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/.gitkeep +0 -0
  240. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/announcement-modal.js +0 -0
  241. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/api.js +0 -0
  242. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/artifact-window.js +0 -0
  243. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/card-terminal.js +0 -0
  244. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/collage.js +0 -0
  245. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/command-palette.js +0 -0
  246. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/council-window.js +0 -0
  247. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/dead-key-suppressor.js +0 -0
  248. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/desktop-manager.js +0 -0
  249. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/help-modal.js +0 -0
  250. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/icon-manager.js +0 -0
  251. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/lineage.js +0 -0
  252. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/mobile.js +0 -0
  253. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/notification-prefs.js +0 -0
  254. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/ptt.js +0 -0
  255. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/push-client.js +0 -0
  256. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/review-window.js +0 -0
  257. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/safety-shared.js +0 -0
  258. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/safety-window.js +0 -0
  259. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/scratchpad.js +0 -0
  260. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/service-classification.js +0 -0
  261. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-hud-controller.js +0 -0
  262. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-hud-notices.js +0 -0
  263. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-hud-spawn.js +0 -0
  264. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-hud.js +0 -0
  265. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-id.js +0 -0
  266. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/session-window.js +0 -0
  267. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/shortcuts.js +0 -0
  268. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
  269. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/config-section.js +0 -0
  270. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/council-section.js +0 -0
  271. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/machines-section.js +0 -0
  272. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/projects-section.js +0 -0
  273. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/safety-section.js +0 -0
  274. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/scheduler-section.js +0 -0
  275. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/services-section.js +0 -0
  276. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar/sessions-section.js +0 -0
  277. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/sidebar.js +0 -0
  278. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/spawn-ghost.js +0 -0
  279. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/terminal-font-prefs.js +0 -0
  280. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/terminal-pane.js +0 -0
  281. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/tile-manager.js +0 -0
  282. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/toast.js +0 -0
  283. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/token-modal.js +0 -0
  284. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/topology-render.js +0 -0
  285. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/utils/ansi.js +0 -0
  286. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/utils/rich-text.js +0 -0
  287. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/utils/swipe.js +0 -0
  288. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/autosend-prefs.js +0 -0
  289. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/browser-stt.js +0 -0
  290. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/browser-tts.js +0 -0
  291. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/jargon.js +0 -0
  292. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/voice/prompt.js +0 -0
  293. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/winbox.bundle.min.js +0 -0
  294. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/js/workspace-window.js +0 -0
  295. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/manifest.webmanifest +0 -0
  296. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/service-worker.js +0 -0
  297. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/static/topology-harness.html +0 -0
  298. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/__init__.py +0 -0
  299. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/base.py +0 -0
  300. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/cloud.py +0 -0
  301. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/engine.py +0 -0
  302. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/local.py +0 -0
  303. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/server_backend.py +0 -0
  304. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/stt/stt_server.py +0 -0
  305. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/system_cli.py +0 -0
  306. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tabs_cli.py +0 -0
  307. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tasks.py +0 -0
  308. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tasks_cli.py +0 -0
  309. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/__init__.py +0 -0
  310. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/base.html +0 -0
  311. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/council/minutes.html.j2 +0 -0
  312. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/desktop.html +0 -0
  313. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/email_notification.html +0 -0
  314. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
  315. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/handoff/theme.css.j2 +0 -0
  316. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/mobile.html +0 -0
  317. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/pair.html +0 -0
  318. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templates/tmux.conf +0 -0
  319. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/templating.py +0 -0
  320. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/aws.yaml +0 -0
  321. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/docker.yaml +0 -0
  322. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/gcp.yaml +0 -0
  323. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/gh.yaml +0 -0
  324. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/git.yaml +0 -0
  325. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/gws.yaml +0 -0
  326. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/kubectl.yaml +0 -0
  327. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/npm.yaml +0 -0
  328. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/terraform.yaml +0 -0
  329. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tooldefs/uv.yaml +0 -0
  330. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/__init__.py +0 -0
  331. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/audio.py +0 -0
  332. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/base.py +0 -0
  333. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/engines/__init__.py +0 -0
  334. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/engines/chatterbox.py +0 -0
  335. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/engines/kokoro.py +0 -0
  336. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/engines/zonos.py +0 -0
  337. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/kokoro_server.py +0 -0
  338. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/local.py +0 -0
  339. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts/registry.py +0 -0
  340. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts_cli.py +0 -0
  341. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tts_server.py +0 -0
  342. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tunnels.py +0 -0
  343. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/tunnels_cli.py +0 -0
  344. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/usage_limit.py +0 -0
  345. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/__init__.py +0 -0
  346. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/chunker.py +0 -0
  347. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/event_log.py +0 -0
  348. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/file_io.py +0 -0
  349. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/paths.py +0 -0
  350. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/speech.py +0 -0
  351. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/utils/subprocess.py +0 -0
  352. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/validation.py +0 -0
  353. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/voice_status.py +0 -0
  354. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/wiki.py +0 -0
  355. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/wiki_audit.py +0 -0
  356. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/wiki_cli.py +0 -0
  357. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/agentwire/worktree_registry.py +0 -0
  358. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/decisions/obsidian-second-brain.md +0 -0
  359. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/design/session-card-fields.md +0 -0
  360. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/design/session-card-recommendation.md +0 -0
  361. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/logo.png +0 -0
  362. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/INDEX.md +0 -0
  363. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/architecture.md +0 -0
  364. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/briefing-mode.md +0 -0
  365. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/communication/channels.md +0 -0
  366. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/communication/hammerspoon.md +0 -0
  367. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/communication/handoff.md +0 -0
  368. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/concepts.md +0 -0
  369. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/council.md +0 -0
  370. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/deployment/remote-access.md +0 -0
  371. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/deployment/remote-machines.md +0 -0
  372. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/glossary.md +0 -0
  373. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
  374. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/damage-control.md +0 -0
  375. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/parallel-refactor.md +0 -0
  376. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/portal.md +0 -0
  377. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/session-topology.md +0 -0
  378. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/shell-escaping.md +0 -0
  379. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/troubleshooting.md +0 -0
  380. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/internals/window-collage.md +0 -0
  381. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/quickstart.md +0 -0
  382. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/research/briefing-mode-feasibility.md +0 -0
  383. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/research/orchestration-transport-alternatives.md +0 -0
  384. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/scheduling/scheduled-workloads.md +0 -0
  385. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/security/damage-control-hardening.md +0 -0
  386. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/security/pip-audit.md +0 -0
  387. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/security/remote-access-hardening.md +0 -0
  388. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/security/secrets.md +0 -0
  389. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/services.md +0 -0
  390. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
  391. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/messaging.md +0 -0
  392. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/prompt-routing.md +0 -0
  393. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/window-sizing.md +0 -0
  394. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/sessions/worktree-sessions.md +0 -0
  395. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/usage-limit-recovery.md +0 -0
  396. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/voice/shim-contract.md +0 -0
  397. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/voice/stt-cloud.md +0 -0
  398. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/voice/stt-self-hosted.md +0 -0
  399. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/docs/wiki/voice/tts-self-hosted.md +0 -0
  400. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/pyproject.toml +0 -0
  401. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/conftest.py +0 -0
  402. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/e2e/test_portal_ui.py +0 -0
  403. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/fixtures/sample_agentwire.yml +0 -0
  404. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/fixtures/sample_config.yaml +0 -0
  405. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/fixtures/sample_scheduler.yaml +0 -0
  406. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_council_portal.py +0 -0
  407. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_scheduler_board.py +0 -0
  408. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_send_verified_tmux.py +0 -0
  409. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/integration/test_server_websockets.py +0 -0
  410. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_announcements.py +0 -0
  411. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_build_agent_command.py +0 -0
  412. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_channels.py +0 -0
  413. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_chrome_tabs.py +0 -0
  414. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_cli_commands.py +0 -0
  415. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_cli_output.py +0 -0
  416. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_cli_smoke.py +0 -0
  417. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_config.py +0 -0
  418. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_config_cli.py +0 -0
  419. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_control_plane_protection.py +0 -0
  420. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_core_created_by_rooting.py +0 -0
  421. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_cli.py +0 -0
  422. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_inbox.py +0 -0
  423. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_minutes.py +0 -0
  424. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_state.py +0 -0
  425. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_council_view.py +0 -0
  426. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_damage_control_bypass.py +0 -0
  427. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_damage_control_hooks.py +0 -0
  428. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_damage_control_sync.py +0 -0
  429. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_dangling_worktrees.py +0 -0
  430. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_devices.py +0 -0
  431. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_diff_cli.py +0 -0
  432. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_doctor_scheduler_staleness.py +0 -0
  433. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_doctor_task_migration.py +0 -0
  434. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_doctor_voice.py +0 -0
  435. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_event_log.py +0 -0
  436. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_file_io.py +0 -0
  437. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_guarded_launch_command.py +0 -0
  438. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_handoff_git_state.py +0 -0
  439. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_handoff_instructions.py +0 -0
  440. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_handoff_parser.py +0 -0
  441. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_handoff_renderer.py +0 -0
  442. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_history.py +0 -0
  443. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_hooks_install.py +0 -0
  444. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_idle_handler.py +0 -0
  445. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_idle_nag.py +0 -0
  446. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_inbox.py +0 -0
  447. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_init_command.py +0 -0
  448. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_install_parity.py +0 -0
  449. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_limits_tick_isolation.py +0 -0
  450. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_locking.py +0 -0
  451. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_mcp_server.py +0 -0
  452. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_msg_cli.py +0 -0
  453. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_notify_cli.py +0 -0
  454. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_onboarding_reinit.py +0 -0
  455. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_palette_cli.py +0 -0
  456. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_pip_environment.py +0 -0
  457. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_posture_default.py +0 -0
  458. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_project_config.py +0 -0
  459. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_projects_registry.py +0 -0
  460. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_prompt_router.py +0 -0
  461. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_push.py +0 -0
  462. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_rebuild_guard.py +0 -0
  463. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_repo_cli.py +0 -0
  464. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_rich_text_js.py +0 -0
  465. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_roles.py +0 -0
  466. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_routes_snapshot.py +0 -0
  467. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_commands.py +0 -0
  468. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_disabled_rules.py +0 -0
  469. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_escape_hatch.py +0 -0
  470. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_heal.py +0 -0
  471. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_safety_kill_switch.py +0 -0
  472. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_scheduler.py +0 -0
  473. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_scheduler_parsing.py +0 -0
  474. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_scheduler_zombie.py +0 -0
  475. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_scratchpad.py +0 -0
  476. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_security.py +0 -0
  477. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_server_async.py +0 -0
  478. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_server_pure.py +0 -0
  479. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_services.py +0 -0
  480. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_session_context.py +0 -0
  481. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_session_created_by_env.py +0 -0
  482. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_session_ready.py +0 -0
  483. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_shared_dir_guard.py +0 -0
  484. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_shim_selfheal.py +0 -0
  485. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_skill_install.py +0 -0
  486. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_speech_tags.py +0 -0
  487. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_ssh.py +0 -0
  488. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_stt_backend.py +0 -0
  489. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_stt_cloud.py +0 -0
  490. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_stt_engine.py +0 -0
  491. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_task_cli.py +0 -0
  492. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tasks.py +0 -0
  493. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tasks_cli.py +0 -0
  494. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_templating.py +0 -0
  495. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_terminal_resize.py +0 -0
  496. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tmux_template.py +0 -0
  497. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tts_engine_resolution.py +0 -0
  498. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tts_local.py +0 -0
  499. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_tunnels_probe.py +0 -0
  500. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_unattended_env_isolation.py +0 -0
  501. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_usage_limit.py +0 -0
  502. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_validation.py +0 -0
  503. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_voice_status.py +0 -0
  504. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_wiki.py +0 -0
  505. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_wiki_audit.py +0 -0
  506. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_window_cycling_binding.py +0 -0
  507. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_worktree_branch_cleanup.py +0 -0
  508. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/tests/unit/test_worktree_layout.py +0 -0
  509. {agentwire_dev-1.65.1 → agentwire_dev-1.65.2}/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.65.1
3
+ Version: 1.65.2
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.65.1"
3
+ __version__ = "1.65.2"
@@ -10,6 +10,22 @@ through the composed server's MRO.
10
10
  from aiohttp import web
11
11
 
12
12
 
13
+ def _artifact_url_hash(url: str) -> str:
14
+ """FNV-1a 32-bit hash of ``url``, as 8 lowercase hex chars.
15
+
16
+ Must match ``artifactUrlHash`` in static/js/desktop.js byte-for-byte —
17
+ the server and frontend both derive the same fallback artifact id from
18
+ the same URL, and a naive char-substitution slug (the prior approach)
19
+ let distinct URLs like "reports/jan.html" and "reports-jan.html" collide
20
+ onto the same id. A hash isn't lossy the way substitution is.
21
+ """
22
+ h = 0x811C9DC5
23
+ for b in url.encode("utf-8"):
24
+ h ^= b
25
+ h = (h * 0x01000193) & 0xFFFFFFFF
26
+ return f"{h:08x}"
27
+
28
+
13
29
  class DesktopRoutesMixin:
14
30
  async def api_desktop_windows(self, request):
15
31
  """GET /api/desktop/windows — query browser clients for open windows."""
@@ -173,7 +189,7 @@ class DesktopRoutesMixin:
173
189
  "url": url,
174
190
  "title": title,
175
191
  "artifact_id": artifact.get("artifact_id")
176
- or f"artifact-{url.replace('/', '-').replace('.', '-')}",
192
+ or f"artifact-{_artifact_url_hash(url)}",
177
193
  }
178
194
  if not text:
179
195
  text = f"**{title}** is ready — click to open"
@@ -62,6 +62,7 @@ from .worktree import (
62
62
  default_base_branch,
63
63
  ensure_worktree,
64
64
  git_root,
65
+ is_registered_worktree,
65
66
  is_valid_branch_name,
66
67
  parse_session_name,
67
68
  remove_worktree,
@@ -1561,7 +1562,17 @@ def _teardown_entry(
1561
1562
  Never reports worktree_removed=True while the dir is still on disk: if
1562
1563
  `git worktree remove --force` can't clear it, this fails LOUDLY
1563
1564
  (success: False) and leaves the registry entry in place, instead of
1564
- silently "unregistering" an orphan.
1565
+ silently "unregistering" an orphan — UNLESS git *already had no record of
1566
+ the path before we touched it* (see `is_registered_worktree`), in which
1567
+ case there's no registered worktree left to protect and the leftover
1568
+ directory (a stale build-tool cache, typically) is hard-deleted instead.
1569
+
1570
+ That pre-check matters: `git worktree prune` below runs unconditionally
1571
+ and clears any entry git marks "prunable" (e.g. one whose linked `.git`
1572
+ file was deleted) as a side effect of THIS call — checking registration
1573
+ after prune would misread a worktree that was real and registered right
1574
+ up until this attempt as a pre-existing orphan, and hard-delete content
1575
+ the fail-loud path exists to protect.
1565
1576
 
1566
1577
  The worktree removal is attempted BEFORE the session is killed, and the
1567
1578
  session is only killed once removal is confirmed — never the reverse.
@@ -1569,10 +1580,17 @@ def _teardown_entry(
1569
1580
  disk with no session left to notice, on any removal failure (bad
1570
1581
  project_path, a stuck worktree, ...) (#740).
1571
1582
  """
1583
+ was_registered = is_registered_worktree(project_path, worktree_path)
1584
+
1572
1585
  # Force-remove the git worktree, then prune admin files either way.
1573
1586
  _, remove_error = remove_worktree(project_path, worktree_path, force=True)
1574
1587
  subprocess.run(["git", "-C", str(project_path), "worktree", "prune"], capture_output=True)
1575
1588
 
1589
+ hard_deleted_orphan = False
1590
+ if worktree_path.exists() and not was_registered:
1591
+ shutil.rmtree(worktree_path, ignore_errors=True)
1592
+ hard_deleted_orphan = not worktree_path.exists()
1593
+
1576
1594
  if worktree_path.exists():
1577
1595
  reason = remove_error or "worktree directory still present after `git worktree remove --force`"
1578
1596
  return {"success": False, "session": session_name, "path": str(worktree_path),
@@ -1605,7 +1623,7 @@ def _teardown_entry(
1605
1623
  return {"success": True, "session": session_name, "path": str(worktree_path),
1606
1624
  "killed": killed, "worktree_removed": True,
1607
1625
  "branch": branch, "branch_deleted": branch_deleted, "branch_note": branch_note,
1608
- "orphaned_tabs": orphaned_tabs}
1626
+ "orphaned_tabs": orphaned_tabs, "hard_deleted_orphan": hard_deleted_orphan}
1609
1627
 
1610
1628
 
1611
1629
  def _worktree_remove(args, project_path: Path, worktree_dir: Path, json_mode: bool) -> int:
@@ -1641,7 +1659,9 @@ def _worktree_remove(args, project_path: Path, worktree_dir: Path, json_mode: bo
1641
1659
  else:
1642
1660
  msg = (f"Removed worktree session '{result['session']}'"
1643
1661
  + (" (killed live session)" if result["killed"] else "")
1644
- + f"; worktree {result['path']} removed")
1662
+ + f"; worktree {result['path']} removed"
1663
+ + (" (git had no registration for it — hard-deleted the leftover directory)"
1664
+ if result.get("hard_deleted_orphan") else ""))
1645
1665
  if result["branch"]:
1646
1666
  msg += f"; branch '{result['branch']}' " + ("deleted" if result["branch_deleted"] else f"kept ({result['branch_note']})")
1647
1667
  if result["orphaned_tabs"]:
@@ -824,6 +824,24 @@ function _mountSessionWindow(session, mode, machine, id) {
824
824
  addTaskbarButton(id, sw);
825
825
  }
826
826
 
827
+ /**
828
+ * FNV-1a 32-bit hash of `url`, as 8 lowercase hex chars. Must match
829
+ * `_artifact_url_hash` in routes/desktop.py byte-for-byte — server and
830
+ * frontend both derive the same fallback artifact id from the same URL. A
831
+ * hash isn't lossy the way the prior char-substitution slug was (distinct
832
+ * URLs like "reports/jan.html" and "reports-jan.html" collided onto the
833
+ * same id).
834
+ */
835
+ function artifactUrlHash(url) {
836
+ let h = 0x811c9dc5;
837
+ const bytes = new TextEncoder().encode(url);
838
+ for (const b of bytes) {
839
+ h ^= b;
840
+ h = Math.imul(h, 0x01000193) >>> 0;
841
+ }
842
+ return h.toString(16).padStart(8, '0');
843
+ }
844
+
827
845
  /**
828
846
  * Open an artifact window (agent-generated HTML or external URL).
829
847
  *
@@ -832,7 +850,7 @@ function _mountSessionWindow(session, mode, machine, id) {
832
850
  * @param {string|null} artifactId - Optional explicit window ID
833
851
  */
834
852
  export function openArtifactWindow(url, title = 'Artifact', artifactId = null) {
835
- const id = artifactId || `artifact-${url.replace(/[\/\.]/g, '-')}`;
853
+ const id = artifactId || `artifact-${artifactUrlHash(url)}`;
836
854
 
837
855
  // Check if already open — restore if minimized, otherwise focus
838
856
  if (artifactWindows.has(id)) {
@@ -86,10 +86,19 @@ class NotificationsPanel {
86
86
  this._removeToast(id, false);
87
87
  }
88
88
 
89
- // Evict oldest if at capacity
89
+ // Evict the oldest toast NOT carrying an artifact notice, if at
90
+ // capacity. Artifact toasts are exempt regardless of priority: an
91
+ // unclicked deliverable must not silently fade (#817) — the cap
92
+ // only trims ordinary toasts (sticky `high`-priority ones included).
93
+ // If every current toast is an artifact notice, the panel
94
+ // temporarily exceeds MAX_TOASTS rather than dropping one.
90
95
  if (this.toasts.size >= MAX_TOASTS) {
91
- const oldest = this.toasts.keys().next().value;
92
- this._removeToast(oldest, false);
96
+ for (const id of this.toasts.keys()) {
97
+ if (!this.artifactNotices.has(id)) {
98
+ this._removeToast(id, false);
99
+ break;
100
+ }
101
+ }
93
102
  }
94
103
 
95
104
  // Resolve auto-fade: explicit timeout wins (0 = sticky); otherwise
@@ -309,6 +309,39 @@ def remove_worktree(project_path: Path, worktree_path: Path, *, force: bool = Tr
309
309
  return False, (result.stderr or result.stdout).strip()
310
310
 
311
311
 
312
+ def is_registered_worktree(project_path: Path, worktree_path: Path) -> bool:
313
+ """Does git's own worktree registry (still) know about ``worktree_path``?
314
+
315
+ A directory can outlive its registration — e.g. `git worktree remove`
316
+ succeeded on a prior teardown attempt but the `rm -rf` half crashed
317
+ before clearing a build-tool cache dir left inside, or the admin file
318
+ under `.git/worktrees/` was pruned independently. In that state git
319
+ reports "fatal: ... is not a working tree" for every future removal
320
+ attempt, forever — this lets a caller distinguish that from a real
321
+ registered worktree that `remove --force` merely failed to clear. It
322
+ says nothing about whether the directory holds valuable content — that
323
+ judgment (e.g. "orphaned + unregistered is safe to hard-delete") belongs
324
+ to the caller, not this function.
325
+
326
+ Fails closed on an inconclusive read: if `git worktree list` itself
327
+ errors (corrupt repo, I/O, lock contention), that's reported as
328
+ registered rather than not — a caller gating a destructive action on
329
+ this should default to "assume real" when unsure, not "assume orphan".
330
+ """
331
+ result = subprocess.run(
332
+ ["git", "worktree", "list", "--porcelain"],
333
+ cwd=project_path, capture_output=True, text=True,
334
+ )
335
+ if result.returncode != 0:
336
+ return True
337
+ target = str(worktree_path.resolve())
338
+ for line in result.stdout.splitlines():
339
+ if line.startswith("worktree "):
340
+ if str(Path(line[len("worktree "):]).resolve()) == target:
341
+ return True
342
+ return False
343
+
344
+
312
345
  def worktree_status(worktree_path: Path) -> dict:
313
346
  """Read-only git status for a worktree. Local git only — no network, no gh.
314
347
 
@@ -643,6 +643,38 @@ def test_remove_fails_loudly_when_dir_survives(tmp_path, monkeypatch, wt_env, ca
643
643
  assert payload["error"]
644
644
 
645
645
 
646
+ def test_remove_hard_deletes_unregistered_orphan_directory(tmp_path, monkeypatch, wt_env, capsys):
647
+ """A directory git no longer registers as a worktree at all (its
648
+ `.git/worktrees/<name>` admin entry is gone, e.g. from a prior teardown
649
+ that crashed mid-way) must not get stuck failing `git worktree remove`
650
+ forever — since git has nothing left to lose, the leftover directory is
651
+ hard-deleted and teardown proceeds and succeeds."""
652
+ import shutil
653
+
654
+ _, clone = _origin_and_clone(tmp_path, default_branch="develop")
655
+ wt_dir = tmp_path / "worktrees"
656
+ cfg = _config(wt_dir)
657
+ assert _run(monkeypatch, cfg, name="orphan", project=str(clone)) == 0
658
+ wt_path = wt_dir / "clone-repo" / "orphan"
659
+ assert wt_path.exists()
660
+
661
+ # Simulate the crashed-partial-teardown state: git's own registration is
662
+ # gone, but the directory (with leftover content) survives on disk.
663
+ shutil.rmtree(clone / ".git" / "worktrees" / "orphan")
664
+ (wt_path / "stale-cache-file").write_text("leftover\n")
665
+
666
+ capsys.readouterr()
667
+ rc = _run(monkeypatch, cfg, name="orphan", project=str(clone), remove=True)
668
+ assert rc == 0
669
+ assert not wt_path.exists()
670
+ assert reg.entries(clone.resolve()) == []
671
+
672
+ payload = json.loads(capsys.readouterr().out)
673
+ assert payload["success"] is True
674
+ assert payload["worktree_removed"] is True
675
+ assert payload["hard_deleted_orphan"] is True
676
+
677
+
646
678
  def test_remove_kills_alive_session(tmp_path, monkeypatch, wt_env, capsys):
647
679
  _, clone = _origin_and_clone(tmp_path, default_branch="develop")
648
680
  wt_dir = tmp_path / "worktrees"
@@ -212,6 +212,35 @@ class TestVoiceTools:
212
212
  assert "parked" in result
213
213
 
214
214
 
215
+ class TestNotifyUserArtifactParams:
216
+ """#822: notify_user's artifact_url/artifact_title params (#821) had zero
217
+ test coverage — cover the body it builds for /api/desktop/notification."""
218
+
219
+ @patch("agentwire.mcp_notify._portal_request")
220
+ def test_artifact_url_sets_artifact_body_with_default_title(self, mock_req):
221
+ from agentwire.mcp_notify import notify_user
222
+ mock_req.return_value = _success(id="n1", clients=1)
223
+ notify_user(text="ready", artifact_url="report.html")
224
+ body = mock_req.call_args[0][2]
225
+ assert body["artifact"] == {"url": "report.html", "title": "Artifact"}
226
+
227
+ @patch("agentwire.mcp_notify._portal_request")
228
+ def test_artifact_title_overrides_default(self, mock_req):
229
+ from agentwire.mcp_notify import notify_user
230
+ mock_req.return_value = _success(id="n1", clients=1)
231
+ notify_user(text="ready", artifact_url="report.html", artifact_title="Q3 Report")
232
+ body = mock_req.call_args[0][2]
233
+ assert body["artifact"] == {"url": "report.html", "title": "Q3 Report"}
234
+
235
+ @patch("agentwire.mcp_notify._portal_request")
236
+ def test_no_artifact_url_omits_artifact_body(self, mock_req):
237
+ from agentwire.mcp_notify import notify_user
238
+ mock_req.return_value = _success(id="n1", clients=1)
239
+ notify_user(text="plain toast", artifact_title="ignored without a url")
240
+ body = mock_req.call_args[0][2]
241
+ assert "artifact" not in body
242
+
243
+
215
244
  # ---------------------------------------------------------------------------
216
245
  # Desktop tools
217
246
  # ---------------------------------------------------------------------------
@@ -614,6 +614,35 @@ class TestApiNotify:
614
614
  assert data["clients"] == 2
615
615
 
616
616
 
617
+ class TestArtifactUrlHash:
618
+ """#822: pins `_artifact_url_hash` (routes/desktop.py) against known
619
+ vectors, independently cross-checked in Node against its JS twin
620
+ (`artifactUrlHash` in static/js/desktop.js) — the two have no shared
621
+ source and no JS test harness exists in this repo, so this is the only
622
+ automated guard against the two silently drifting apart. If you change
623
+ the hash algorithm on either side, recompute vectors on the OTHER side
624
+ (e.g. `node -e "..."` mirroring this function) before touching this
625
+ test — a passing Python-only test proves nothing about JS parity."""
626
+
627
+ @pytest.mark.parametrize("url,expected", [
628
+ ("", "811c9dc5"),
629
+ ("a", "e40c292c"),
630
+ ("reports/jan.html", "7084fac5"),
631
+ ("reports-jan.html", "b5f6349b"),
632
+ ("https://example.com", "6fbc04d3"),
633
+ ("council-proj-minutes/index.html", "d569834e"),
634
+ ("日本語", "805f5ce7"), # multi-byte UTF-8
635
+ ("🦉", "11131011"), # astral/surrogate-pair UTF-8
636
+ ])
637
+ def test_pinned_vectors(self, url, expected):
638
+ from agentwire.routes.desktop import _artifact_url_hash
639
+ assert _artifact_url_hash(url) == expected
640
+
641
+ def test_distinct_urls_that_collided_under_the_old_slug_now_differ(self):
642
+ from agentwire.routes.desktop import _artifact_url_hash
643
+ assert _artifact_url_hash("reports/jan.html") != _artifact_url_hash("reports-jan.html")
644
+
645
+
617
646
  class TestApiDesktopNotification:
618
647
  async def test_toast_reports_client_count(self, portal_client):
619
648
  """#444: posting a toast reports how many dashboards saw it live (the
@@ -630,8 +659,10 @@ class TestApiDesktopNotification:
630
659
 
631
660
  async def test_artifact_notice_defaults(self, portal_client):
632
661
  """#817: an artifact notice needs no text (synthesized from the title),
633
- derives the frontend's url-slug window id, and defaults to sticky —
634
- an unclicked deliverable must never silently fade."""
662
+ derives the frontend's hash-based window id (#822 a lossy
663
+ char-substitution slug let distinct URLs collide onto the same id),
664
+ and defaults to sticky — an unclicked deliverable must never
665
+ silently fade."""
635
666
  client, server = portal_client
636
667
  server.broadcast_dashboard = AsyncMock()
637
668
  resp = await client.post("/api/desktop/notification", json={
@@ -645,9 +676,27 @@ class TestApiDesktopNotification:
645
676
  assert notice["artifact"] == {
646
677
  "url": "council-proj-minutes/index.html",
647
678
  "title": "Council minutes — proj",
648
- "artifact_id": "artifact-council-proj-minutes-index-html",
679
+ "artifact_id": "artifact-d569834e",
649
680
  }
650
681
 
682
+ async def test_artifact_id_does_not_collide_across_similar_urls(self, portal_client):
683
+ """#822: the fallback id used to be a lossy char-substitution slug —
684
+ "reports/jan.html" and "reports-jan.html" both became
685
+ "artifact-reports-jan-html", so a new artifact could dedup-clobber a
686
+ different still-pending one. A hash of the full url doesn't collide
687
+ on this pair, so both notices coexist."""
688
+ client, server = portal_client
689
+ server.broadcast_dashboard = AsyncMock()
690
+ await client.post("/api/desktop/notification", json={
691
+ "artifact": {"url": "reports/jan.html", "title": "Jan (nested)"},
692
+ })
693
+ await client.post("/api/desktop/notification", json={
694
+ "artifact": {"url": "reports-jan.html", "title": "Jan (flat)"},
695
+ })
696
+ assert len(server.active_notifications) == 2
697
+ ids = {n["artifact"]["artifact_id"] for n in server.active_notifications.values()}
698
+ assert len(ids) == 2
699
+
651
700
  async def test_artifact_requires_url(self, portal_client):
652
701
  client, server = portal_client
653
702
  server.broadcast_dashboard = AsyncMock()
@@ -667,6 +716,23 @@ class TestApiDesktopNotification:
667
716
  })
668
717
  assert len(server.active_notifications) == 1
669
718
 
719
+ async def test_two_distinct_artifact_notices_coexist(self, portal_client):
720
+ """Two different concurrent unclicked artifact deliverables must both
721
+ stay pending — dedup keys on artifact_id, so distinct artifacts must
722
+ never clobber each other the way a same-id re-render intentionally
723
+ does above."""
724
+ client, server = portal_client
725
+ server.broadcast_dashboard = AsyncMock()
726
+ await client.post("/api/desktop/notification", json={
727
+ "artifact": {"url": "report-a.html", "title": "Report A"},
728
+ })
729
+ await client.post("/api/desktop/notification", json={
730
+ "artifact": {"url": "report-b.html", "title": "Report B"},
731
+ })
732
+ assert len(server.active_notifications) == 2
733
+ titles = sorted(n["artifact"]["title"] for n in server.active_notifications.values())
734
+ assert titles == ["Report A", "Report B"]
735
+
670
736
  async def test_session_sweep_spares_artifact_notices(self, portal_client):
671
737
  """The one-toast-per-session replacement must not eat a pending
672
738
  artifact notice tagged with the same session — seeing the session
@@ -12,6 +12,7 @@ from agentwire.worktree import (
12
12
  git_common_dir,
13
13
  git_root,
14
14
  is_git_repo,
15
+ is_registered_worktree,
15
16
  is_valid_branch_name,
16
17
  parse_session_name,
17
18
  remove_worktree,
@@ -303,3 +304,45 @@ class TestRemoveWorktree:
303
304
  removed, error = remove_worktree(not_repo, tmp_path / "wherever")
304
305
  assert removed is False
305
306
  assert error
307
+
308
+
309
+ # --- is_registered_worktree ---
310
+
311
+ class TestIsRegisteredWorktree:
312
+ def test_true_for_a_live_worktree(self, tmp_path):
313
+ repo, _ = _make_repo(tmp_path)
314
+ wt = tmp_path / "repo-worktrees" / "feature"
315
+ assert ensure_worktree(repo, "feature", wt)
316
+ assert is_registered_worktree(repo, wt) is True
317
+
318
+ def test_false_once_gits_own_admin_dir_is_gone(self, tmp_path):
319
+ """A directory can outlive its registration (e.g. a prior teardown's
320
+ `rm` half crashed, or the admin dir was pruned independently) — once
321
+ git's `.git/worktrees/<name>` entry is gone, git itself no longer
322
+ considers this path a worktree, even though it still exists on disk.
323
+ """
324
+ import shutil
325
+
326
+ repo, _ = _make_repo(tmp_path)
327
+ wt = tmp_path / "repo-worktrees" / "feature"
328
+ assert ensure_worktree(repo, "feature", wt)
329
+
330
+ shutil.rmtree(repo / ".git" / "worktrees" / "feature")
331
+
332
+ assert wt.exists() # leftover directory content untouched
333
+ assert is_registered_worktree(repo, wt) is False
334
+
335
+ def test_false_for_a_path_never_registered(self, tmp_path):
336
+ repo, _ = _make_repo(tmp_path)
337
+ bogus = tmp_path / "never-a-worktree"
338
+ bogus.mkdir()
339
+ assert is_registered_worktree(repo, bogus) is False
340
+
341
+ def test_fails_closed_toward_registered_when_git_errors(self, tmp_path):
342
+ """An inconclusive `git worktree list` (corrupt repo, I/O error, ...)
343
+ must not be read as "definitely orphaned" — a caller gating a
344
+ destructive hard-delete on this should default to treating it as a
345
+ real worktree when unsure, not as safe to discard."""
346
+ not_a_repo = tmp_path / "not-a-repo"
347
+ not_a_repo.mkdir()
348
+ assert is_registered_worktree(not_a_repo, tmp_path / "wherever") is True
File without changes
File without changes
File without changes