ctrlrelay 0.1.6__tar.gz → 0.1.7__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.
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/CHANGELOG.md +27 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/PKG-INFO +1 -1
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/pyproject.toml +1 -1
- ctrlrelay-0.1.7/src/ctrlrelay/__init__.py +33 -0
- ctrlrelay-0.1.7/tests/test_cli_version.py +49 -0
- ctrlrelay-0.1.6/src/ctrlrelay/__init__.py +0 -8
- ctrlrelay-0.1.6/tests/test_cli_version.py +0 -22
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/dependabot.yml +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/workflows/build.yml +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/workflows/cla.yml +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/workflows/pages.yml +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/workflows/publish.yml +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.github/workflows/test.yml +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/.gitignore +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/CODE_OF_CONDUCT.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/CONTRIBUTING.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/LICENSE +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/README.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/SECURITY.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/config/orchestrator.yaml.example +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/Gemfile +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/_config.yml +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/architecture.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/bridge.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/cli.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/configuration.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/development.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/feedback-loop.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/getting-started.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/index.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/docs/operations.md +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/bridge/__init__.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/bridge/__main__.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/bridge/protocol.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/bridge/server.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/bridge/telegram_handler.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/cli.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/__init__.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/audit.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/checkpoint.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/config.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/dispatcher.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/github.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/obs.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/poller.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/pr_verifier.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/pr_watcher.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/scheduler.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/state.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/core/worktree.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/dashboard/__init__.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/dashboard/client.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/pipelines/__init__.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/pipelines/base.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/pipelines/dev.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/pipelines/post_merge.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/pipelines/secops.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/transports/__init__.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/transports/base.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/transports/file_mock.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/src/ctrlrelay/transports/socket_client.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/__init__.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/conftest.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_audit.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_bridge_protocol.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_bridge_server.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_checkpoint.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_cli_ci_wait.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_cli_dev.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_cli_secops.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_cli_start.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_config.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_dashboard_client.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_dev_integration.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_dev_pipeline.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_dispatcher.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_docs_site.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_github.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_obs.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_pipeline_base.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_poller.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_post_merge.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_pr_verifier.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_pr_watcher.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_scheduler.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_secops_integration.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_secops_pipeline.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_state.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_telegram_handler.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_transport.py +0 -0
- {ctrlrelay-0.1.6 → ctrlrelay-0.1.7}/tests/test_worktree.py +0 -0
|
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.7] - 2026-04-20
|
|
11
|
+
|
|
12
|
+
Patch release. Fixes one drift bug in how the package reports its own
|
|
13
|
+
version — the `__version__` string was pinned to a literal in
|
|
14
|
+
`__init__.py` and never got bumped alongside releases, so `ctrlrelay
|
|
15
|
+
version` on an installed 0.1.6 wheel still reported `0.1.4`. No API
|
|
16
|
+
or behavior changes.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **`__version__` now derives from installed metadata** (`closes
|
|
21
|
+
#94`). `ctrlrelay.__version__` resolves via
|
|
22
|
+
`importlib.metadata.version("ctrlrelay")` at import time so it
|
|
23
|
+
tracks the installed wheel's `pyproject.toml` automatically.
|
|
24
|
+
Source-checkout pytest runs (where no dist-info exists because
|
|
25
|
+
`pythonpath = ["src"]` is the only mechanism putting the package on
|
|
26
|
+
`sys.path`) fall back to parsing the sibling `pyproject.toml` with
|
|
27
|
+
`tomllib` — so the drift-catcher test
|
|
28
|
+
(`test_version_matches_pyproject`) still sees a real version
|
|
29
|
+
instead of a `0.0.0+unknown` placeholder.
|
|
30
|
+
|
|
31
|
+
### Operator notes
|
|
32
|
+
|
|
33
|
+
- No migration or restart guidance. Upgrade via `uv tool upgrade
|
|
34
|
+
ctrlrelay` (or `pip install -U ctrlrelay`) and the next `ctrlrelay
|
|
35
|
+
version` will report `0.1.7`.
|
|
36
|
+
|
|
10
37
|
## [0.1.6] - 2026-04-20
|
|
11
38
|
|
|
12
39
|
The "pipeline reliability + operator control" release. Closes three
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ctrlrelay
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
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/
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""ctrlrelay: Local-first orchestrator for headless coding agents."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from ctrlrelay.core import checkpoint
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _resolve_version() -> str:
|
|
9
|
+
try:
|
|
10
|
+
return version("ctrlrelay")
|
|
11
|
+
except PackageNotFoundError:
|
|
12
|
+
# Source checkout with no installed dist-info — e.g. a bare
|
|
13
|
+
# `pytest tests/` with pyproject's `pythonpath = ["src"]` as the
|
|
14
|
+
# only mechanism putting the package on sys.path. Fall back to
|
|
15
|
+
# parsing pyproject.toml so the drift-catcher test still sees a
|
|
16
|
+
# real version instead of a placeholder.
|
|
17
|
+
import tomllib
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
pyproject = Path(__file__).resolve().parents[2] / "pyproject.toml"
|
|
21
|
+
if pyproject.is_file():
|
|
22
|
+
try:
|
|
23
|
+
with pyproject.open("rb") as f:
|
|
24
|
+
return tomllib.load(f)["project"]["version"]
|
|
25
|
+
except (OSError, KeyError, tomllib.TOMLDecodeError):
|
|
26
|
+
pass
|
|
27
|
+
return "0.0.0+unknown"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
__version__ = _resolve_version()
|
|
31
|
+
|
|
32
|
+
# Public API
|
|
33
|
+
__all__ = ["__version__", "checkpoint"]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Tests for the version command."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import tomllib
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from typer.testing import CliRunner
|
|
8
|
+
|
|
9
|
+
from ctrlrelay import __version__
|
|
10
|
+
from ctrlrelay.cli import app
|
|
11
|
+
|
|
12
|
+
runner = CliRunner()
|
|
13
|
+
|
|
14
|
+
SEMVER_RE = re.compile(r"^\d+\.\d+\.\d+([.\-+].+)?$")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestVersionCommand:
|
|
18
|
+
def test_version_command_succeeds(self) -> None:
|
|
19
|
+
"""ctrlrelay version should exit with code 0."""
|
|
20
|
+
result = runner.invoke(app, ["version"])
|
|
21
|
+
|
|
22
|
+
assert result.exit_code == 0
|
|
23
|
+
|
|
24
|
+
def test_version_command_prints_version(self) -> None:
|
|
25
|
+
"""ctrlrelay version should print the package version."""
|
|
26
|
+
result = runner.invoke(app, ["version"])
|
|
27
|
+
|
|
28
|
+
assert __version__ in result.output
|
|
29
|
+
|
|
30
|
+
def test_version_matches_semver_shape(self) -> None:
|
|
31
|
+
"""__version__ should look like a real version, not a literal placeholder."""
|
|
32
|
+
assert SEMVER_RE.match(__version__), (
|
|
33
|
+
f"__version__={__version__!r} does not match semver-like shape"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def test_version_matches_pyproject(self) -> None:
|
|
37
|
+
"""__version__ must match pyproject.toml so published wheels don't lie.
|
|
38
|
+
|
|
39
|
+
Catches the drift that caused issue #94: bumping pyproject.toml on each
|
|
40
|
+
release while forgetting to bump a hardcoded string in __init__.py.
|
|
41
|
+
"""
|
|
42
|
+
pyproject_path = Path(__file__).resolve().parents[1] / "pyproject.toml"
|
|
43
|
+
pyproject = tomllib.loads(pyproject_path.read_text())
|
|
44
|
+
expected = pyproject["project"]["version"]
|
|
45
|
+
|
|
46
|
+
assert __version__ == expected, (
|
|
47
|
+
f"__version__={__version__!r} diverges from pyproject.toml version "
|
|
48
|
+
f"{expected!r} — did a release bump one but not the other?"
|
|
49
|
+
)
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"""Tests for the version command."""
|
|
2
|
-
|
|
3
|
-
from typer.testing import CliRunner
|
|
4
|
-
|
|
5
|
-
from ctrlrelay import __version__
|
|
6
|
-
from ctrlrelay.cli import app
|
|
7
|
-
|
|
8
|
-
runner = CliRunner()
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class TestVersionCommand:
|
|
12
|
-
def test_version_command_succeeds(self) -> None:
|
|
13
|
-
"""ctrlrelay version should exit with code 0."""
|
|
14
|
-
result = runner.invoke(app, ["version"])
|
|
15
|
-
|
|
16
|
-
assert result.exit_code == 0
|
|
17
|
-
|
|
18
|
-
def test_version_command_prints_version(self) -> None:
|
|
19
|
-
"""ctrlrelay version should print the package version."""
|
|
20
|
-
result = runner.invoke(app, ["version"])
|
|
21
|
-
|
|
22
|
-
assert __version__ in result.output
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|