ctrlrelay 0.16.0__tar.gz → 0.16.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 (187) hide show
  1. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/CHANGELOG.md +21 -1
  2. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/PKG-INFO +5 -5
  3. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/README.md +4 -4
  4. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/SECURITY.md +1 -1
  5. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/cli.md +2 -2
  6. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/configuration.md +2 -2
  7. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/development.md +2 -2
  8. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/getting-started.md +4 -4
  9. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/index.md +2 -2
  10. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/operations.md +1 -1
  11. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/pyproject.toml +1 -1
  12. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/cli.py +4 -0
  13. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/systemd/bridge.service.template +1 -1
  14. ctrlrelay-0.16.1/tests/test_bridge_start_command.py +63 -0
  15. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_install.py +11 -0
  16. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  17. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  18. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  19. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/dependabot.yml +0 -0
  20. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/workflows/build.yml +0 -0
  21. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/workflows/cla.yml +0 -0
  22. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/workflows/pages.yml +0 -0
  23. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/workflows/publish.yml +0 -0
  24. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.github/workflows/test.yml +0 -0
  25. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/.gitignore +0 -0
  26. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/CODE_OF_CONDUCT.md +0 -0
  27. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/CONTRIBUTING.md +0 -0
  28. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/LICENSE +0 -0
  29. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/config/orchestrator.yaml.example +0 -0
  30. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/Gemfile +0 -0
  31. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/_config.yml +0 -0
  32. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/adding-a-machine.md +0 -0
  33. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/architecture.md +0 -0
  34. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/bridge.md +0 -0
  35. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/feedback-loop.md +0 -0
  36. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/personalization.md +0 -0
  37. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/superpowers/plans/2026-10-30-status-page.md +0 -0
  38. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/docs/superpowers/specs/2026-10-30-status-page-design.md +0 -0
  39. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/__init__.py +0 -0
  40. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/__init__.py +0 -0
  41. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/__main__.py +0 -0
  42. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/factory.py +0 -0
  43. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/handler.py +0 -0
  44. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/mattermost_handler.py +0 -0
  45. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/node_tag.py +0 -0
  46. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/protocol.py +0 -0
  47. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/server.py +0 -0
  48. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/bridge/telegram_handler.py +0 -0
  49. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/__init__.py +0 -0
  50. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/agent_env.py +0 -0
  51. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/archived.py +0 -0
  52. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/audit.py +0 -0
  53. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/binaries.py +0 -0
  54. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/checkpoint.py +0 -0
  55. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/claims.py +0 -0
  56. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/code_review.py +0 -0
  57. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/config.py +0 -0
  58. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/dispatch_health.py +0 -0
  59. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/dispatcher.py +0 -0
  60. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/events.py +0 -0
  61. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/github.py +0 -0
  62. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/github_budget.py +0 -0
  63. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/heartbeat.py +0 -0
  64. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/job_claims.py +0 -0
  65. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/network.py +0 -0
  66. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/node_check.py +0 -0
  67. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/obs.py +0 -0
  68. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/poller.py +0 -0
  69. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/pr_verifier.py +0 -0
  70. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/pr_watcher.py +0 -0
  71. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/publish.py +0 -0
  72. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/question_expiry.py +0 -0
  73. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/redact.py +0 -0
  74. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/scheduler.py +0 -0
  75. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/state.py +0 -0
  76. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/usage.py +0 -0
  77. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/core/worktree.py +0 -0
  78. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/dashboard/__init__.py +0 -0
  79. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/dashboard/client.py +0 -0
  80. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/gh_protocol.py +0 -0
  81. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/install.py +0 -0
  82. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/personalization/__init__.py +0 -0
  83. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/personalization/manager.py +0 -0
  84. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/personalization/paths.py +0 -0
  85. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/pipelines/__init__.py +0 -0
  86. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/pipelines/base.py +0 -0
  87. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/pipelines/dev.py +0 -0
  88. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/pipelines/post_merge.py +0 -0
  89. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/pipelines/secops.py +0 -0
  90. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/pipelines/task.py +0 -0
  91. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/setup.py +0 -0
  92. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/__init__.py +0 -0
  93. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/global-CLAUDE.md.snippet +0 -0
  94. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/launchd/__init__.py +0 -0
  95. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/launchd/bridge.plist.template +0 -0
  96. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/launchd/poller.plist.template +0 -0
  97. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/systemd/__init__.py +0 -0
  98. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/systemd/poller.service.template +0 -0
  99. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/templates/systemd/web.service.template +0 -0
  100. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/transports/__init__.py +0 -0
  101. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/transports/base.py +0 -0
  102. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/transports/file_mock.py +0 -0
  103. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/transports/socket_client.py +0 -0
  104. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/__init__.py +0 -0
  105. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/fleet.py +0 -0
  106. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/health.py +0 -0
  107. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/links.py +0 -0
  108. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/server.py +0 -0
  109. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/static/index.html +0 -0
  110. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/status.py +0 -0
  111. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/transcript.py +0 -0
  112. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/src/ctrlrelay/web/waiting.py +0 -0
  113. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/__init__.py +0 -0
  114. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/_publish_fakes.py +0 -0
  115. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/conftest.py +0 -0
  116. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/fixtures/gh_search_issues.json +0 -0
  117. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/fixtures/stream_json_rate_limit.jsonl +0 -0
  118. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/fixtures/transcript_sample.jsonl +0 -0
  119. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_agent_no_keys.py +0 -0
  120. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_agent_sandbox.py +0 -0
  121. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_archived.py +0 -0
  122. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_audit.py +0 -0
  123. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_binary_resolution.py +0 -0
  124. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_bridge_protocol.py +0 -0
  125. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_bridge_server.py +0 -0
  126. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_chat_machines.py +0 -0
  127. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_checkpoint.py +0 -0
  128. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_claim_reconciliation.py +0 -0
  129. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_cli_ci_wait.py +0 -0
  130. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_cli_dev.py +0 -0
  131. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_cli_repos.py +0 -0
  132. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_cli_secops.py +0 -0
  133. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_cli_start.py +0 -0
  134. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_cli_version.py +0 -0
  135. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_code_review.py +0 -0
  136. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_config.py +0 -0
  137. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_dashboard_client.py +0 -0
  138. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_dev_integration.py +0 -0
  139. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_dev_pipeline.py +0 -0
  140. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_dispatch_health.py +0 -0
  141. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_dispatch_outcome_hook.py +0 -0
  142. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_dispatcher.py +0 -0
  143. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_docs_site.py +0 -0
  144. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_event_emission.py +0 -0
  145. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_events.py +0 -0
  146. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_fleet.py +0 -0
  147. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_gh_protocol.py +0 -0
  148. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_github.py +0 -0
  149. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_github_budget.py +0 -0
  150. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_issue_outcome_announcement.py +0 -0
  151. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_job_claims.py +0 -0
  152. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_mattermost_handler.py +0 -0
  153. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_network.py +0 -0
  154. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_node_check.py +0 -0
  155. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_node_claims.py +0 -0
  156. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_notify_transport.py +0 -0
  157. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_obs.py +0 -0
  158. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_personalization.py +0 -0
  159. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_pipeline_base.py +0 -0
  160. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_poller.py +0 -0
  161. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_post_merge.py +0 -0
  162. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_pr_verifier.py +0 -0
  163. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_pr_watcher.py +0 -0
  164. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_pre_dispatch_retry.py +0 -0
  165. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_question_backoff.py +0 -0
  166. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_question_expiry.py +0 -0
  167. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_redact.py +0 -0
  168. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_relay_alert_off_lock.py +0 -0
  169. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_resume_prompt_contract.py +0 -0
  170. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_scheduler.py +0 -0
  171. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_secops_integration.py +0 -0
  172. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_secops_pipeline.py +0 -0
  173. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_setup.py +0 -0
  174. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_state.py +0 -0
  175. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_task_pipeline.py +0 -0
  176. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_telegram_handler.py +0 -0
  177. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_transport.py +0 -0
  178. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_transport_resolution.py +0 -0
  179. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_unreviewed_pr_announcement.py +0 -0
  180. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_usage.py +0 -0
  181. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_web_health.py +0 -0
  182. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_web_links.py +0 -0
  183. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_web_server.py +0 -0
  184. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_web_status.py +0 -0
  185. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_web_transcript.py +0 -0
  186. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_web_waiting.py +0 -0
  187. {ctrlrelay-0.16.0 → ctrlrelay-0.16.1}/tests/test_worktree.py +0 -0
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.16.1] - 2026-11-01
11
+
12
+ Fixes the chat bridge, which did not start on 0.16.0. **No config edit is
13
+ required.** If you upgraded to 0.16.0, upgrade to this.
14
+
15
+ ### Fixed
16
+
17
+ - `ctrlrelay bridge start` (what the bridge service runs) exited at startup
18
+ on 0.16.0 with `BridgeServer.__init__() missing 1 required keyword-only
19
+ argument: 'node'`, for Telegram and Mattermost alike, so chat questions
20
+ and answers stopped. It now passes the machine's name and the shared
21
+ setting, like `python -m ctrlrelay.bridge` (#265)
22
+
23
+ ### Changed
24
+
25
+ - The bridge's systemd unit is described as "ctrlrelay chat bridge
26
+ (Telegram or Mattermost)", and the docs call it the chat bridge. An
27
+ installed unit keeps its old description until it is re-rendered (#266)
28
+
10
29
  ## [0.16.0] - 2026-11-01
11
30
 
12
31
  Several machines can now run ctrlrelay on one GitHub account, each claiming
@@ -1957,7 +1976,8 @@ pipeline).
1957
1976
  per-phase implementation plans (Phase 0 through Phase 4).
1958
1977
  - `docs/Claude_Code_Project_Guide.md` — project development guide.
1959
1978
 
1960
- [Unreleased]: https://github.com/AInvirion/ctrlrelay/compare/v0.16.0...HEAD
1979
+ [Unreleased]: https://github.com/AInvirion/ctrlrelay/compare/v0.16.1...HEAD
1980
+ [0.16.1]: https://github.com/AInvirion/ctrlrelay/compare/v0.16.0...v0.16.1
1961
1981
  [0.16.0]: https://github.com/AInvirion/ctrlrelay/compare/v0.15.0...v0.16.0
1962
1982
  [0.15.0]: https://github.com/AInvirion/ctrlrelay/compare/v0.14.0...v0.15.0
1963
1983
  [0.14.0]: https://github.com/AInvirion/ctrlrelay/compare/v0.13.0...v0.14.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ctrlrelay
3
- Version: 0.16.0
3
+ Version: 0.16.1
4
4
  Summary: Local-first orchestrator for headless coding agents across multiple GitHub repos
5
5
  Project-URL: Homepage, https://github.com/AInvirion/ctrlrelay
6
6
  Project-URL: Documentation, https://ainvirion.github.io/ctrlrelay/
@@ -128,11 +128,11 @@ are on the roadmap (see [Roadmap](#roadmap)).
128
128
  new issue │ │ blocked session
129
129
  │ │
130
130
  ┌──────────▼──┐ ┌─▼───────────────────┐
131
- │ dev pipeline│ │ Telegram bridge │
132
- │ in worktree │ │ (socket ↔ bot API) │
131
+ │ dev pipeline│ │ chat bridge │
132
+ │ in worktree │ │ (socket ↔ chat API) │
133
133
  │ agent CLI │ └──────────┬──────────┘
134
134
  └──────┬──────┘ │
135
- │ PR opened │ DM you
135
+ │ PR opened │ asks you
136
136
  ▼ ▼
137
137
  ┌────────────┐ ┌─────────┐
138
138
  │ PR watcher │ │ You │
@@ -207,7 +207,7 @@ Run as a supervised daemon (launchd on macOS / systemd on Linux) — see
207
207
 
208
208
  - [Getting started][docs-start]
209
209
  - [Configuration][docs-config]
210
- - [Telegram bridge][docs-bridge]
210
+ - [Chat bridge (Telegram or Mattermost)][docs-bridge]
211
211
  - [Feedback loop][docs-feedback]
212
212
  - [CLI reference][docs-cli]
213
213
  - [Operations (launchd / systemd / scheduled jobs)][ops-docs]
@@ -87,11 +87,11 @@ are on the roadmap (see [Roadmap](#roadmap)).
87
87
  new issue │ │ blocked session
88
88
  │ │
89
89
  ┌──────────▼──┐ ┌─▼───────────────────┐
90
- │ dev pipeline│ │ Telegram bridge │
91
- │ in worktree │ │ (socket ↔ bot API) │
90
+ │ dev pipeline│ │ chat bridge │
91
+ │ in worktree │ │ (socket ↔ chat API) │
92
92
  │ agent CLI │ └──────────┬──────────┘
93
93
  └──────┬──────┘ │
94
- │ PR opened │ DM you
94
+ │ PR opened │ asks you
95
95
  ▼ ▼
96
96
  ┌────────────┐ ┌─────────┐
97
97
  │ PR watcher │ │ You │
@@ -166,7 +166,7 @@ Run as a supervised daemon (launchd on macOS / systemd on Linux) — see
166
166
 
167
167
  - [Getting started][docs-start]
168
168
  - [Configuration][docs-config]
169
- - [Telegram bridge][docs-bridge]
169
+ - [Chat bridge (Telegram or Mattermost)][docs-bridge]
170
170
  - [Feedback loop][docs-feedback]
171
171
  - [CLI reference][docs-cli]
172
172
  - [Operations (launchd / systemd / scheduled jobs)][ops-docs]
@@ -25,7 +25,7 @@ mitigation within **14 days** for high-severity issues.
25
25
  In-scope:
26
26
 
27
27
  - The `ctrlrelay` CLI and its pipelines (`dev`, `secops`, scheduled jobs).
28
- - The Telegram bridge and socket transport.
28
+ - The chat bridge (Telegram or Mattermost) and socket transport.
29
29
  - Anything in `src/` and `config/`.
30
30
 
31
31
  Out-of-scope:
@@ -27,7 +27,7 @@ ctrlrelay [--version] <command> ...
27
27
  | `ctrlrelay status` | Show active locks and the 5 most-recent sessions. |
28
28
  | `ctrlrelay config ...` | Configuration helpers. |
29
29
  | `ctrlrelay skills ...` | Skill discovery / audit. |
30
- | `ctrlrelay bridge ...` | Manage the Telegram bridge daemon. |
30
+ | `ctrlrelay bridge ...` | Manage the chat bridge daemon (Telegram or Mattermost). |
31
31
  | `ctrlrelay run ...` | Run a pipeline interactively. |
32
32
  | `ctrlrelay ci ...` | CI helpers used by the dev pipeline prompt. |
33
33
  | `ctrlrelay poller ...` | Manage the issue-poller daemon. |
@@ -128,7 +128,7 @@ Lists discovered skills as a table (name, path).
128
128
 
129
129
  ## `ctrlrelay bridge`
130
130
 
131
- See [Telegram bridge]({{ '/bridge/' | relative_url }}) for the full setup walkthrough.
131
+ See [Chat bridge]({{ '/bridge/' | relative_url }}) for the full setup walkthrough.
132
132
 
133
133
  ### `bridge start`
134
134
 
@@ -302,7 +302,7 @@ transport:
302
302
  | Key | Type | Required | Default | Description |
303
303
  |---|---|---|---|---|
304
304
  | `type` | enum | no | `"file_mock"` | One of `"telegram"`, `"mattermost"`, `"file_mock"`. |
305
- | `telegram` | object | required when `type=telegram` | — | Telegram bridge settings — see below. |
305
+ | `telegram` | object | required when `type=telegram` | — | Telegram settings — see below. |
306
306
  | `mattermost` | object | required when `type=mattermost` | — | Mattermost bridge settings — see below. |
307
307
  | `file_mock` | object | required when `type=file_mock` | — | Local-file fake transport, used for tests/dev. |
308
308
 
@@ -321,7 +321,7 @@ reach anybody.
321
321
  | `question_ttl_seconds` | int | `172800` (48h) | How long an **unanswered** question stays routable before it is retired. Minimum `3600`. Without a ceiling those rows never die — a question whose PR was merged by hand weeks ago stays a live target for an orphan reply. The hourly `question_expiry_sweeper` also retires a question early once every issue/PR it cites is closed or merged. |
322
322
  | `question_retention_days` | int | `90` | How long a **finished** question (expired, or answered and resumed) is kept before the hourly sweeper deletes it. Minimum `1`. Open questions are never deleted. The kept history is what lets a re-asked question be marked as a repeat. |
323
323
 
324
- See [Telegram bridge]({{ '/bridge/' | relative_url }}) for the full setup walkthrough.
324
+ See [Chat bridge]({{ '/bridge/' | relative_url }}) for the full setup walkthrough.
325
325
 
326
326
  ### transport.mattermost
327
327
 
@@ -52,7 +52,7 @@ pytest --cov=src/ctrlrelay --cov-report=term-missing
52
52
  `pyproject.toml` sets `pythonpath = ["src"]` and `testpaths = ["tests"]` so
53
53
  pytest finds the package without an extra install step on a fresh checkout.
54
54
 
55
- The Telegram bridge tests stub the network — no real bot token is required to
55
+ The chat bridge tests stub the network — no real bot token is required to
56
56
  run the suite. Tests that exercise the dev / secops pipelines use the
57
57
  `file_mock` transport so they stay hermetic.
58
58
 
@@ -112,7 +112,7 @@ ctrlrelay/
112
112
  │ ├── cli.py # Typer CLI entry point
113
113
  │ ├── core/ # Dispatcher, worktree, state, config, ...
114
114
  │ ├── pipelines/ # dev, secops, post_merge
115
- │ ├── bridge/ # Telegram bridge daemon
115
+ │ ├── bridge/ # chat bridge daemon (Telegram, Mattermost)
116
116
  │ ├── transports/ # SocketTransport, FileMockTransport
117
117
  │ └── dashboard/ # Optional dashboard push client
118
118
  ├── tests/ # pytest suites (one file per module)
@@ -24,7 +24,7 @@ and running the dev pipeline against a real GitHub issue. Allow about 15 minutes
24
24
  Optional:
25
25
 
26
26
  - [`uv`](https://github.com/astral-sh/uv) for faster installs.
27
- - A Telegram bot if you want the human-in-the-loop bridge — see [Telegram bridge]({{ '/bridge/' | relative_url }}).
27
+ - A Telegram bot or a Mattermost server if you want the human-in-the-loop bridge — see [Chat bridge]({{ '/bridge/' | relative_url }}).
28
28
 
29
29
  ## Install
30
30
 
@@ -127,8 +127,8 @@ What happens:
127
127
 
128
128
  If Claude blocks asking a question, the answer mechanism only works when a
129
129
  transport is connected. With `file_mock`, you'll see the question on the console
130
- but cannot resume. Switch to the Telegram transport to actually answer — see
131
- [Telegram bridge]({{ '/bridge/' | relative_url }}) and [Feedback loop]({{ '/feedback-loop/' | relative_url }}).
130
+ but cannot resume. Switch to the Telegram or Mattermost transport to actually
131
+ answer — see [Chat bridge]({{ '/bridge/' | relative_url }}) and [Feedback loop]({{ '/feedback-loop/' | relative_url }}).
132
132
 
133
133
  ## Your first poller tick
134
134
 
@@ -151,7 +151,7 @@ To run the poller as a long-lived background service, see [Operations]({{ '/oper
151
151
  ## Where to next
152
152
 
153
153
  - [Configuration]({{ '/configuration/' | relative_url }}) — every key in `orchestrator.yaml`.
154
- - [Telegram bridge]({{ '/bridge/' | relative_url }}) — how to set up the human-in-the-loop channel.
154
+ - [Chat bridge]({{ '/bridge/' | relative_url }}) — how to set up the human-in-the-loop channel.
155
155
  - [Feedback loop]({{ '/feedback-loop/' | relative_url }}) — what `BLOCKED_NEEDS_INPUT` actually does end-to-end.
156
156
  - [CLI reference]({{ '/cli/' | relative_url }}) — every subcommand and flag.
157
157
  - [Operations]({{ '/operations/' | relative_url }}) — running ctrlrelay as a service.
@@ -26,8 +26,8 @@ isolated git worktree, opens a PR, and asks you on Telegram when it gets stuck.
26
26
  write your first config, run the dev pipeline against an issue.
27
27
  - **[Configuration]({{ '/configuration/' | relative_url }})** — every key in
28
28
  `orchestrator.yaml`, with defaults and what they actually do.
29
- - **[Telegram bridge]({{ '/bridge/' | relative_url }})** — BotFather walkthrough,
30
- starting the bridge, troubleshooting Telegram delivery.
29
+ - **[Chat bridge]({{ '/bridge/' | relative_url }})** — setting up Telegram or
30
+ Mattermost, starting the bridge, troubleshooting delivery.
31
31
  - **[Feedback loop]({{ '/feedback-loop/' | relative_url }})** — how
32
32
  `BLOCKED_NEEDS_INPUT` checkpoints reach you and how your reply resumes the
33
33
  paused Claude session.
@@ -184,7 +184,7 @@ installer uses. Save under `~/.config/systemd/user/`.
184
184
 
185
185
  ```ini
186
186
  [Unit]
187
- Description=ctrlrelay Telegram bridge
187
+ Description=ctrlrelay chat bridge (Telegram or Mattermost)
188
188
  After=network-online.target
189
189
 
190
190
  [Service]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ctrlrelay"
3
- version = "0.16.0"
3
+ version = "0.16.1"
4
4
  description = "Local-first orchestrator for headless coding agents across multiple GitHub repos"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -1846,10 +1846,14 @@ def bridge_start(
1846
1846
  from ctrlrelay.core.state import StateDB
1847
1847
  state_db = StateDB(config.paths.state_db)
1848
1848
 
1849
+ # #248: this machine's name on every post, and whether other
1850
+ # machines read the same chat (Mattermost only).
1849
1851
  server = BridgeServer(
1850
1852
  socket_path=socket_path,
1851
1853
  handler=handler,
1852
1854
  state_db=state_db,
1855
+ node=config.node_id,
1856
+ shared=bool(getattr(chat_config, "shared", False)),
1853
1857
  )
1854
1858
 
1855
1859
  loop = asyncio.new_event_loop()
@@ -1,5 +1,5 @@
1
1
  [Unit]
2
- Description=ctrlrelay Telegram bridge
2
+ Description=ctrlrelay chat bridge (Telegram or Mattermost)
3
3
  After=network-online.target
4
4
 
5
5
  [Service]
@@ -0,0 +1,63 @@
1
+ """``ctrlrelay bridge start --foreground`` builds the bridge it is meant to.
2
+
3
+ 0.16.0 shipped with this command constructing ``BridgeServer`` without the
4
+ ``node`` argument #248 made required, so the bridge exited at startup on
5
+ every machine. The ``python -m ctrlrelay.bridge`` path had it; this one did
6
+ not, and nothing ran the command.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from pathlib import Path
12
+
13
+ import pytest
14
+ from typer.testing import CliRunner
15
+
16
+
17
+ @pytest.mark.parametrize("transport,shared", [
18
+ ("telegram", False),
19
+ ("mattermost", True),
20
+ ])
21
+ def test_bridge_start_names_this_machine(
22
+ tmp_path: Path, monkeypatch, transport: str, shared: bool,
23
+ ) -> None:
24
+ import ctrlrelay.bridge as bridge
25
+ from ctrlrelay.cli import app
26
+
27
+ built: dict = {}
28
+
29
+ class FakeServer:
30
+ def __init__(self, socket_path, handler, state_db=None, *, node, shared=False):
31
+ built.update(node=node, shared=shared)
32
+
33
+ async def start(self) -> None:
34
+ return None
35
+
36
+ async def stop(self) -> None:
37
+ return None
38
+
39
+ monkeypatch.setattr(bridge, "BridgeServer", FakeServer)
40
+ monkeypatch.setattr(bridge, "make_handler", lambda _t: object())
41
+ if transport == "telegram":
42
+ block = (
43
+ f'transport: {{type: telegram, telegram: {{bot_token_env: "T", '
44
+ f'chat_id: 1, socket_path: "{tmp_path}/b.sock"}}}}\n'
45
+ )
46
+ else:
47
+ block = (
48
+ f'transport: {{type: mattermost, mattermost: {{url: "https://chat.example.com", '
49
+ f'bot_token_env: "T", channel_id: "abcdefghijklmnopqrstuvwxyz", '
50
+ f'shared: true, socket_path: "{tmp_path}/b.sock"}}}}\n'
51
+ )
52
+ cfg = tmp_path / "orchestrator.yaml"
53
+ cfg.write_text(
54
+ 'version: "1"\nnode_id: "node-a"\n'
55
+ f'paths: {{state_db: "{tmp_path}/s.db", worktrees: "{tmp_path}/w", '
56
+ f'bare_repos: "{tmp_path}/r", contexts: "{tmp_path}/c", skills: "{tmp_path}/k"}}\n'
57
+ + block
58
+ )
59
+ result = CliRunner().invoke(
60
+ app, ["bridge", "start", "--foreground", "-c", str(cfg)],
61
+ )
62
+ assert result.exit_code == 0, result.output + repr(result.exception)
63
+ assert built == {"node": "node-a", "shared": shared}
@@ -352,3 +352,14 @@ class TestInstallCli:
352
352
  assert result.exit_code == 0, result.output
353
353
  assert (target_dir / "ctrlrelay-bridge.service").exists()
354
354
  assert (target_dir / "ctrlrelay-poller.service").exists()
355
+
356
+
357
+ def test_the_bridge_unit_names_the_chat_bridge_not_one_provider(tmp_path) -> None:
358
+ """The bridge serves Telegram or Mattermost; its unit says so."""
359
+ from ctrlrelay.install import render_systemd
360
+
361
+ [bridge] = [
362
+ u for u in render_systemd(workdir=tmp_path, target_dir=tmp_path)
363
+ if u.service == "bridge"
364
+ ]
365
+ assert "Description=ctrlrelay chat bridge (Telegram or Mattermost)" in bridge.content
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes