ctrlrelay 0.1.11__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/CHANGELOG.md +136 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/PKG-INFO +1 -1
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/operations.md +13 -8
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/pyproject.toml +1 -1
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/cli.py +503 -25
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/config.py +17 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/github.py +35 -6
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/pr_verifier.py +67 -14
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/state.py +150 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/worktree.py +176 -12
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/pipelines/dev.py +457 -51
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/pipelines/post_merge.py +150 -18
- ctrlrelay-0.2.0/tests/test_cli_repos.py +268 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_dev_integration.py +148 -7
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_dev_pipeline.py +574 -11
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_github.py +39 -0
- ctrlrelay-0.2.0/tests/test_post_merge.py +1312 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_pr_verifier.py +147 -0
- ctrlrelay-0.2.0/tests/test_state.py +594 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_worktree.py +485 -12
- ctrlrelay-0.1.11/tests/test_post_merge.py +0 -666
- ctrlrelay-0.1.11/tests/test_state.py +0 -271
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/dependabot.yml +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/workflows/build.yml +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/workflows/cla.yml +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/workflows/pages.yml +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/workflows/publish.yml +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.github/workflows/test.yml +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/.gitignore +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/CODE_OF_CONDUCT.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/CONTRIBUTING.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/LICENSE +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/README.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/SECURITY.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/config/orchestrator.yaml.example +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/Gemfile +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/_config.yml +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/architecture.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/bridge.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/cli.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/configuration.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/development.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/feedback-loop.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/getting-started.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/docs/index.md +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/__init__.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/bridge/__init__.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/bridge/__main__.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/bridge/protocol.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/bridge/server.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/bridge/telegram_handler.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/__init__.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/audit.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/checkpoint.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/dispatcher.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/obs.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/poller.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/pr_watcher.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/core/scheduler.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/dashboard/__init__.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/dashboard/client.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/pipelines/__init__.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/pipelines/base.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/pipelines/secops.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/pipelines/task.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/transports/__init__.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/transports/base.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/transports/file_mock.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/src/ctrlrelay/transports/socket_client.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/__init__.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/conftest.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_audit.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_bridge_protocol.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_bridge_server.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_checkpoint.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_cli_ci_wait.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_cli_dev.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_cli_secops.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_cli_start.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_cli_version.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_config.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_dashboard_client.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_dispatcher.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_docs_site.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_obs.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_pipeline_base.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_poller.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_pr_watcher.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_scheduler.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_secops_integration.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_secops_pipeline.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_task_pipeline.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_telegram_handler.py +0 -0
- {ctrlrelay-0.1.11 → ctrlrelay-0.2.0}/tests/test_transport.py +0 -0
|
@@ -7,6 +7,142 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.0] - 2026-04-27
|
|
11
|
+
|
|
12
|
+
Minor release. Adds bulk repo operations driven by
|
|
13
|
+
`config/orchestrator.yaml`, plus a batch of dev-pipeline correctness
|
|
14
|
+
fixes (worktree ownership, PR-CI lock contention, watcher
|
|
15
|
+
persistence) and a docs cleanup.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **`ctrlrelay repos clone-all/pull-all/status`** (closes #117).
|
|
20
|
+
Stand up an isolated workspace from the orchestrator manifest in
|
|
21
|
+
one command:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
ctrlrelay repos clone-all ~/code/myproject [--filter ORG] [--dry-run]
|
|
25
|
+
ctrlrelay repos pull-all ~/code/myproject [--filter ORG] [--dry-run]
|
|
26
|
+
ctrlrelay repos status ~/code/myproject [--filter ORG]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Each repo lands at `DEST/<org>/<repo>` derived from the `name:`
|
|
30
|
+
field; remote is `git@github.com:{name}.git`. The configured
|
|
31
|
+
`local_path` is ignored when `DEST` is passed, so existing
|
|
32
|
+
`~/Projects/...` checkouts stay untouched. Replaces the legacy
|
|
33
|
+
`bkp/sync` shell scripts that broke when the manifest was
|
|
34
|
+
archived during the rewrite.
|
|
35
|
+
- **`RepoConfig.name` validator.** Repo names are now validated
|
|
36
|
+
against `^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$` at config load.
|
|
37
|
+
Rejects `..`, extra slashes, and shell metacharacters before they
|
|
38
|
+
reach a clone target — defense in depth for the new bulk
|
|
39
|
+
commands.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **Watchers persist across poller restarts** (closes #57). Adds
|
|
44
|
+
a `pr_watches` state-db table so in-flight merge watchers
|
|
45
|
+
survive launchd kickstart, crashes, and reboots. Before this,
|
|
46
|
+
any PR sitting in review across a poller restart silently lost
|
|
47
|
+
its post-merge automation (issue auto-close + Telegram
|
|
48
|
+
notification) for the rest of its 7-day window. The poller now
|
|
49
|
+
rehydrates surviving rows on startup and spawns one watcher
|
|
50
|
+
task per row.
|
|
51
|
+
- **Repo lock released during PR CI verification** (closes #29).
|
|
52
|
+
`run_dev_issue` used to hold the per-repo lock through the
|
|
53
|
+
`PRVerifier.wait_for_checks` polling window — a pure `gh` poll
|
|
54
|
+
that can run for up to 30 minutes — which made every peer
|
|
55
|
+
session targeting the same repo report "Repository locked by
|
|
56
|
+
another session" while no git work was in flight. The lock is
|
|
57
|
+
now released before `verify`, reacquired only if a `request_fix`
|
|
58
|
+
follow-up needs to spawn an agent against the worktree, and
|
|
59
|
+
released again on cleanup. `CancelledError` during the unlocked
|
|
60
|
+
window propagates without leaking a lock row.
|
|
61
|
+
- **Branch ownership signal survives delete+recreate** (closes #51).
|
|
62
|
+
`create_worktree_with_new_branch` now returns
|
|
63
|
+
`(path, created_fresh)` so the caller knows whether THIS session
|
|
64
|
+
created the branch (fresh from default, or via the stale-merged
|
|
65
|
+
delete+recreate path). Before #51, `run_dev_issue` snapshotted
|
|
66
|
+
`branch_preexisted` BEFORE the call; the snapshot went stale the
|
|
67
|
+
moment the helper detected a fully-merged local branch and
|
|
68
|
+
deleted+recreated it. A FAILED cleanup would then skip
|
|
69
|
+
`delete_branch` and leak partial commits into the next retry.
|
|
70
|
+
- **Refuse reuse when branch still backs an open PR** (closes #52).
|
|
71
|
+
`create_worktree_with_new_branch` now probes GitHub (via
|
|
72
|
+
`GitHubCLI.list_prs(head=...)`) before reusing an existing local
|
|
73
|
+
branch. If an open PR still backs it (prior DONE session whose
|
|
74
|
+
PR is unmerged, or any external source), raises `WorktreeError`
|
|
75
|
+
with the PR number and a concrete operator action instead of
|
|
76
|
+
silently hijacking the reviewer's already-reviewed branch or
|
|
77
|
+
tripping "A pull request already exists" at `gh pr create`.
|
|
78
|
+
- **`pull-all` checks subprocess return codes.** `git status`
|
|
79
|
+
failure no longer treats an empty stdout as "clean" and proceeds
|
|
80
|
+
to pull a corrupt repo. `git fetch` failure on a dirty tree is
|
|
81
|
+
now reported as `failed` instead of silently being counted as
|
|
82
|
+
`dirty — fetched only`.
|
|
83
|
+
- **`status` no longer crashes on edge cases.** `git rev-list`
|
|
84
|
+
parsing wrapped in a helper that returns 0 on any non-zero
|
|
85
|
+
return code or non-numeric output, instead of raising on
|
|
86
|
+
`int(ahead)`.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
|
|
90
|
+
- **Docs use `com.example.*` placeholder for launchd labels**
|
|
91
|
+
(closes #23). The launchd plist examples and `launchctl`
|
|
92
|
+
commands no longer hard-code `com.ainvirion.ctrlrelay-*` as the
|
|
93
|
+
job label. Anyone copying the docs verbatim picked up that label
|
|
94
|
+
too, which is fine until two forks of the project share a
|
|
95
|
+
machine. Swapped to `com.example.ctrlrelay-*` with a one-line
|
|
96
|
+
note directing readers to use a reverse-DNS prefix they own.
|
|
97
|
+
|
|
98
|
+
### Operator notes
|
|
99
|
+
|
|
100
|
+
- Upgrade via `uv tool install ctrlrelay@latest --force` and
|
|
101
|
+
restart poller + bridge.
|
|
102
|
+
No schema or config changes — the new `pr_watches` state-db
|
|
103
|
+
table is created idempotently on first start.
|
|
104
|
+
- New workflow: `ctrlrelay repos clone-all ~/code/myproject` to
|
|
105
|
+
stand up a fresh workspace, `repos pull-all` to refresh it.
|
|
106
|
+
Existing `~/Projects/...` checkouts are not touched.
|
|
107
|
+
|
|
108
|
+
## [0.1.12] - 2026-04-22
|
|
109
|
+
|
|
110
|
+
Patch release. Closes #90 — three related polish items on the
|
|
111
|
+
`ctrlrelay ci wait` helper / `PRVerifier.wait_for_checks` polling
|
|
112
|
+
loop, plus a fail-closed safety fix caught by codex on the PR.
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
|
|
116
|
+
- **Short timeouts now honored.** `wait_for_checks` used to block
|
|
117
|
+
the full `poll_interval` before noticing a shorter `--timeout`
|
|
118
|
+
budget was over. Repro: `ctrlrelay ci wait --timeout 1
|
|
119
|
+
--interval 15` returned in ~15s instead of ~1s. Now the per-
|
|
120
|
+
iteration sleep is capped at the remaining wall-clock deadline.
|
|
121
|
+
- **Transient `gh` errors no longer leak as tracebacks.**
|
|
122
|
+
`asyncio.TimeoutError` from a hung `gh` subprocess used to
|
|
123
|
+
surface as an unhandled Python stack trace. The polling loop now
|
|
124
|
+
catches it (and `GitHubError`) inside the loop, logs
|
|
125
|
+
`pr_verifier.transient_gh_error`, and retries the next tick.
|
|
126
|
+
- **Persistent `gh` failures now fail closed** (codex P1). If
|
|
127
|
+
every poll errors up to the deadline and no successful read ever
|
|
128
|
+
happened, `wait_for_checks` raises the last transient error
|
|
129
|
+
instead of returning `[]`. Without this, the empty list was
|
|
130
|
+
misread by callers as "no CI configured" and silently
|
|
131
|
+
greenlighted PRs while GitHub was down.
|
|
132
|
+
- **Wall-clock deadline.** Switched from accumulated-sleep elapsed
|
|
133
|
+
tracking to a monotonic `loop.time()` deadline, which is correct
|
|
134
|
+
even with `poll_interval=0` and unaffected by wall-clock jumps.
|
|
135
|
+
|
|
136
|
+
### Operator notes
|
|
137
|
+
|
|
138
|
+
- Upgrade via `uv tool install ctrlrelay@latest --force` and
|
|
139
|
+
restart poller + bridge. No schema or config changes.
|
|
140
|
+
- `ctrlrelay ci wait --pr <N> --timeout <s>` invocations with
|
|
141
|
+
short timeouts will now return promptly. Existing dev-pipeline
|
|
142
|
+
PR verification calls behave identically except in the
|
|
143
|
+
GitHub-fully-down scenario, where they will now surface a clean
|
|
144
|
+
failure instead of silently passing.
|
|
145
|
+
|
|
10
146
|
## [0.1.11] - 2026-04-22
|
|
11
147
|
|
|
12
148
|
Patch release. Fixes a stale-bare-repo bug that caused worktrees
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ctrlrelay
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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/
|
|
@@ -33,7 +33,12 @@ and restart on failure — the unit examples below already do this.
|
|
|
33
33
|
Save plist files under `~/Library/LaunchAgents/`. Use the **absolute** path to
|
|
34
34
|
`ctrlrelay` (run `which ctrlrelay` to find it) — launchd's PATH is minimal.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
The job labels below use `com.example.ctrlrelay-*` as a placeholder. Pick a
|
|
37
|
+
reverse-DNS prefix you own (e.g. `com.yourname.ctrlrelay-*`) and use it
|
|
38
|
+
consistently across the filename, the `<Label>` value, and the `launchctl`
|
|
39
|
+
commands so `launchctl list` output is unambiguous.
|
|
40
|
+
|
|
41
|
+
`~/Library/LaunchAgents/com.example.ctrlrelay-bridge.plist`:
|
|
37
42
|
|
|
38
43
|
{% raw %}
|
|
39
44
|
```xml
|
|
@@ -42,7 +47,7 @@ Save plist files under `~/Library/LaunchAgents/`. Use the **absolute** path to
|
|
|
42
47
|
<plist version="1.0">
|
|
43
48
|
<dict>
|
|
44
49
|
<key>Label</key>
|
|
45
|
-
<string>com.
|
|
50
|
+
<string>com.example.ctrlrelay-bridge</string>
|
|
46
51
|
<key>ProgramArguments</key>
|
|
47
52
|
<array>
|
|
48
53
|
<string>/opt/homebrew/bin/ctrlrelay</string>
|
|
@@ -72,7 +77,7 @@ Save plist files under `~/Library/LaunchAgents/`. Use the **absolute** path to
|
|
|
72
77
|
```
|
|
73
78
|
{% endraw %}
|
|
74
79
|
|
|
75
|
-
`~/Library/LaunchAgents/com.
|
|
80
|
+
`~/Library/LaunchAgents/com.example.ctrlrelay-poller.plist`:
|
|
76
81
|
|
|
77
82
|
{% raw %}
|
|
78
83
|
```xml
|
|
@@ -81,7 +86,7 @@ Save plist files under `~/Library/LaunchAgents/`. Use the **absolute** path to
|
|
|
81
86
|
<plist version="1.0">
|
|
82
87
|
<dict>
|
|
83
88
|
<key>Label</key>
|
|
84
|
-
<string>com.
|
|
89
|
+
<string>com.example.ctrlrelay-poller</string>
|
|
85
90
|
<key>ProgramArguments</key>
|
|
86
91
|
<array>
|
|
87
92
|
<string>/opt/homebrew/bin/ctrlrelay</string>
|
|
@@ -122,16 +127,16 @@ Create the log directory and load the agents:
|
|
|
122
127
|
|
|
123
128
|
```bash
|
|
124
129
|
mkdir -p ~/.ctrlrelay/logs
|
|
125
|
-
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.
|
|
126
|
-
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.
|
|
130
|
+
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.ctrlrelay-bridge.plist
|
|
131
|
+
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.ctrlrelay-poller.plist
|
|
127
132
|
```
|
|
128
133
|
|
|
129
134
|
Manage them:
|
|
130
135
|
|
|
131
136
|
```bash
|
|
132
137
|
launchctl list | grep ctrlrelay # check loaded
|
|
133
|
-
launchctl bootout gui/$(id -u)/com.
|
|
134
|
-
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.
|
|
138
|
+
launchctl bootout gui/$(id -u)/com.example.ctrlrelay-poller # stop
|
|
139
|
+
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.ctrlrelay-poller.plist # start
|
|
135
140
|
```
|
|
136
141
|
|
|
137
142
|
### Linux — systemd
|