tray4hermes 2.0.17__py3-none-any.whl
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.
- tray4hermes/__init__.py +17 -0
- tray4hermes/__main__.py +176 -0
- tray4hermes/_locales/cs/LC_MESSAGES/tray4hermes.mo +0 -0
- tray4hermes/app.py +506 -0
- tray4hermes/data/tray4hermes.desktop +9 -0
- tray4hermes/i18n.py +311 -0
- tray4hermes/icons.py +97 -0
- tray4hermes/lock.py +54 -0
- tray4hermes/log_dialog.py +787 -0
- tray4hermes/log_parse.py +106 -0
- tray4hermes/log_settings.py +343 -0
- tray4hermes/log_theme.py +100 -0
- tray4hermes/paths.py +75 -0
- tray4hermes/py.typed +0 -0
- tray4hermes/state.py +264 -0
- tray4hermes/tray_settings.py +291 -0
- tray4hermes-2.0.17.dist-info/METADATA +624 -0
- tray4hermes-2.0.17.dist-info/RECORD +22 -0
- tray4hermes-2.0.17.dist-info/WHEEL +5 -0
- tray4hermes-2.0.17.dist-info/entry_points.txt +2 -0
- tray4hermes-2.0.17.dist-info/licenses/LICENSE +21 -0
- tray4hermes-2.0.17.dist-info/top_level.txt +1 -0
tray4hermes/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""tray4hermes — passive KDE/Plasma tray monitor for Hermes Gateway.
|
|
2
|
+
|
|
3
|
+
Hermes Gateway is the messaging bridge that ships with Hermes Agent
|
|
4
|
+
(Nous Research). This package is a thin controller:
|
|
5
|
+
|
|
6
|
+
- reads ~/.hermes/{gateway_state.json, profiles/, config.yaml, logs/gateway.log}
|
|
7
|
+
- writes only ~/.config/tray4hermes/state.json
|
|
8
|
+
- controls the gateway via `systemctl --user`
|
|
9
|
+
|
|
10
|
+
Nothing else. No token storage, no provider config, no agent logic.
|
|
11
|
+
All of that lives in Hermes Agent itself.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
__version__ = "2.0.17"
|
|
17
|
+
__all__ = ["__version__"]
|
tray4hermes/__main__.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""`python -m tray4hermes` entry point.
|
|
2
|
+
|
|
3
|
+
Supports `--help`, `--version`, and `--language` flags. The
|
|
4
|
+
language flag accepts an ISO 639-1 code (e.g. ``cs``, ``en``,
|
|
5
|
+
``de``); when set, the runtime UI strings are translated into
|
|
6
|
+
that language if a translation exists. When omitted, the
|
|
7
|
+
selection follows the OS environment (``LC_ALL`` / ``LC_MESSAGES``
|
|
8
|
+
/ ``LANG``) with ``en`` (canonical) and ``cs`` (the first
|
|
9
|
+
translation we shipped) as the fallback chain.
|
|
10
|
+
|
|
11
|
+
Other paths acquire the single-instance lock and run the tray.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
from tray4hermes import __version__
|
|
20
|
+
from tray4hermes import paths as _paths
|
|
21
|
+
|
|
22
|
+
# ``install`` is the runtime binding step for gettext; importing
|
|
23
|
+
# the symbol at module-load ensures we fail loudly if i18n
|
|
24
|
+
# machinery is missing, rather than later at the first ``_()``
|
|
25
|
+
# call. ``available_languages`` lets ``--language`` (with no
|
|
26
|
+
# argument) report what's shipped.
|
|
27
|
+
from tray4hermes.i18n import available_languages
|
|
28
|
+
from tray4hermes.i18n import install as _i18n_install
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Dynamic gettext lookup — see the same wrapper in app.py. Here it also
|
|
32
|
+
# has to be dynamic in time: this module *is* what calls ``install()``,
|
|
33
|
+
# so every ``_()`` below necessarily runs after the binding exists.
|
|
34
|
+
def _(s: str) -> str:
|
|
35
|
+
"""Dynamic gettext wrapper — looks up i18n._ on every call."""
|
|
36
|
+
from tray4hermes import i18n as _i18n_mod
|
|
37
|
+
|
|
38
|
+
return _i18n_mod._(s)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Sentinel for ``--language`` used without a value: "tell me which
|
|
42
|
+
# languages this build ships". A real language code can never collide
|
|
43
|
+
# with it — ISO 639-1 codes are two letters.
|
|
44
|
+
LIST_LANGUAGES = "?list-languages"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _resolve_language(cli_value: str | None, saved: str | None) -> str | None:
|
|
48
|
+
"""Decide which language to bind, given the flag and the saved setting.
|
|
49
|
+
|
|
50
|
+
Priority: explicit ``--language`` → saved ``TraySettings.language``
|
|
51
|
+
→ ``None``, which leaves gettext to follow the OS environment.
|
|
52
|
+
|
|
53
|
+
``--language none`` is an explicit request for the environment, so
|
|
54
|
+
it has to override the saved value rather than fall through to it.
|
|
55
|
+
"""
|
|
56
|
+
if cli_value is None:
|
|
57
|
+
return saved
|
|
58
|
+
if cli_value.strip().lower() in ("", "none"):
|
|
59
|
+
return None
|
|
60
|
+
return cli_value
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _parse_args(argv: list[str]) -> argparse.Namespace:
|
|
64
|
+
"""Keep argparse deliberately small — flags are documented in README.
|
|
65
|
+
|
|
66
|
+
Recognised flags:
|
|
67
|
+
|
|
68
|
+
- ``--version``: print version and exit.
|
|
69
|
+
- ``--help``: print usage and exit.
|
|
70
|
+
- ``--language`` / ``-L``: ISO 639-1 short code. ``--language cs``
|
|
71
|
+
forces Czech, ``--language none`` reads from the OS environment,
|
|
72
|
+
and ``--language`` with no value lists what the build ships.
|
|
73
|
+
"""
|
|
74
|
+
parser = argparse.ArgumentParser(
|
|
75
|
+
prog="tray4hermes",
|
|
76
|
+
description=(
|
|
77
|
+
"Passive KDE/Plasma tray monitor for Hermes Gateway. "
|
|
78
|
+
"Controls the gateway via systemctl --user; otherwise read-only."
|
|
79
|
+
),
|
|
80
|
+
epilog=(
|
|
81
|
+
"See https://github.com/MoDD0/tray4hermes for full documentation, "
|
|
82
|
+
"installation instructions, and contributing guidelines."
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
parser.add_argument(
|
|
86
|
+
"--version",
|
|
87
|
+
action="version",
|
|
88
|
+
version=f"%(prog)s {__version__}",
|
|
89
|
+
)
|
|
90
|
+
parser.add_argument(
|
|
91
|
+
"-L",
|
|
92
|
+
"--language",
|
|
93
|
+
nargs="?",
|
|
94
|
+
const=LIST_LANGUAGES,
|
|
95
|
+
default=None,
|
|
96
|
+
metavar="CODE",
|
|
97
|
+
help=(
|
|
98
|
+
"Force a UI language (ISO 639-1 code, e.g. 'cs', 'en'). "
|
|
99
|
+
"Default is to honour the OS locale (LANG / LC_ALL / LC_MESSAGES) "
|
|
100
|
+
"with English / Czech as fallback. Pass --language without an "
|
|
101
|
+
"argument to query which languages have been built into the wheel."
|
|
102
|
+
),
|
|
103
|
+
)
|
|
104
|
+
return parser.parse_args(argv)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def main() -> int:
|
|
108
|
+
"""Acquire single-instance lock, run the tray, release on exit.
|
|
109
|
+
|
|
110
|
+
Step 1: parse argv BEFORE binding gettext, so argparse's
|
|
111
|
+
--help / --version text can still be read in source lang.
|
|
112
|
+
|
|
113
|
+
Step 2: bind the UI translation. We do this only after we
|
|
114
|
+
know which language to install (CLI flag or env), so Qt
|
|
115
|
+
widgets constructed later pick up the right strings.
|
|
116
|
+
"""
|
|
117
|
+
args = _parse_args(sys.argv[1:])
|
|
118
|
+
|
|
119
|
+
# ``--language`` with no value is a short-circuit that lists the
|
|
120
|
+
# available languages and exits; convenient for the README snippet
|
|
121
|
+
# "what languages does this build support?". It returns before the
|
|
122
|
+
# single-instance lock, so asking the question never disturbs a
|
|
123
|
+
# running tray.
|
|
124
|
+
if args.language == LIST_LANGUAGES:
|
|
125
|
+
print(
|
|
126
|
+
"Available languages:",
|
|
127
|
+
", ".join(available_languages()) or "(none — no compiled .mo files found)",
|
|
128
|
+
)
|
|
129
|
+
return 0
|
|
130
|
+
|
|
131
|
+
# Bind gettext with the requested language.
|
|
132
|
+
#
|
|
133
|
+
# Priority:
|
|
134
|
+
# 1. --language CLI flag (highest)
|
|
135
|
+
# 2. Saved TraySettings.language (from state.json)
|
|
136
|
+
# 3. OS env (LANG/LC_ALL/LC_MESSAGES)
|
|
137
|
+
# 4. English source (fallback)
|
|
138
|
+
saved_lang = None
|
|
139
|
+
try:
|
|
140
|
+
from tray4hermes.tray_settings import load_tray_settings
|
|
141
|
+
|
|
142
|
+
saved_lang = load_tray_settings().language
|
|
143
|
+
except Exception as e: # noqa: BLE001
|
|
144
|
+
# Non-fatal — fall through to env/CLI
|
|
145
|
+
import sys as _sys
|
|
146
|
+
|
|
147
|
+
print(f"[tray4hermes] could not load saved language: {e}", file=_sys.stderr)
|
|
148
|
+
_i18n_install(language=_resolve_language(args.language, saved_lang))
|
|
149
|
+
|
|
150
|
+
from tray4hermes.lock import acquire, release
|
|
151
|
+
|
|
152
|
+
if not acquire(_paths.lock_file()):
|
|
153
|
+
# Another tray is already running — pop a dialog so the user knows.
|
|
154
|
+
from PyQt5.QtWidgets import QApplication, QMessageBox
|
|
155
|
+
|
|
156
|
+
QApplication.instance() or QApplication(sys.argv)
|
|
157
|
+
QMessageBox.information(
|
|
158
|
+
None,
|
|
159
|
+
"Hermes Tray",
|
|
160
|
+
# TRANSLATORS: body of a dialog shown when another instance
|
|
161
|
+
# of the tray is already running (we hold a single-instance
|
|
162
|
+
# lock and refuse to start a second).
|
|
163
|
+
_("tray4hermes is already running.\nFind it in the system tray."),
|
|
164
|
+
)
|
|
165
|
+
return 2
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
from tray4hermes.app import HermesTray
|
|
169
|
+
|
|
170
|
+
return HermesTray().run()
|
|
171
|
+
finally:
|
|
172
|
+
release(_paths.lock_file())
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
if __name__ == "__main__":
|
|
176
|
+
sys.exit(main())
|
|
Binary file
|