agentwire-dev 1.28.1__tar.gz → 1.29.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/CHANGELOG.md +1 -0
  2. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/PKG-INFO +1 -1
  3. agentwire_dev-1.29.1/SECURITY.md +59 -0
  4. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/__init__.py +1 -1
  5. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/__main__.py +161 -181
  6. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/bash-tool-damage-control.py +89 -0
  7. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/edit-tool-damage-control.py +89 -0
  8. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/write-tool-damage-control.py +89 -0
  9. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/mcp_server.py +282 -119
  10. agentwire_dev-1.29.1/agentwire/missions/__init__.py +30 -0
  11. agentwire_dev-1.29.1/agentwire/missions/cli.py +521 -0
  12. agentwire_dev-1.29.1/agentwire/missions/config.py +93 -0
  13. agentwire_dev-1.29.1/agentwire/missions/dispatcher.py +325 -0
  14. agentwire_dev-1.29.1/agentwire/missions/eligibility.py +61 -0
  15. agentwire_dev-1.29.1/agentwire/missions/feedback_router.py +248 -0
  16. agentwire_dev-1.29.1/agentwire/missions/gc.py +228 -0
  17. agentwire_dev-1.29.1/agentwire/missions/github.py +252 -0
  18. agentwire_dev-1.29.1/agentwire/missions/naming.py +83 -0
  19. agentwire_dev-1.29.1/agentwire/missions/state.py +136 -0
  20. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/pane_manager.py +53 -31
  21. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/safety/_core.py +89 -0
  22. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/scheduler.py +12 -239
  23. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/server.py +67 -149
  24. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/css/desktop.css +44 -205
  25. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/desktop.js +2 -2
  26. agentwire_dev-1.29.1/agentwire/static/js/sidebar/missions-section.js +144 -0
  27. agentwire_dev-1.29.1/agentwire/static/js/sidebar/scheduler-section.js +179 -0
  28. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/INDEX.md +2 -3
  29. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/architecture.md +17 -21
  30. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/concepts.md +5 -9
  31. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/deployment/remote-machines.md +3 -3
  32. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/glossary.md +2 -5
  33. agentwire_dev-1.29.1/docs/wiki/missions.md +263 -0
  34. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/quickstart.md +0 -1
  35. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/scheduling/scheduled-workloads.md +3 -23
  36. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/pyproject.toml +0 -2
  37. agentwire_dev-1.29.1/templates/launchd/dev.agentwire.mission-dispatcher.plist +70 -0
  38. agentwire_dev-1.29.1/templates/launchd/dev.agentwire.mission-feedback-router.plist +49 -0
  39. agentwire_dev-1.29.1/templates/launchd/dev.agentwire.mission-janitor.plist +51 -0
  40. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/conftest.py +1 -1
  41. agentwire_dev-1.29.1/tests/integration/test_missions_concurrency.py +150 -0
  42. agentwire_dev-1.29.1/tests/integration/test_missions_lifecycle.py +236 -0
  43. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_cli_safety.py +6 -2
  44. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_history.py +2 -2
  45. agentwire_dev-1.29.1/tests/unit/test_missions_cli.py +403 -0
  46. agentwire_dev-1.29.1/tests/unit/test_missions_config.py +97 -0
  47. agentwire_dev-1.29.1/tests/unit/test_missions_dispatcher.py +244 -0
  48. agentwire_dev-1.29.1/tests/unit/test_missions_eligibility.py +113 -0
  49. agentwire_dev-1.29.1/tests/unit/test_missions_feedback_router.py +283 -0
  50. agentwire_dev-1.29.1/tests/unit/test_missions_gc.py +276 -0
  51. agentwire_dev-1.29.1/tests/unit/test_missions_github.py +174 -0
  52. agentwire_dev-1.29.1/tests/unit/test_missions_naming.py +97 -0
  53. agentwire_dev-1.29.1/tests/unit/test_missions_state.py +120 -0
  54. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_project_config.py +4 -4
  55. agentwire_dev-1.29.1/tests/unit/test_safety_mission_worker.py +233 -0
  56. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_scheduler.py +4 -126
  57. agentwire_dev-1.28.1/SECURITY.md +0 -46
  58. agentwire_dev-1.28.1/agentwire/static/js/sidebar/scheduler-section.js +0 -101
  59. agentwire_dev-1.28.1/agentwire/static/js/sidebar/workflows-section.js +0 -114
  60. agentwire_dev-1.28.1/agentwire/static/js/windows/workflow-window.js +0 -166
  61. agentwire_dev-1.28.1/agentwire/workflows/__init__.py +0 -27
  62. agentwire_dev-1.28.1/agentwire/workflows/cli.py +0 -378
  63. agentwire_dev-1.28.1/agentwire/workflows/context.py +0 -52
  64. agentwire_dev-1.28.1/agentwire/workflows/definitions.py +0 -370
  65. agentwire_dev-1.28.1/agentwire/workflows/node.py +0 -137
  66. agentwire_dev-1.28.1/agentwire/workflows/outputs.py +0 -149
  67. agentwire_dev-1.28.1/agentwire/workflows/pi_runner.py +0 -245
  68. agentwire_dev-1.28.1/agentwire/workflows/runner.py +0 -378
  69. agentwire_dev-1.28.1/agentwire/workflows/runners/__init__.py +0 -56
  70. agentwire_dev-1.28.1/agentwire/workflows/runners/pi.py +0 -35
  71. agentwire_dev-1.28.1/agentwire/workflows/storage.py +0 -198
  72. agentwire_dev-1.28.1/docs/wiki/scheduling/workflows.md +0 -512
  73. agentwire_dev-1.28.1/tests/unit/test_pi_runner.py +0 -427
  74. agentwire_dev-1.28.1/tests/unit/test_runner_on_event.py +0 -86
  75. agentwire_dev-1.28.1/tests/unit/test_runners_registry.py +0 -108
  76. agentwire_dev-1.28.1/tests/unit/test_scheduler_workflow_dispatch.py +0 -213
  77. agentwire_dev-1.28.1/tests/unit/test_server_workflow_history.py +0 -173
  78. agentwire_dev-1.28.1/tests/unit/test_workflow_cli.py +0 -172
  79. agentwire_dev-1.28.1/tests/unit/test_workflow_storage.py +0 -128
  80. agentwire_dev-1.28.1/tests/unit/test_workflows.py +0 -487
  81. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/.github/FUNDING.yml +0 -0
  82. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  83. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  84. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/.github/ISSUE_TEMPLATE/question.md +0 -0
  85. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  86. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/.gitignore +0 -0
  87. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/CLA.md +0 -0
  88. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/CODE_OF_CONDUCT.md +0 -0
  89. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/CONTRIBUTING.md +0 -0
  90. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/Dockerfile.local +0 -0
  91. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/Dockerfile.runpod +0 -0
  92. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/LICENSE +0 -0
  93. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/README.md +0 -0
  94. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/RELEASING.md +0 -0
  95. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/SPONSORS.md +0 -0
  96. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/agents/__init__.py +0 -0
  97. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/agents/base.py +0 -0
  98. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/agents/tmux.py +0 -0
  99. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/cached_status.py +0 -0
  100. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/channels/__init__.py +0 -0
  101. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/channels/base.py +0 -0
  102. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/channels/email.py +0 -0
  103. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/channels/quo.py +0 -0
  104. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/cli_safety.py +0 -0
  105. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/completion.py +0 -0
  106. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/config.py +0 -0
  107. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/fetch.py +0 -0
  108. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/handoff/__init__.py +0 -0
  109. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/handoff/git_state.py +0 -0
  110. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/handoff/instructions.py +0 -0
  111. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/handoff/parser.py +0 -0
  112. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/handoff/renderer.py +0 -0
  113. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/handoff/schema.py +0 -0
  114. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/history.py +0 -0
  115. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/__init__.py +0 -0
  116. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/agentwire-permission.sh +0 -0
  117. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/__init__.py +0 -0
  118. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/audit_logger.py +0 -0
  119. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/agentwire.yaml +0 -0
  120. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/aws.yaml +0 -0
  121. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/cloud-hosting.yaml +0 -0
  122. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/containers.yaml +0 -0
  123. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/core.yaml +0 -0
  124. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/databases.yaml +0 -0
  125. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/firebase.yaml +0 -0
  126. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/gcp.yaml +0 -0
  127. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/git.yaml +0 -0
  128. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/gws.yaml +0 -0
  129. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/infrastructure.yaml +0 -0
  130. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/damage-control/rules/remote.yaml +0 -0
  131. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/hooks/idle-handler.sh +0 -0
  132. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/listen.py +0 -0
  133. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/locking.py +0 -0
  134. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/network.py +0 -0
  135. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/onboarding.py +0 -0
  136. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/overnight.py +0 -0
  137. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/project_config.py +0 -0
  138. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/projects.py +0 -0
  139. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/prompts/__init__.py +0 -0
  140. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/prompts/init.md +0 -0
  141. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/__init__.py +0 -0
  142. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/agentwire.md +0 -0
  143. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/chatbot.md +0 -0
  144. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/init.md +0 -0
  145. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/notifications.md +0 -0
  146. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/orchestrator.md +0 -0
  147. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/task-runner.md +0 -0
  148. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/voice.md +0 -0
  149. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/roles/worker.md +0 -0
  150. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/safety/__init__.py +0 -0
  151. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/search.py +0 -0
  152. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-Echo--black.png +0 -0
  153. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-Echo--transparent.png +0 -0
  154. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-Echo.png +0 -0
  155. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-email-banner.png +0 -0
  156. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--agentwire-text.png +0 -0
  157. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--echo-claw-fg.png +0 -0
  158. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--echo.png +0 -0
  159. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--full--transparent-top.png +0 -0
  160. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--full-black.png +0 -0
  161. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--telephone-fg.png +0 -0
  162. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--telephone.png +0 -0
  163. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--transparent-top.png +0 -0
  164. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--transparent.png +0 -0
  165. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers--tree.png +0 -0
  166. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/agentwire-splash-logo-layers.png +0 -0
  167. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/favicon.png +0 -0
  168. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/android.jpeg +0 -0
  169. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/automaton.jpeg +0 -0
  170. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/bot.jpeg +0 -0
  171. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/cyborg.jpeg +0 -0
  172. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/droid.jpeg +0 -0
  173. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/drone.jpeg +0 -0
  174. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/guardian.jpeg +0 -0
  175. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/mech.jpeg +0 -0
  176. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/probe.jpeg +0 -0
  177. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/robot.jpeg +0 -0
  178. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/sentinel.jpeg +0 -0
  179. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/machines/unit.jpeg +0 -0
  180. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/blob.jpeg +0 -0
  181. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/cloud.jpeg +0 -0
  182. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/crystal.jpeg +0 -0
  183. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/cyclops.jpeg +0 -0
  184. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/flame.jpeg +0 -0
  185. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/fuzzy.jpeg +0 -0
  186. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/horned.jpeg +0 -0
  187. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/moon.jpeg +0 -0
  188. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/slime.jpeg +0 -0
  189. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/star.jpeg +0 -0
  190. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/tentacle.jpeg +0 -0
  191. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/projects/winged.jpeg +0 -0
  192. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/bear.jpeg +0 -0
  193. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/cat.jpeg +0 -0
  194. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/crown.jpeg +0 -0
  195. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/custom/agentwire-portal.png +0 -0
  196. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/custom/agentwire-tts.png +0 -0
  197. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/custom/agentwire.png +0 -0
  198. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/deer.jpeg +0 -0
  199. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/drone.jpeg +0 -0
  200. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/eagle.jpeg +0 -0
  201. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/fox.jpeg +0 -0
  202. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/hawk.jpeg +0 -0
  203. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/horse.jpeg +0 -0
  204. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/lion.jpeg +0 -0
  205. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/rabbit.jpeg +0 -0
  206. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/robot.jpeg +0 -0
  207. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/tiger.jpeg +0 -0
  208. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/icons/sessions/wolf.jpeg +0 -0
  209. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/.gitkeep +0 -0
  210. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/artifact-window.js +0 -0
  211. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/components/icon-picker.js +0 -0
  212. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/components/list-card.js +0 -0
  213. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/components/type-tag.js +0 -0
  214. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/desktop-manager.js +0 -0
  215. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/icon-manager.js +0 -0
  216. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/new-project-modal.js +0 -0
  217. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/notifications-panel.js +0 -0
  218. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/quicktask-modal.js +0 -0
  219. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/safety-shared.js +0 -0
  220. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/safety-window.js +0 -0
  221. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/session-id.js +0 -0
  222. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/session-window.js +0 -0
  223. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/sidebar/artifacts-section.js +0 -0
  224. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/sidebar/config-section.js +0 -0
  225. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/sidebar/machines-section.js +0 -0
  226. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/sidebar/projects-section.js +0 -0
  227. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/sidebar/safety-section.js +0 -0
  228. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/sidebar/services-section.js +0 -0
  229. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/sidebar/sessions-section.js +0 -0
  230. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/sidebar.js +0 -0
  231. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/terminal-font-prefs.js +0 -0
  232. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/tile-manager.js +0 -0
  233. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/utils/auto-refresh.js +0 -0
  234. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/winbox.bundle.min.js +0 -0
  235. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/static/js/windows/chat-window.js +0 -0
  236. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/stt/__init__.py +0 -0
  237. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/stt/base.py +0 -0
  238. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/stt/server_backend.py +0 -0
  239. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/stt/stt_server.py +0 -0
  240. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/stt/whisperkit.py +0 -0
  241. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tasks.py +0 -0
  242. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/templates/__init__.py +0 -0
  243. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/templates/base.html +0 -0
  244. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/templates/desktop.html +0 -0
  245. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/templates/email_notification.html +0 -0
  246. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/templates/handoff/show-the-story.html.j2 +0 -0
  247. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/templates/handoff/theme.css.j2 +0 -0
  248. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/templates/tmux.conf +0 -0
  249. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/templating.py +0 -0
  250. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/aws.yaml +0 -0
  251. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/docker.yaml +0 -0
  252. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/gcp.yaml +0 -0
  253. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/gh.yaml +0 -0
  254. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/git.yaml +0 -0
  255. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/gws.yaml +0 -0
  256. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/kubectl.yaml +0 -0
  257. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/npm.yaml +0 -0
  258. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/terraform.yaml +0 -0
  259. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tooldefs/uv.yaml +0 -0
  260. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/__init__.py +0 -0
  261. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/base.py +0 -0
  262. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/engines/__init__.py +0 -0
  263. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/engines/chatterbox.py +0 -0
  264. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/engines/kokoro.py +0 -0
  265. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/engines/qwen_base.py +0 -0
  266. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/engines/qwen_custom.py +0 -0
  267. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/engines/qwen_design.py +0 -0
  268. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/engines/zonos.py +0 -0
  269. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/registry.py +0 -0
  270. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts/runpod_handler.py +0 -0
  271. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tts_server.py +0 -0
  272. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/tunnels.py +0 -0
  273. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/utils/__init__.py +0 -0
  274. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/utils/chunker.py +0 -0
  275. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/utils/file_io.py +0 -0
  276. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/utils/paths.py +0 -0
  277. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/utils/subprocess.py +0 -0
  278. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/validation.py +0 -0
  279. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/voiceclone.py +0 -0
  280. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/voices/darren.wav +0 -0
  281. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/voices/default.wav +0 -0
  282. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/voices/jessica.wav +0 -0
  283. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/voices/lisa.wav +0 -0
  284. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/voices/may.wav +0 -0
  285. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/agentwire/worktree.py +0 -0
  286. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/logo.png +0 -0
  287. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/communication/channels.md +0 -0
  288. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/communication/hammerspoon.md +0 -0
  289. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/communication/handoff.md +0 -0
  290. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/deployment/remote-access.md +0 -0
  291. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/integrations/gws-google-workspace-cli.md +0 -0
  292. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/internals/damage-control.md +0 -0
  293. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/internals/portal.md +0 -0
  294. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/internals/shell-escaping.md +0 -0
  295. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/internals/troubleshooting.md +0 -0
  296. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/sessions/claude-code-auto-mode.md +0 -0
  297. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/sessions/pi.md +0 -0
  298. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/tts/runpod-tts.md +0 -0
  299. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/docs/wiki/tts/tts-self-hosted.md +0 -0
  300. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/requirements-tts.txt +0 -0
  301. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/e2e/test_portal_ui.py +0 -0
  302. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/fixtures/sample_agentwire.yml +0 -0
  303. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/fixtures/sample_config.yaml +0 -0
  304. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/fixtures/sample_scheduler.yaml +0 -0
  305. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/integration/test_scheduler_board.py +0 -0
  306. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/integration/test_server_websockets.py +0 -0
  307. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_build_agent_command.py +0 -0
  308. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_channels.py +0 -0
  309. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_cli_commands.py +0 -0
  310. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_cli_output.py +0 -0
  311. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_config.py +0 -0
  312. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_damage_control_hooks.py +0 -0
  313. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_damage_control_sync.py +0 -0
  314. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_file_io.py +0 -0
  315. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_handoff_git_state.py +0 -0
  316. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_handoff_instructions.py +0 -0
  317. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_handoff_parser.py +0 -0
  318. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_handoff_renderer.py +0 -0
  319. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_locking.py +0 -0
  320. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_mcp_server.py +0 -0
  321. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_mcp_tools_args.py +0 -0
  322. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_overnight_resume_flags.py +0 -0
  323. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_portal_api.py +0 -0
  324. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_roles.py +0 -0
  325. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_safety_disabled_rules.py +0 -0
  326. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_safety_escape_hatch.py +0 -0
  327. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_safety_kill_switch.py +0 -0
  328. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_scheduler_parsing.py +0 -0
  329. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_search.py +0 -0
  330. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_server_async.py +0 -0
  331. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_server_pure.py +0 -0
  332. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_tasks.py +0 -0
  333. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_templating.py +0 -0
  334. {agentwire_dev-1.28.1 → agentwire_dev-1.29.1}/tests/unit/test_worktree.py +0 -0
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Removed
11
11
 
12
+ - **Workflow engine** — entire `agentwire/workflows/` package (DAG runner, definitions, storage, pi runner, CLI), the `agentwire workflow` CLI subcommand, 5 MCP tools (`workflow_list/validate/run/history/show`), 3 portal endpoints (`/api/workflows/list|runs|runs/{id}`), the Workflows sidebar section + WorkflowWindow + ~230 lines of CSS, the scheduler's `workflow:` dispatch branch (`SchedulerTask.workflow`/`inputs` fields, `_dispatch_workflow_task`, `_render_workflow_inputs`, `_parse_workflow_summary`, `_workflow_failure_state`, validation block), 9 workflow test files plus the workflow-specific cases in `test_scheduler.py`, the `agentwire-workflows` skill, `docs/wiki/scheduling/workflows.md`, and ~120 dirs of historical runs under `~/.agentwire/workflows/`. The user's actual recurring automations all live as scheduler ensure tasks (`task:`); the engine was unused in practice and the empty sidebar surface was just noise. Scheduler is now ensure-only.
12
13
  - **Inbound channel surface** — entire Telegram bridge (`agentwire/bridges/telegram.py`), Discord channel (`agentwire/channels/discord.py`), Slack channel (`agentwire/channels/slack.py`), Twilio SMS (`agentwire/channels/sms.py`), Webhook (`agentwire/channels/webhook.py`), outbound-Telegram (`agentwire/channels/telegram.py`), channel scaffolding template (`agentwire/channels/_template.py`), all `agentwire {telegram,discord,slack,sms,webhook}` CLI command groups, the `agentwire reply` command, MCP tools `discord_status` / `slack_status` / `sms_send` / `webhook_send`, the portal sidebar "socials" section, the `ServiceChannel` / `MessageQueueManager` / `QueuedMessage` / `compose_session_config` / `inject_instructions` / session-helper plumbing in `channels/base.py`, the TTS/STT primitives on the channel base class, the auto-injected `discord-dm` / `slack-dm` / `channel-admin` roles, the `OutputConfig.notify` task field plus its `_handle_task_notification` dispatcher (voice / alert / webhook / email / command), the doctor's Telegram bridge check, and the `aiogram` optional dep. Wire surface is now outbound-only: **email** (Resend) and **quo** (OpenPhone SMS) remain. Inbound user input flows through the portal. Security review traced the cut: Telegram bridge was secure (refuse-to-start on empty allowlist + silent default-deny), Discord/Slack fail-open on empty allowlist + unauthenticated channel `@mention`; rather than fix the gaps, the whole inbound surface comes out to keep the wire posture outbound-only.
13
14
  - **Anthropic SDK surface** — entire `agentwire/sdk/` package, `agentwire/repl/` (Textual REPL), `agentwire/workflows/runners/{anthropic,human_gate}.py`, `sdk-bypass` / `sdk-prompted` / `sdk-restricted` session types, `sdk-watch` portal window + sidebar section, `--runner` workflow CLI override, and the `claude-agent-sdk` dependency. Anthropic moved Agent SDK + `claude -p` usage out of the monthly subscription tier on 2026-05-13 (now API-billed); the in-tree consumers were too expensive to keep running. The `pi` workflow runner is now the only runner. For Anthropic-quality scheduled work, use a `claude-bypass` tmux session via `.agentwire.yml` + scheduler. Mission [#184](https://github.com/dotdevdotdev/agentwire-dev/issues/184). Findings captured in `~/.agentwire/wiki/` (anthropic-agent-sdk, anthropic-runner-findings, textual-repl-retrospective, workflow-runner-choice, claude-code-print-mode).
14
15
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentwire-dev
3
- Version: 1.28.1
3
+ Version: 1.29.1
4
4
  Summary: Multi-session voice web interface for AI coding agents
5
5
  Project-URL: Homepage, https://agentwire.dev
6
6
  Project-URL: Repository, https://github.com/dotdevdotdev/agentwire-dev
@@ -0,0 +1,59 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If you discover a security vulnerability in AgentWire, please report it privately.
6
+
7
+ **Do NOT open a public GitHub issue for security vulnerabilities.**
8
+
9
+ ### How to Report
10
+
11
+ Email: security@agentwire.dev
12
+
13
+ Include:
14
+ - Description of the vulnerability
15
+ - Steps to reproduce
16
+ - Potential impact
17
+ - Any suggested fixes (optional)
18
+
19
+ ### What to Expect
20
+
21
+ - **Acknowledgment:** Within 48 hours
22
+ - **Initial Assessment:** Within 1 week
23
+ - **Resolution Timeline:** Depends on severity, typically 30-90 days
24
+
25
+ ### Scope
26
+
27
+ This security policy applies to:
28
+ - The AgentWire CLI (`agentwire` command)
29
+ - The AgentWire portal (web interface)
30
+ - Official AgentWire packages on PyPI
31
+
32
+ ### Out of Scope
33
+
34
+ - Third-party dependencies (report to their maintainers)
35
+ - Self-hosted TTS/STT servers
36
+ - User misconfiguration
37
+
38
+ ## Security Features
39
+
40
+ AgentWire includes built-in security features:
41
+
42
+ - **Damage Control Hooks:** Block 300+ dangerous command patterns
43
+ - **Path Protection:** Prevent access to sensitive files (.env, SSH keys, credentials)
44
+ - **Audit Logging:** All blocked operations are logged
45
+
46
+ See `docs/wiki/internals/damage-control.md` for details.
47
+
48
+ ## Trust Model
49
+
50
+ The portal (HTTPS server bound to `0.0.0.0:8765` by default) **has no built-in authentication or authorization on its API endpoints**. This is by design — agentwire is built for a local-network trust perimeter, typically running on the same machine as the operator's browser or behind a Cloudflare Tunnel + Zero Trust gate (see `docs/wiki/deployment/remote-access.md`).
51
+
52
+ What this means in practice:
53
+
54
+ - **Anyone who can reach the portal port can drive it.** All `/api/*` endpoints (scheduler control, missions dispatch, project deletion, artifact upload, desktop window control) execute without auth.
55
+ - **Do not expose the portal directly to the public internet.** Use either firewall rules limiting access to trusted IPs, or front it with an auth gateway. Cloudflare Tunnel + Zero Trust is the recommended pattern; details in the deployment docs.
56
+ - **Project deletion via `/api/projects/delete`** validates the path is absolute, contains no `..`, contains no shell metacharacters, and is not in a protected list. Local execution uses argv form (no shell); SSH execution uses `shlex.quote` per argument. These mitigations don't substitute for perimeter security — they reduce blast radius if the perimeter fails.
57
+ - **CSRF / Origin checks are not enforced** on state-changing POSTs. A browser inside the trust perimeter that loads attacker-controlled content could be coerced into making requests to the portal. If your portal is reachable from a browser on a less-trusted network, add an origin check or fence it behind an auth proxy.
58
+
59
+ If you need authentication, the recommended path is **Cloudflare Tunnel + Zero Trust** rather than adding auth in-process: identity, MFA, audit, and revocation are all handled upstream and survive process restarts.
@@ -1,3 +1,3 @@
1
1
  """AgentWire - Multi-session voice web interface for AI coding agents."""
2
2
 
3
- __version__ = "1.28.1"
3
+ __version__ = "1.29.1"
@@ -2,7 +2,6 @@
2
2
 
3
3
  import argparse
4
4
  import base64
5
- from dataclasses import dataclass, field
6
5
  import datetime
7
6
  import importlib.resources
8
7
  import json
@@ -17,6 +16,7 @@ import tempfile
17
16
  import time
18
17
  import urllib.error
19
18
  import urllib.request
19
+ from dataclasses import dataclass, field
20
20
  from pathlib import Path
21
21
 
22
22
  from dotenv import load_dotenv
@@ -101,6 +101,17 @@ def _build_tmux_env_flags_shell(env: dict[str, str]) -> str:
101
101
  return " ".join(parts) + " "
102
102
 
103
103
 
104
+ def _set_session_name_env(agent: "AgentCommand", session_name: str) -> None:
105
+ """Stamp ``AGENTWIRE_SESSION_NAME`` onto an ``AgentCommand.env``.
106
+
107
+ Every session created via ``cmd_new`` / ``cmd_spawn`` / ``cmd_recreate``
108
+ / ``cmd_fork`` / scheduler-spawn paths gets this so downstream tooling
109
+ (notably the mission-worker damage-control rules in ``safety/_core.py``)
110
+ can identify which agentwire session the running tool is part of.
111
+ """
112
+ agent.env["AGENTWIRE_SESSION_NAME"] = session_name
113
+
114
+
104
115
  def inject_session_env(session: str, env: dict[str, str], remote_host: str | None = None) -> None:
105
116
  """Set env vars on an existing tmux session for FUTURE shells in that session.
106
117
 
@@ -1386,9 +1397,10 @@ def cmd_tts_restart(args) -> int:
1386
1397
  Used by CLI when venv_mismatch occurs during TTS request.
1387
1398
  Supports both local and remote TTS servers.
1388
1399
  """
1389
- from .network import NetworkContext
1390
1400
  import time
1391
1401
 
1402
+ from .network import NetworkContext
1403
+
1392
1404
  ctx = NetworkContext.from_config()
1393
1405
  session_name = get_tts_session_name()
1394
1406
 
@@ -2907,40 +2919,14 @@ def cmd_send(args) -> int:
2907
2919
  print(f"Session '{session}' not found", file=sys.stderr)
2908
2920
  return 1
2909
2921
 
2910
- # Send the prompt use load-buffer for anything non-trivial to avoid PTY flooding
2911
- use_buffer = len(prompt) > 10 or "\n" in prompt
2912
-
2913
- if use_buffer:
2914
- with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
2915
- f.write(prompt)
2916
- temp_path = f.name
2917
- try:
2918
- subprocess.run(["tmux", "load-buffer", temp_path], check=True)
2919
- subprocess.run(["tmux", "paste-buffer", "-t", session], check=True)
2920
- finally:
2921
- os.unlink(temp_path)
2922
- else:
2923
- subprocess.run(
2924
- ["tmux", "send-keys", "-t", session, "-l", prompt],
2925
- check=True
2926
- )
2927
-
2928
- # Wait for text to be displayed before pressing Enter
2929
- time.sleep(0.5)
2930
-
2931
- subprocess.run(
2932
- ["tmux", "send-keys", "-t", session, "Enter"],
2933
- check=True
2934
- )
2935
-
2936
- # For multi-line text, Claude Code shows "[Pasted text...]" and waits for Enter
2937
- # Send another Enter after a short delay to confirm the paste
2938
- if "\n" in prompt or len(prompt) > 200:
2939
- time.sleep(0.5)
2940
- subprocess.run(
2941
- ["tmux", "send-keys", "-t", session, "Enter"],
2942
- check=True
2943
- )
2922
+ # Delegate paste + Enter handling to the shared pane_manager helper so
2923
+ # send-to-session and send-to-pane stay in lockstep. The helper handles
2924
+ # buffer-vs-send-keys, settle delay, and the bracketed-paste double-Enter
2925
+ # in one place.
2926
+ try:
2927
+ pane_manager.send_to_target(session, prompt, enter=True)
2928
+ except RuntimeError as e:
2929
+ return _output_result(False, json_mode, str(e))
2944
2930
 
2945
2931
  if json_mode:
2946
2932
  print(json.dumps({"success": True, "session": session_full, "machine": None, "message": "Prompt sent"}))
@@ -3372,6 +3358,40 @@ def cmd_new(args) -> int:
3372
3358
  # Simple session: ~/projects/project/
3373
3359
  session_path = projects_dir / project
3374
3360
 
3361
+ # Safety: refuse to attach a new session to a path that is already the working
3362
+ # directory of another active session. Two agents sharing the same working tree
3363
+ # is the dangerous footgun (one's dirty state visible to the other, branches
3364
+ # mixing). Worktree sessions (project/branch) get unique paths and won't trip
3365
+ # this. --force overrides.
3366
+ if not args.force:
3367
+ target = str(session_path.resolve()) if session_path.exists() else str(session_path)
3368
+ panes_result = subprocess.run(
3369
+ ["tmux", "list-panes", "-a", "-F", "#{session_name}\t#{pane_current_path}"],
3370
+ capture_output=True, text=True,
3371
+ )
3372
+ if panes_result.returncode == 0:
3373
+ conflicting: set[str] = set()
3374
+ for line in panes_result.stdout.splitlines():
3375
+ if "\t" not in line:
3376
+ continue
3377
+ sess, p = line.split("\t", 1)
3378
+ if sess == session_name:
3379
+ continue
3380
+ try:
3381
+ if str(Path(p).resolve()) == target:
3382
+ conflicting.add(sess)
3383
+ except (OSError, RuntimeError):
3384
+ continue
3385
+ if conflicting:
3386
+ others = ", ".join(sorted(conflicting))
3387
+ hint = (
3388
+ f"Refusing to attach session '{session_name}' to {session_path}: "
3389
+ f"already the working directory of active session(s): {others}. "
3390
+ "Use a 'project/branch' name to create an isolated worktree, "
3391
+ "pick a different path, or pass --force to override."
3392
+ )
3393
+ return _output_result(False, json_mode, hint)
3394
+
3375
3395
  if not session_path.exists():
3376
3396
  if args.force or path:
3377
3397
  # Auto-create directory with -f flag or when custom path explicitly provided
@@ -3431,6 +3451,7 @@ def cmd_new(args) -> int:
3431
3451
  model_override = getattr(args, 'model', None)
3432
3452
  agent = build_agent_command(session_type, roles if roles else None, model=model_override)
3433
3453
  agent.env.update(parse_env_args(getattr(args, 'env', None)))
3454
+ _set_session_name_env(agent, session_name)
3434
3455
 
3435
3456
  agent_cmd = agent.command
3436
3457
 
@@ -6291,9 +6312,10 @@ def cmd_voiceclone_list(args) -> int:
6291
6312
  """List available voices."""
6292
6313
  json_mode = getattr(args, 'json', False)
6293
6314
 
6294
- from .voiceclone import is_runpod_backend, list_voices_runpod, get_tts_url
6295
6315
  import requests
6296
6316
 
6317
+ from .voiceclone import get_tts_url, is_runpod_backend, list_voices_runpod
6318
+
6297
6319
  if is_runpod_backend():
6298
6320
  success, result = list_voices_runpod()
6299
6321
  if success:
@@ -7754,22 +7776,16 @@ def cmd_ensure(args) -> int:
7754
7776
  10. Handle retries on failure
7755
7777
  """
7756
7778
  from .completion import (
7757
- CompletionTimeout,
7758
- generate_summary_filename,
7759
7779
  get_summary_prompt,
7760
- status_to_exit_code,
7761
7780
  )
7762
7781
  from .locking import LockConflict, LockTimeout, session_lock
7763
7782
  from .tasks import (
7764
- PreCommandError,
7765
7783
  TaskNotFound,
7766
7784
  TaskValidationError,
7767
7785
  load_task,
7768
- run_post_command,
7769
- run_pre_command,
7770
7786
  validate_task,
7771
7787
  )
7772
- from .templating import TemplateContext, TemplateError, expand_all, preview_template
7788
+ from .templating import TemplateContext, preview_template
7773
7789
 
7774
7790
  session_name = args.session
7775
7791
  task_name = args.task
@@ -8109,7 +8125,7 @@ def _run_ensure_task(args, session, task, ctx, shell, project_path, json_mode) -
8109
8125
  capture_output=True, text=True,
8110
8126
  )
8111
8127
  if fork_result.returncode != 0 and not json_mode:
8112
- print(f"Warning: context fork failed, starting fresh session")
8128
+ print("Warning: context fork failed, starting fresh session")
8113
8129
  elif not json_mode:
8114
8130
  print(f"Warning: starting_session '{task.starting_session}' not found, starting fresh")
8115
8131
 
@@ -8813,10 +8829,9 @@ def cmd_scheduler_board(args) -> int:
8813
8829
 
8814
8830
  def cmd_scheduler_run(args) -> int:
8815
8831
  """Force-run a specific task now."""
8816
- from .scheduler import _render_workflow_inputs, dispatch_task, load_board, save_board
8832
+ from .scheduler import dispatch_task, load_board, save_board
8817
8833
 
8818
8834
  json_mode = getattr(args, 'json', False)
8819
- dry_run = getattr(args, 'dry_run', False)
8820
8835
  name = args.name
8821
8836
 
8822
8837
  try:
@@ -8830,40 +8845,6 @@ def cmd_scheduler_run(args) -> int:
8830
8845
  f"Task '{name}' not found in board. Available: {', '.join(board.tasks.keys())}",
8831
8846
  )
8832
8847
 
8833
- task = board.tasks[name]
8834
-
8835
- if dry_run:
8836
- if not task.workflow:
8837
- return _output_result(
8838
- False, json_mode,
8839
- f"--dry-run only applies to workflow tasks; '{name}' runs via ensure.",
8840
- )
8841
- from agentwire.workflows.definitions import resolve_workflow
8842
- from agentwire.workflows.runner import run_workflow
8843
- try:
8844
- wf = resolve_workflow(task.workflow)
8845
- except Exception as e:
8846
- return _output_result(False, json_mode, f"Could not load workflow '{task.workflow}': {e}")
8847
- rendered_inputs = _render_workflow_inputs(task.inputs, task)
8848
- run = run_workflow(wf, runs_dir=None, inputs=rendered_inputs, dry_run=True)
8849
- if json_mode:
8850
- _output_json({
8851
- "success": True,
8852
- "task": name,
8853
- "dry_run": True,
8854
- "workflow": wf.name,
8855
- "inputs": rendered_inputs,
8856
- "nodes": [r.node_id for r in run.node_results],
8857
- "status": run.status,
8858
- })
8859
- return 0
8860
- print(f"Dry-run: {name} → workflow '{wf.name}'")
8861
- if rendered_inputs:
8862
- print(f" inputs: {rendered_inputs}")
8863
- for r in run.node_results:
8864
- print(f" - {r.node_id}: {r.final_text}")
8865
- return 0
8866
-
8867
8848
  if not json_mode:
8868
8849
  print(f"Running: {name}")
8869
8850
 
@@ -8946,7 +8927,6 @@ def cmd_scheduler_history(args) -> int:
8946
8927
  "last_status": state.last_status,
8947
8928
  "last_duration": state.last_duration,
8948
8929
  "run_count": state.run_count,
8949
- "workflow": (task.workflow if task else "") or None,
8950
8930
  })
8951
8931
  _output_json({"success": True, "history": history})
8952
8932
  return 0
@@ -8972,8 +8952,8 @@ def cmd_scheduler_history(args) -> int:
8972
8952
 
8973
8953
  def cmd_scheduler_report(args) -> int:
8974
8954
  """Generate a morning report HTML artifact of recent task runs."""
8975
- import re as _re
8976
8955
  from html import escape as html_escape
8956
+
8977
8957
  from .scheduler import _parse_duration, format_interval, load_board, read_events
8978
8958
 
8979
8959
  json_mode = getattr(args, 'json', False)
@@ -9045,38 +9025,11 @@ def cmd_scheduler_report(args) -> int:
9045
9025
  color = colors.get(status, "#78909c")
9046
9026
  return f'<span style="background:{color};color:#fff;padding:2px 8px;border-radius:12px;font-size:0.85em">{status}</span>'
9047
9027
 
9048
- def node_badges(nodes: list) -> str:
9049
- if not nodes:
9050
- return ""
9051
- node_colors = {
9052
- "success": "#00c853",
9053
- "failure": "#ff5252",
9054
- "timeout": "#ff7043",
9055
- "skipped": "#78909c",
9056
- }
9057
- pieces = []
9058
- for n in nodes:
9059
- nid = html_escape(str(n.get("id", "?")))
9060
- nstatus = str(n.get("status", "?"))
9061
- color = node_colors.get(nstatus, "#556")
9062
- pieces.append(
9063
- f'<span style="background:{color};color:#fff;padding:1px 6px;border-radius:8px;font-size:0.75em;margin-right:3px">{nid}</span>'
9064
- )
9065
- return "".join(pieces)
9066
-
9067
9028
  rows_html = ""
9068
9029
  for r in runs:
9069
9030
  duration_str = format_interval(r["duration"]) if r["duration"] else "-"
9070
9031
  pr_link = f'<a href="{r["pr_url"]}" target="_blank" style="color:#00d4ff">{r["pr_url"][:40]}...</a>' if r.get("pr_url") else "-"
9071
- branch_col = ""
9072
- if r.get("workflow"):
9073
- wf_label = html_escape(r["workflow"])
9074
- run_id = html_escape(r.get("run_id", ""))
9075
- badges = node_badges(r["nodes"])
9076
- run_hint = f' <span style="color:#556;font-size:0.75em">({run_id[:20]}…)</span>' if run_id else ""
9077
- branch_col = f'<code style="font-size:0.85em">workflow:{wf_label}</code>{run_hint}<div style="margin-top:4px">{badges}</div>'
9078
- else:
9079
- branch_col = f'<code style="font-size:0.85em">{r.get("work_branch") or "-"}</code>'
9032
+ branch_col = f'<code style="font-size:0.85em">{r.get("work_branch") or "-"}</code>'
9080
9033
  summary_text = r["summary"][:120] if r["summary"] else "-"
9081
9034
  rows_html += f"""
9082
9035
  <tr>
@@ -9536,7 +9489,7 @@ def cmd_overnight_prepare(args) -> int:
9536
9489
  "status": item.status,
9537
9490
  })
9538
9491
  else:
9539
- print(f"Queued for overnight execution:")
9492
+ print("Queued for overnight execution:")
9540
9493
  print(f" ID: {item.id}")
9541
9494
  print(f" Session: {item.session}")
9542
9495
  print(f" Branch: {item.work_branch}")
@@ -9548,7 +9501,7 @@ def cmd_overnight_prepare(args) -> int:
9548
9501
 
9549
9502
  def cmd_overnight_list(args) -> int:
9550
9503
  """List overnight queue items."""
9551
- from .overnight import load_queue, load_done
9504
+ from .overnight import load_done, load_queue
9552
9505
 
9553
9506
  json_mode = getattr(args, "json", False)
9554
9507
  show_all = getattr(args, "all", False)
@@ -9587,7 +9540,7 @@ def cmd_overnight_list(args) -> int:
9587
9540
 
9588
9541
  def cmd_overnight_status(args) -> int:
9589
9542
  """Show overnight orchestrator state and queue summary."""
9590
- from .overnight import load_queue, read_live_state, in_overnight_window
9543
+ from .overnight import in_overnight_window, load_queue, read_live_state
9591
9544
 
9592
9545
  json_mode = getattr(args, "json", False)
9593
9546
 
@@ -9633,7 +9586,7 @@ def cmd_overnight_status(args) -> int:
9633
9586
 
9634
9587
  def cmd_overnight_cancel(args) -> int:
9635
9588
  """Cancel a queued overnight item."""
9636
- from .overnight import load_item, save_item, delete_item
9589
+ from .overnight import delete_item, load_item
9637
9590
 
9638
9591
  item_id = args.id
9639
9592
  json_mode = getattr(args, "json", False)
@@ -10209,70 +10162,6 @@ def main() -> int:
10209
10162
  )
10210
10163
  dev_parser.set_defaults(func=cmd_dev)
10211
10164
 
10212
- # === workflow command group ===
10213
- from agentwire.workflows.cli import (
10214
- cmd_workflow_history,
10215
- cmd_workflow_list,
10216
- cmd_workflow_run,
10217
- cmd_workflow_show,
10218
- cmd_workflow_validate,
10219
- )
10220
-
10221
- workflow_parser = subparsers.add_parser("workflow", help="Pi workflow engine")
10222
- workflow_subparsers = workflow_parser.add_subparsers(dest="workflow_command")
10223
-
10224
- wf_list = workflow_subparsers.add_parser("list", help="List discoverable workflows")
10225
- wf_list.add_argument("--json", action="store_true", help="Output as JSON")
10226
- wf_list.set_defaults(func=cmd_workflow_list)
10227
-
10228
- wf_validate = workflow_subparsers.add_parser(
10229
- "validate", help="Validate a workflow YAML without running it"
10230
- )
10231
- wf_validate.add_argument("workflow", help="Workflow name or path to YAML")
10232
- wf_validate.set_defaults(func=cmd_workflow_validate)
10233
-
10234
- wf_run = workflow_subparsers.add_parser("run", help="Execute a workflow")
10235
- wf_run.add_argument("workflow", help="Workflow name or path to YAML")
10236
- wf_run.add_argument(
10237
- "--input", action="append", metavar="KEY=VALUE",
10238
- help="Workflow input (repeatable). Overrides --input-file."
10239
- )
10240
- wf_run.add_argument(
10241
- "--input-file", metavar="PATH",
10242
- help="JSON file with inputs (object mapping name → value)"
10243
- )
10244
- wf_run.add_argument("--dry-run", action="store_true", help="Print plan without running")
10245
- wf_run.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
10246
- wf_run.add_argument("--json", action="store_true", help="Output as JSON")
10247
- wf_run.set_defaults(func=cmd_workflow_run)
10248
-
10249
- wf_history = workflow_subparsers.add_parser(
10250
- "history", help="List past workflow runs"
10251
- )
10252
- wf_history.add_argument(
10253
- "--workflow", metavar="NAME", help="Filter by workflow name"
10254
- )
10255
- wf_history.add_argument(
10256
- "--limit", type=int, default=20, help="Max runs to show (default: 20)"
10257
- )
10258
- wf_history.add_argument("--json", action="store_true", help="Output as JSON")
10259
- wf_history.set_defaults(func=cmd_workflow_history)
10260
-
10261
- wf_show = workflow_subparsers.add_parser(
10262
- "show", help="Inspect a past workflow run"
10263
- )
10264
- wf_show.add_argument("run_id", help="Run ID (from `workflow history`)")
10265
- wf_show.add_argument(
10266
- "--events", action="store_true",
10267
- help="Dump raw event JSONL for all nodes",
10268
- )
10269
- wf_show.add_argument(
10270
- "--node", metavar="ID",
10271
- help="Filter events to one node id (implies --events)",
10272
- )
10273
- wf_show.add_argument("--json", action="store_true", help="Output as JSON")
10274
- wf_show.set_defaults(func=cmd_workflow_show)
10275
-
10276
10165
  # === listen command group ===
10277
10166
  listen_parser = subparsers.add_parser("listen", help="Voice input recording")
10278
10167
  listen_parser.add_argument(
@@ -10738,8 +10627,6 @@ def main() -> int:
10738
10627
  sched_run = scheduler_subparsers.add_parser("run", help="Force-run a task now")
10739
10628
  sched_run.add_argument("name", help="Task name from board")
10740
10629
  sched_run.add_argument("--json", action="store_true", help="Output JSON")
10741
- sched_run.add_argument("--dry-run", action="store_true",
10742
- help="For workflow tasks: print the execution plan without running")
10743
10630
  sched_run.set_defaults(func=cmd_scheduler_run)
10744
10631
 
10745
10632
  # scheduler enable <name>
@@ -10782,6 +10669,95 @@ def main() -> int:
10782
10669
  sched_report.add_argument("--json", action="store_true", help="Output JSON")
10783
10670
  sched_report.set_defaults(func=cmd_scheduler_report)
10784
10671
 
10672
+ # === mission command group ===
10673
+ from .missions import cli as mission_cli
10674
+
10675
+ mission_parser = subparsers.add_parser(
10676
+ "mission",
10677
+ help="Manage agent-driven missions (issue→branch→draft PR cycles)",
10678
+ description=(
10679
+ "First-class auto-dispatcher: stateless orchestrators tick the GitHub "
10680
+ "issue board, spawn worker sessions in isolated worktrees, route PR "
10681
+ "feedback back, and gc when the PR closes. See docs/MISSIONS.md."
10682
+ ),
10683
+ )
10684
+ mission_subparsers = mission_parser.add_subparsers(dest="mission_command")
10685
+
10686
+ # mission list
10687
+ m_list = mission_subparsers.add_parser("list", help="List active workers + eligible issues")
10688
+ m_list.add_argument("--json", action="store_true", help="Output JSON")
10689
+ m_list.set_defaults(func=mission_cli.cmd_mission_list)
10690
+
10691
+ # mission show <N>
10692
+ m_show = mission_subparsers.add_parser("show", help="Show one issue + dispatch + PR state")
10693
+ m_show.add_argument("number", type=int, help="GitHub issue number")
10694
+ m_show.add_argument("--repo", required=True, help="Repo short name (from missions config)")
10695
+ m_show.add_argument("--json", action="store_true", help="Output JSON")
10696
+ m_show.set_defaults(func=mission_cli.cmd_mission_show)
10697
+
10698
+ # mission status
10699
+ m_status = mission_subparsers.add_parser("status", help="Per-repo summary of active + eligible")
10700
+ m_status.add_argument("--json", action="store_true", help="Output JSON")
10701
+ m_status.set_defaults(func=mission_cli.cmd_mission_status)
10702
+
10703
+ # mission spawn <N>
10704
+ m_spawn = mission_subparsers.add_parser(
10705
+ "spawn", help="Force-dispatch an issue, bypassing eligibility"
10706
+ )
10707
+ m_spawn.add_argument("number", type=int, help="GitHub issue number")
10708
+ m_spawn.add_argument("--repo", required=True, help="Repo short name")
10709
+ m_spawn.add_argument("--json", action="store_true", help="Output JSON")
10710
+ m_spawn.set_defaults(func=mission_cli.cmd_mission_spawn)
10711
+
10712
+ # mission stall <N>
10713
+ m_stall = mission_subparsers.add_parser("stall", help="Stop dispatch for an issue with a reason")
10714
+ m_stall.add_argument("number", type=int, help="GitHub issue number")
10715
+ m_stall.add_argument("--repo", required=True, help="Repo short name")
10716
+ m_stall.add_argument("--reason", required=True, help="Reason (posted as comment)")
10717
+ m_stall.add_argument("--json", action="store_true", help="Output JSON")
10718
+ m_stall.set_defaults(func=mission_cli.cmd_mission_stall)
10719
+
10720
+ # mission resume <N>
10721
+ m_resume = mission_subparsers.add_parser("resume", help="Re-enable an issue for dispatch")
10722
+ m_resume.add_argument("number", type=int, help="GitHub issue number")
10723
+ m_resume.add_argument("--repo", required=True, help="Repo short name")
10724
+ m_resume.add_argument("--json", action="store_true", help="Output JSON")
10725
+ m_resume.set_defaults(func=mission_cli.cmd_mission_resume)
10726
+
10727
+ # mission kill <N>
10728
+ m_kill = mission_subparsers.add_parser(
10729
+ "kill", help="Kill worker session + worktree (does NOT close the PR)"
10730
+ )
10731
+ m_kill.add_argument("number", type=int, help="GitHub issue number")
10732
+ m_kill.add_argument("--repo", required=True, help="Repo short name")
10733
+ m_kill.add_argument("--json", action="store_true", help="Output JSON")
10734
+ m_kill.set_defaults(func=mission_cli.cmd_mission_kill)
10735
+
10736
+ # mission gc
10737
+ m_gc = mission_subparsers.add_parser("gc", help="Reap sessions whose PR is merged/closed")
10738
+ m_gc.add_argument("--json", action="store_true", help="Output JSON")
10739
+ m_gc.set_defaults(func=mission_cli.cmd_mission_gc)
10740
+
10741
+ # mission tick
10742
+ m_tick = mission_subparsers.add_parser("tick", help="Run one dispatcher tick now")
10743
+ m_tick.add_argument("--json", action="store_true", help="Output JSON")
10744
+ m_tick.set_defaults(func=mission_cli.cmd_mission_tick)
10745
+
10746
+ # mission route-feedback
10747
+ m_route = mission_subparsers.add_parser(
10748
+ "route-feedback", help="Run one PR-feedback router tick now"
10749
+ )
10750
+ m_route.add_argument("--json", action="store_true", help="Output JSON")
10751
+ m_route.set_defaults(func=mission_cli.cmd_mission_route_feedback)
10752
+
10753
+ # mission init <repo>
10754
+ m_init = mission_subparsers.add_parser(
10755
+ "init", help="Create the agent-ready label on a repo (idempotent)"
10756
+ )
10757
+ m_init.add_argument("repo", help="Repo short name (from config) or owner/repo form")
10758
+ m_init.add_argument("--json", action="store_true", help="Output JSON")
10759
+ m_init.set_defaults(func=mission_cli.cmd_mission_init)
10760
+
10785
10761
  # === overnight command group ===
10786
10762
  overnight_parser = subparsers.add_parser(
10787
10763
  "overnight",
@@ -10918,6 +10894,10 @@ def main() -> int:
10918
10894
  scheduler_parser.print_help()
10919
10895
  return 0
10920
10896
 
10897
+ if args.command == "mission" and getattr(args, "mission_command", None) is None:
10898
+ mission_parser.print_help()
10899
+ return 0
10900
+
10921
10901
  if args.command == "overnight" and getattr(args, "overnight_command", None) is None:
10922
10902
  overnight_parser.print_help()
10923
10903
  return 0