elsewindow 0.1.0__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.
Files changed (38) hide show
  1. elsewindow-0.2.0/.version +1 -0
  2. elsewindow-0.2.0/CHANGELOG.md +115 -0
  3. {elsewindow-0.1.0 → elsewindow-0.2.0}/MANIFEST.in +5 -0
  4. {elsewindow-0.1.0 → elsewindow-0.2.0}/PKG-INFO +41 -35
  5. {elsewindow-0.1.0 → elsewindow-0.2.0}/README.md +40 -15
  6. elsewindow-0.2.0/elsewindow/_persistent_agent.py +690 -0
  7. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/cli.py +97 -14
  8. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/config.py +26 -1
  9. elsewindow-0.2.0/elsewindow/journal.py +408 -0
  10. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/live-cli.yml +29 -2
  11. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/live_config.py +20 -3
  12. elsewindow-0.2.0/elsewindow/log_transport.py +358 -0
  13. elsewindow-0.2.0/elsewindow/machine.py +58 -0
  14. elsewindow-0.2.0/elsewindow/persistent.py +249 -0
  15. elsewindow-0.2.0/elsewindow/requirements-xpra-build.in +5 -0
  16. elsewindow-0.2.0/elsewindow/requirements-xpra-build.txt +121 -0
  17. elsewindow-0.2.0/elsewindow/requirements-xpra.in +4 -0
  18. elsewindow-0.2.0/elsewindow/requirements-xpra.txt +53 -0
  19. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/session.py +245 -29
  20. elsewindow-0.2.0/elsewindow/session_bus.py +93 -0
  21. elsewindow-0.2.0/elsewindow/xpra_runtime.py +427 -0
  22. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow.egg-info/PKG-INFO +41 -35
  23. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow.egg-info/SOURCES.txt +12 -0
  24. elsewindow-0.2.0/elsewindow.egg-info/requires.txt +1 -0
  25. {elsewindow-0.1.0 → elsewindow-0.2.0}/pyproject.toml +6 -32
  26. elsewindow-0.2.0/requirements.in +2 -0
  27. elsewindow-0.1.0/.version +0 -1
  28. elsewindow-0.1.0/CHANGELOG.md +0 -18
  29. elsewindow-0.1.0/elsewindow.egg-info/requires.txt +0 -25
  30. {elsewindow-0.1.0 → elsewindow-0.2.0}/LICENSE +0 -0
  31. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/__init__.py +0 -0
  32. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/__main__.py +0 -0
  33. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/profiles.yml +0 -0
  34. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow/py.typed +0 -0
  35. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow.egg-info/dependency_links.txt +0 -0
  36. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow.egg-info/entry_points.txt +0 -0
  37. {elsewindow-0.1.0 → elsewindow-0.2.0}/elsewindow.egg-info/top_level.txt +0 -0
  38. {elsewindow-0.1.0 → elsewindow-0.2.0}/setup.cfg +0 -0
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,115 @@
1
+ <!-- Copyright (c) 2026 kogeler. SPDX-License-Identifier: MIT. -->
2
+
3
+ # Changelog
4
+
5
+ All notable changes to Elsewindow are documented here.
6
+
7
+ ## Unreleased
8
+
9
+ ## [0.2.0] - 2026-09-05
10
+
11
+ ### Added
12
+
13
+ - Enabled remote application notifications by default, with a private owned
14
+ foreground D-Bus session per application session and no Xpra D-Bus control.
15
+ - Added a separate system-Python Xpra environment with hash-locked matching
16
+ PyOpenGL and accelerator additions. `make runtime-venv` prepares both local
17
+ environments; installed and standalone commands provide `--prepare-xpra`.
18
+ All local Xpra commands use the prepared interpreter, while ordinary startup
19
+ validates current inputs and installed bytes without installing anything.
20
+ - Bundled Xpra setup resources in all artifacts and shared clean setup,
21
+ stale-environment rejection, and repair smoke across wheel, sdist, and
22
+ standalone routes. Extended the existing live topology to exercise the
23
+ prepared client and its public zero-copy capability.
24
+ - Support accelerator source builds when a wheel is unavailable, including
25
+ Linux arm64, using a hash-verified archive and separately locked temporary
26
+ build tools. Exercise offline native compilation in every artifact smoke.
27
+ - Added synchronized `--log-level` control for Elsewindow and Xpra logs on both
28
+ hosts, with `warning` by default, host-local journald records in ordinary and
29
+ persistent sessions, and matching local stdout/stderr output.
30
+ - Added targeted diagnostics with `--log-level=debug-clipboard` and general
31
+ diagnostics with `--log-level=debug`. Both modes warn that system journals
32
+ may contain sensitive data.
33
+ - Preserved local Xpra probe diagnostics in the journal, including failures
34
+ before SSH authentication, and added side/session/source-process metadata.
35
+ - Extended the existing live topology to verify real journals on both hosts,
36
+ identical local terminal output, and unchanged ordinary/persistent cleanup.
37
+ - Aggregate four clearly labeled local/remote Elsewindow and Xpra sources in
38
+ the local terminal and journal. Forward new remote records through owned
39
+ SSH mux channels in both lifecycle modes; keep the remote journal limited
40
+ to remote sources, without granting journal-reading privileges or reconnecting.
41
+ - Include one shared session ID in every log message and native journal record
42
+ on both hosts. Keep ordinary invocations distinct and persistent IDs stable
43
+ across reconnects, namespaced by remote machine and account; isolate concurrent
44
+ log subscribers without changing application identity or ownership.
45
+ - Added `--persistent` sessions backed by owned transient user systemd
46
+ services. Repeating the same remote executable invocation path and exact
47
+ arguments resumes the application after client or SSH loss; exiting the
48
+ foreground application with any status ends the session. Ordinary
49
+ heartbeat-supervised sessions remain the default.
50
+ - Added per-invocation linger checks and interactive consent to enable it for
51
+ the remote account, using the same owned SSH connection for any required
52
+ sudo prompt. Persistent sessions never reconnect or restart automatically.
53
+ - Extended the existing release-backed live topology with real systemd,
54
+ linger refusal/consent, detach and client/SSH-loss recovery, cancellation,
55
+ repeated manual reconnects, and cleanup after successful or failed
56
+ application exit.
57
+
58
+ ### Changed
59
+
60
+ - Isolated all checkout Python environments by an application-specific hash of
61
+ the OS machine ID and local UID, shared by Make and the repository launcher.
62
+ Installed and standalone Xpra defaults use the same host isolation for shared
63
+ data directories. Leave legacy environments and other machines' venvs untouched.
64
+ - Persistent resumption requires the original logging policy.
65
+ - Consolidated all public CLI options, defaults, profiles, and restrictions
66
+ into one linked reference, with parser-backed documentation checks.
67
+ - Synchronized the maintained-fork clipboard YAML blocks and assembled the
68
+ same reviewed policy for both peers without duplicating option values or
69
+ applying the fork's clipboard-test-only X11 overrides.
70
+ - Included the persistent-session helper in wheel, source, and standalone
71
+ distributions, verified its packaged bytes, and exposed its source digest
72
+ through `--diagnose`.
73
+
74
+ ### Fixed
75
+
76
+ - Restored ordinary GUI behavior suppressed by the minimal Xpra base: custom
77
+ cursors, mouse-wheel forwarding, keyboard-state synchronization, modal windows,
78
+ detected DPI, and client scaling initially at 1:1, without new CLI switches.
79
+ - Routed `SIGHUP` through normal session cancellation and terminated owned
80
+ local SSH probe processes when their requests are cancelled.
81
+
82
+ ## [0.1.1] - 2026-09-04
83
+
84
+ ### Changed
85
+
86
+ - Enabled bidirectional Xpra clipboard synchronization by default, with
87
+ explicit `off`, `to-server`, and `both` policies applied to both peers.
88
+ - Synchronized the mirrored Xpra keyboard diagnostics with the current
89
+ maintained-fork configuration.
90
+ - Moved all exact direct Python versions to six native
91
+ `requirements*.in`/`requirements*.txt` pip-compile pairs so Dependabot can
92
+ update each complete graph instead of treating `pyproject.toml` as a plain
93
+ requirements manifest.
94
+ - Aligned both local lock resolver stages with Dependabot's pip and pip-tools
95
+ pair, and made published runtime metadata derive from `requirements.in`
96
+ without a second version authority.
97
+ - Made an exact existing release suppress the reusable release CI and both
98
+ publication jobs, while ordinary CI accepts maintenance at an already
99
+ published version and authenticates installer acceptance API requests.
100
+ - Added trusted-base PR metadata automation that mirrors a populated
101
+ `Unreleased` section without requiring a version change, preserving manual
102
+ PR text while release-worthy changes accumulate across merges.
103
+
104
+ ## [0.1.0] - 2026-08-30
105
+
106
+ ### Added
107
+
108
+ - Established Elsewindow as an independent Linux project with one public
109
+ distribution, import package, command, and repository identity.
110
+ - Preserved the one-authentication OpenSSH lifecycle, mux-only Xpra channels,
111
+ heartbeat-supervised remote process group, and selective cleanup behavior.
112
+ - Shipped reviewed Xpra command and network profiles as package data and kept
113
+ release-backed package installation and container acceptance tooling.
114
+ - Added CPython 3.13 and 3.14 governance, deterministic Python distributions,
115
+ Linux standalone artifacts, and fail-closed publication policy.
@@ -4,7 +4,12 @@ include LICENSE
4
4
  include MANIFEST.in
5
5
  include README.md
6
6
  include pyproject.toml
7
+ include requirements.in
7
8
  recursive-include elsewindow *.py *.yml py.typed
9
+ include elsewindow/requirements-xpra.in
10
+ include elsewindow/requirements-xpra.txt
11
+ include elsewindow/requirements-xpra-build.in
12
+ include elsewindow/requirements-xpra-build.txt
8
13
  prune .github
9
14
  prune bin
10
15
  prune containers
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elsewindow
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Run one remote Linux GUI application through Xpra over one owned OpenSSH master
5
5
  Author: kogeler
6
6
  Maintainer: kogeler
@@ -26,25 +26,6 @@ Requires-Python: <3.15,>=3.13
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: ssh-wrapper==0.1.0
29
- Provides-Extra: quality
30
- Requires-Dist: bandit[toml]==1.9.4; extra == "quality"
31
- Requires-Dist: mypy==2.3.1; extra == "quality"
32
- Requires-Dist: pip-audit==2.10.1; extra == "quality"
33
- Requires-Dist: pip-licenses==5.5.5; extra == "quality"
34
- Requires-Dist: ruff==0.16.5; extra == "quality"
35
- Provides-Extra: test
36
- Requires-Dist: pytest==9.1.1; extra == "test"
37
- Requires-Dist: pytest-asyncio==1.4.0; extra == "test"
38
- Requires-Dist: pytest-cov==7.1.0; extra == "test"
39
- Requires-Dist: pytest-xdist==3.8.0; extra == "test"
40
- Provides-Extra: package
41
- Requires-Dist: build==1.6.0; extra == "package"
42
- Requires-Dist: setuptools==84.0.0; extra == "package"
43
- Requires-Dist: wheel==0.48.0; extra == "package"
44
- Provides-Extra: standalone
45
- Requires-Dist: pyinstaller==6.22.2; extra == "standalone"
46
- Provides-Extra: docs
47
- Requires-Dist: mkdocs-material==9.7.7; extra == "docs"
48
29
  Dynamic: license-file
49
30
 
50
31
  # Elsewindow
@@ -56,17 +37,19 @@ cleans only the server, application process group, sockets, and runtime state
56
37
  created by that invocation.
57
38
 
58
39
  The application renders through the remote Wayland compositor and remote GPU.
59
- Only Xpra picture, input, and control traffic crosses SSH.
40
+ Only Xpra picture, input, clipboard, and control traffic crosses SSH.
60
41
 
61
42
  ## Install And Run
62
43
 
63
44
  The Python distribution requires Linux, CPython 3.13 or 3.14, OpenSSH,
64
- `false`, a local graphical session, and compatible Xpra packages on both
65
- systems. Install with pip or pipx after the first release:
45
+ `false`, a local graphical session, and compatible Xpra packages and an
46
+ accessible system journal on both systems. Install with pip or pipx after the
47
+ first release:
66
48
 
67
49
  ```bash
68
- python3.14 -m pip install "elsewindow==0.1.0"
69
- # or: pipx install "elsewindow==0.1.0"
50
+ python3.14 -m pip install "elsewindow==0.2.0"
51
+ # or: pipx install "elsewindow==0.2.0"
52
+ elsewindow --prepare-xpra
70
53
  elsewindow --ssh-alias agents-a -- xterm
71
54
  ```
72
55
 
@@ -87,6 +70,15 @@ make runtime-venv
87
70
  ./bin/elsewindow --help
88
71
  ```
89
72
 
73
+ This one make target prepares the isolated Elsewindow runtime and a separate
74
+ system-Python venv for local Xpra. The latter keeps GTK and native Xpra modules
75
+ in their system packages while installing a hash-locked matching PyOpenGL and
76
+ accelerator pair. Session startup never invokes pip or changes system packages.
77
+ Both environments are selected automatically beneath `.venvs/<machine-user-key>/`,
78
+ so each machine prepares its own Python and native additions in a shared checkout.
79
+ See [checkout setup](doc/getting-started.md#prepare-a-source-checkout) for migration
80
+ and system-command behavior.
81
+
90
82
  Use a direct authority when an OpenSSH alias is not appropriate:
91
83
 
92
84
  ```bash
@@ -97,10 +89,12 @@ elsewindow \
97
89
  -- /opt/application/bin/application
98
90
  ```
99
91
 
100
- The default encoding and network profiles are `rgb` and `gigabit_lan`.
101
- Production arguments come exclusively from the reviewed YAML mirrors shipped
102
- inside the Python package. See [the Xpra guide](doc/xpra.md) for profile,
103
- hardware, application, and lifecycle details.
92
+ See the [CLI reference](doc/cli.md) for every option, default, and allowed
93
+ value, including encoding/network profiles, clipboard policy, logging, and
94
+ persistence. Reviewed profile arguments come from the packaged YAML mirrors.
95
+ The [Xpra guide](doc/xpra.md) covers hardware, application, and lifecycle
96
+ behavior; the [security model](doc/security.md) explains clipboard and logging
97
+ trust boundaries.
104
98
 
105
99
  ## Installing The Maintained Xpra Build
106
100
 
@@ -138,17 +132,22 @@ APT transaction.
138
132
  After the first release, GitHub Releases provide `elsewindow-linux-amd64` and
139
133
  `elsewindow-linux-arm64`. These native one-file ELF executables bundle
140
134
  Elsewindow, CPython, `ssh-wrapper`, version metadata, and the reviewed YAML
141
- profiles. They do not bundle OpenSSH, Xpra, Podman, GPU drivers, VA-API, or
135
+ profiles, and the local Xpra setup code and dependency lock. They do not bundle
136
+ OpenSSH, Xpra, Podman, GPU drivers, VA-API, or
142
137
  distribution packages. Verify the release's `SHA256SUMS.txt`, make the selected
143
- file executable, and run `./elsewindow-linux-amd64 --diagnose` (or the arm64
144
- equivalent) before starting a session.
138
+ file executable, run `./elsewindow-linux-amd64 --prepare-xpra`, then
139
+ `./elsewindow-linux-amd64 --diagnose` (or the arm64 equivalents) before starting
140
+ a session. Preparation uses the system Xpra Python, not the bundled interpreter,
141
+ and needs neither a checkout nor GNU Make. See the
142
+ [setup reference](doc/cli.md#prepare-xpra) for prerequisites and storage.
145
143
 
146
144
  ## Documentation
147
145
 
148
146
  - [Rendered documentation site](https://kogeler.github.io/elsewindow/)
149
147
  (published by the first reviewed direct `main` push)
150
148
  - [Getting started](doc/getting-started.md)
151
- - [Complete Xpra behavior and options](doc/xpra.md)
149
+ - [Complete CLI reference](doc/cli.md)
150
+ - [Xpra behavior and lifecycle](doc/xpra.md)
152
151
  - [Security model](doc/security.md)
153
152
  - [Architecture](doc/architecture.md)
154
153
  - [Development and validation](doc/development.md)
@@ -164,13 +163,20 @@ file, and advertised `llms.txt` route without network access.
164
163
  ## Automatic Live Validation
165
164
 
166
165
  `make live-test` resolves the newest fork release, builds checksum-bound Ubuntu
167
- target and Debian client images, and runs detach and abrupt-master-loss cases
166
+ target and Debian client images, and runs ordinary and persistent lifecycle cases
168
167
  on a private rootless Podman network. The payload excludes `elsewindow/` source
169
168
  and clean-installs the already verified wheel. The harness generates a fresh
170
- Ed25519 key, performs exactly one authentication per case, verifies a visible
169
+ Ed25519 key, performs exactly one authentication per invocation, verifies a visible
171
170
  window and picture updates through the production profile assembler, preserves
172
171
  an unrelated session, and removes only its labelled containers and network.
173
172
  All wheel, test, and key material enters through validated tar streams; the
174
173
  test uses no host bind, data volume, or copy channel.
175
174
 
175
+ Persistent cases exercise real systemd user services, linger consent, resumption
176
+ after client/SSH loss, stable application identity and cleanup on application
177
+ exit. The same matrix checks all four local/remote log sources in the local
178
+ journal and terminal, and only remote sources in the server journal, at the
179
+ selected log level. Enable this opt-in mode with
180
+ `--persistent`; see the [CLI reference](doc/cli.md#persistent).
181
+
176
182
  Released under the [MIT License](LICENSE).
@@ -7,17 +7,19 @@ cleans only the server, application process group, sockets, and runtime state
7
7
  created by that invocation.
8
8
 
9
9
  The application renders through the remote Wayland compositor and remote GPU.
10
- Only Xpra picture, input, and control traffic crosses SSH.
10
+ Only Xpra picture, input, clipboard, and control traffic crosses SSH.
11
11
 
12
12
  ## Install And Run
13
13
 
14
14
  The Python distribution requires Linux, CPython 3.13 or 3.14, OpenSSH,
15
- `false`, a local graphical session, and compatible Xpra packages on both
16
- systems. Install with pip or pipx after the first release:
15
+ `false`, a local graphical session, and compatible Xpra packages and an
16
+ accessible system journal on both systems. Install with pip or pipx after the
17
+ first release:
17
18
 
18
19
  ```bash
19
- python3.14 -m pip install "elsewindow==0.1.0"
20
- # or: pipx install "elsewindow==0.1.0"
20
+ python3.14 -m pip install "elsewindow==0.2.0"
21
+ # or: pipx install "elsewindow==0.2.0"
22
+ elsewindow --prepare-xpra
21
23
  elsewindow --ssh-alias agents-a -- xterm
22
24
  ```
23
25
 
@@ -38,6 +40,15 @@ make runtime-venv
38
40
  ./bin/elsewindow --help
39
41
  ```
40
42
 
43
+ This one make target prepares the isolated Elsewindow runtime and a separate
44
+ system-Python venv for local Xpra. The latter keeps GTK and native Xpra modules
45
+ in their system packages while installing a hash-locked matching PyOpenGL and
46
+ accelerator pair. Session startup never invokes pip or changes system packages.
47
+ Both environments are selected automatically beneath `.venvs/<machine-user-key>/`,
48
+ so each machine prepares its own Python and native additions in a shared checkout.
49
+ See [checkout setup](doc/getting-started.md#prepare-a-source-checkout) for migration
50
+ and system-command behavior.
51
+
41
52
  Use a direct authority when an OpenSSH alias is not appropriate:
42
53
 
43
54
  ```bash
@@ -48,10 +59,12 @@ elsewindow \
48
59
  -- /opt/application/bin/application
49
60
  ```
50
61
 
51
- The default encoding and network profiles are `rgb` and `gigabit_lan`.
52
- Production arguments come exclusively from the reviewed YAML mirrors shipped
53
- inside the Python package. See [the Xpra guide](doc/xpra.md) for profile,
54
- hardware, application, and lifecycle details.
62
+ See the [CLI reference](doc/cli.md) for every option, default, and allowed
63
+ value, including encoding/network profiles, clipboard policy, logging, and
64
+ persistence. Reviewed profile arguments come from the packaged YAML mirrors.
65
+ The [Xpra guide](doc/xpra.md) covers hardware, application, and lifecycle
66
+ behavior; the [security model](doc/security.md) explains clipboard and logging
67
+ trust boundaries.
55
68
 
56
69
  ## Installing The Maintained Xpra Build
57
70
 
@@ -89,17 +102,22 @@ APT transaction.
89
102
  After the first release, GitHub Releases provide `elsewindow-linux-amd64` and
90
103
  `elsewindow-linux-arm64`. These native one-file ELF executables bundle
91
104
  Elsewindow, CPython, `ssh-wrapper`, version metadata, and the reviewed YAML
92
- profiles. They do not bundle OpenSSH, Xpra, Podman, GPU drivers, VA-API, or
105
+ profiles, and the local Xpra setup code and dependency lock. They do not bundle
106
+ OpenSSH, Xpra, Podman, GPU drivers, VA-API, or
93
107
  distribution packages. Verify the release's `SHA256SUMS.txt`, make the selected
94
- file executable, and run `./elsewindow-linux-amd64 --diagnose` (or the arm64
95
- equivalent) before starting a session.
108
+ file executable, run `./elsewindow-linux-amd64 --prepare-xpra`, then
109
+ `./elsewindow-linux-amd64 --diagnose` (or the arm64 equivalents) before starting
110
+ a session. Preparation uses the system Xpra Python, not the bundled interpreter,
111
+ and needs neither a checkout nor GNU Make. See the
112
+ [setup reference](doc/cli.md#prepare-xpra) for prerequisites and storage.
96
113
 
97
114
  ## Documentation
98
115
 
99
116
  - [Rendered documentation site](https://kogeler.github.io/elsewindow/)
100
117
  (published by the first reviewed direct `main` push)
101
118
  - [Getting started](doc/getting-started.md)
102
- - [Complete Xpra behavior and options](doc/xpra.md)
119
+ - [Complete CLI reference](doc/cli.md)
120
+ - [Xpra behavior and lifecycle](doc/xpra.md)
103
121
  - [Security model](doc/security.md)
104
122
  - [Architecture](doc/architecture.md)
105
123
  - [Development and validation](doc/development.md)
@@ -115,13 +133,20 @@ file, and advertised `llms.txt` route without network access.
115
133
  ## Automatic Live Validation
116
134
 
117
135
  `make live-test` resolves the newest fork release, builds checksum-bound Ubuntu
118
- target and Debian client images, and runs detach and abrupt-master-loss cases
136
+ target and Debian client images, and runs ordinary and persistent lifecycle cases
119
137
  on a private rootless Podman network. The payload excludes `elsewindow/` source
120
138
  and clean-installs the already verified wheel. The harness generates a fresh
121
- Ed25519 key, performs exactly one authentication per case, verifies a visible
139
+ Ed25519 key, performs exactly one authentication per invocation, verifies a visible
122
140
  window and picture updates through the production profile assembler, preserves
123
141
  an unrelated session, and removes only its labelled containers and network.
124
142
  All wheel, test, and key material enters through validated tar streams; the
125
143
  test uses no host bind, data volume, or copy channel.
126
144
 
145
+ Persistent cases exercise real systemd user services, linger consent, resumption
146
+ after client/SSH loss, stable application identity and cleanup on application
147
+ exit. The same matrix checks all four local/remote log sources in the local
148
+ journal and terminal, and only remote sources in the server journal, at the
149
+ selected log level. Enable this opt-in mode with
150
+ `--persistent`; see the [CLI reference](doc/cli.md#persistent).
151
+
127
152
  Released under the [MIT License](LICENSE).